我们的健康检查在一天内重启了八次一个健康的模型服务器
运维
7 月 22 日,一个看门狗重启了我们的本地模型服务器八次。这八次重启背后没有一次崩溃。本应保持模型运行的检查,反而成了导致其宕机的原因。
发生了什么
模型服务器在一台 NVIDIA GB10 机器上运行 vLLM,为单个请求提供约 8 tokens/s 的生成速度。看门狗每五分钟向它发送一个真实的聊天请求,并等待最多 45 秒以获取响应。连续五次检查失败意味着服务器挂起,看门狗便会重启它。重启会使模型下线几分钟,因为需要重新加载约 19 GB 的权重。
那天,一个批处理任务让服务器上的两到四个请求持续忙碌数分钟。看门狗的请求排在它们后面等待,最终超时并被计为失败。经过五次这样的检查,一个健康的服务器被重启了。我们有一个看门狗会尊重的“忙碌”标志文件,但批处理任务从未设置它。
一次误重启如何引发下一次
每次重启都会使正在进行的请求以 500 错误失败(“cannot schedule new futures after shutdown”)。第二个看门狗统计 500 错误,并在错误过多时重启服务器,而且它看到的错误越多,行动就越快。因此,每次误重启都会让下一次来得更早。总共有四个独立的看门狗可以重启该服务器,分别基于 5、10、15 和 30 分钟的定时器。
我们从中吸取的规则
健康检查不得使用它所守护的资源。模型服务器的稀缺资源是正在处理请求的槽位。一个占用或等待这些槽位的检查,本身就是它要评估的负载的一部分。请进行低成本检查,并且只有在能证明服务器卡住时才重启。
取代它的检查
vLLM 在 /metrics 端点发布其自身的计数器。新的检查首先读取这些计数器:
- 正在运行的请求以及引擎正在推进:健康且忙碌。不发送测试请求。
- 两次读取之间正在运行请求但无进展:卡住。这是仍会触发重启的情况。
- 无运行中请求:空闲。只有此时,检查才会请求一个简短的回答,而空闲引擎会立即给出。
第一个版本将生成的 tokens 计为进展。它通过了八项测试,并在首次实际运行中发现服务器忙碌且健康:2 个请求正在运行,两次读取之间新增了 107 个 tokens。
自那以后我们做出的更改
- 统计引擎步数,而非输出 token 数。当 vLLM 读取长提示词时,它暂时不会生成输出 token,但仍会执行步数。统计步数(即 vllm:iteration_tokens_total 的计数)可防止长提示词被误判为服务器卡死。
- 在判定“卡死”前进行两次等待,以免短暂停顿被计为故障。
- 两次读取之间的重启会被捕获,依据是同一指标中的进程启动时间;此时检查机制会要求返回结果,而不是比较来自两个不同进程的计数器。
- 代理仅通过 /models 进行检查。在最少连接数代理之后,每次读取 /metrics 都可能来自不同的后端,正如我们在两台机器上各运行一份模型副本时发现的那样。后端会被直接检查。
差异显而易见。撰写此说明时,我们的两台模型服务器均正在处理 12 个请求,已达上限。测试请求将在队列中等待。新检查机制报告两者均繁忙且健康,速率分别为每秒 126 和 101 个 token,且无需发送测试请求。
Factory Floor 1.0.2 将此检查作为 models/llm-health.py 发布,并包含针对空闲、繁忙、卡死和重启服务器、无指标服务器、代理以及失效后端的测试。