Hermes Gateway重启慢到让人砸键盘:从journalctl到cProfile,三层根因逐层拆解实录

问题

每次执行 systemctl restart hermes-gateway,都要等差不多半分钟才能用。29 秒的重启时间对于一个本地服务来说,太长了。

本文记录完整的排查过程------从抓日志到代码级热点定位,逐层拆解、逐层修复,每一步都有实测数据。

第一层:journalctl 抓时间线

重启慢,先搞清楚时间花在哪。journalctl 看系统日志:

bash 复制代码
journalctl --user -u hermes-gateway --no-pager -S "重启时间"

日志里明晃晃写着:

makefile 复制代码
05:59:04  Stopping Hermes Agent Gateway...
05:59:19  State 'stop-sigterm' timed out. Killing.
05:59:19  Started Hermes Agent Gateway.

旧进程收到 SIGTERM 后,15 秒没退出,systemd 等到 TimeoutStopSec 超时才 SIGKILL 强杀。这 15 秒是白等的。

根因:旧进程里有 API 429 重试线程在 sleep 120 秒,SIGTERM 信号被忽略。

修复 :改 systemd service 文件里的 TimeoutStopSec。

ini 复制代码
# ~/.config/systemd/user/hermes-gateway.service
TimeoutStopSec=5    # 原来是 90,先改 15 再改 5

然后 systemctl --user daemon-reload 生效。

改完后退出阶段从 90 秒变成 5 秒。但总耗时还是 14 秒------启动阶段有东西卡着。

第二层:bootstrap 日志 38MB

扫磁盘时发现 ~/.hermes/webui/bootstrap-8787.log 涨到了 38MB,32 万行 HTTP 请求日志。虽然不直接拖慢启动,但持续增长不是事。

用 logrotate 解决:

conf 复制代码
# ~/.config/logrotate/hermes-webui.conf
/home/cronuser/.hermes/webui/bootstrap-8787.log {
    daily
    rotate 7
    maxsize 10M
    copytruncate
    olddir /home/cronuser/.hermes/logs/rotated
    dateext
}

配上 cron 每天 3am 自动切割。跑一次:38MB → 135 字节。

第三层:WebUI 模型目录重建------真正的瓶颈

14 秒的启动阶段,Gateway 自身启动其实不到 1 秒。用 cProfile 冷启动测试:

yaml 复制代码
import + config:   50ms
skill sync:        54ms
MCP discovery:      7ms
import runner:    326ms
──────────────────────
TOTAL:           459ms

那剩下的 13 秒去哪了?

WebUI 进程每次重启后,第一次 /api/chat/start 请求会触发 get_available_models() → _build_available_models_uncached(),对每个 provider 调 _fetch_github_models() → urllib.urlopen("https://api.github.com/...") 拉 GitHub Copilot 模型列表。

不用 Copilot?照拉。从国内直连 GitHub API:卡 9-10 秒。

日志证据(errors.log):

yaml 复制代码
Slow WebUI request: resolve_model_provider → 9648.8ms

修复方案一:代理加速

开代理加速,GitHub API 走代理 0.31 秒。重启后首次 chat_start 降到 54.9ms。

但每次重启还要拉一次------浪费。

修复方案二:磁盘缓存落盘

WebUI 源码里已经有完整的磁盘缓存逻辑:

python 复制代码
# api/config.py
_models_cache_path = STATE_DIR / "models_cache.json"

def _save_models_cache_to_disk(cache): ...
def _load_models_cache_from_disk(): ...

但 models_cache.json 从未被写入------目录可写,函数被调用,存的却是空。

直接触发一次构建并落盘:

python 复制代码
from api.config import get_available_models
get_available_models()  # 自动构建 + 落盘到 models_cache.json

3.7KB 文件落盘后,下次重启直接读,不再走网络。

最终效果

阶段 修复前 修复后
旧进程退出 90s(等超时) 5s(TimeoutStopSec=5)
Gateway 启动 0.5s 0.5s
模型目录重建 9.6s(直连 GitHub) 0.05s(磁盘缓存)
总耗时 ~29s ~6s

方法论总结

systemd 服务启动慢的排查套路:

  1. journalctl 抓时间线------确认时间花在退出还是启动
  2. TimeoutStopSec 调优------旧进程不响应 SIGTERM 就别等
  3. cProfile + 子进程冷启动------隔离测量代码热点
  4. 检查外部网络调用 ------urllib 直连外网是大坑
  5. 磁盘缓存落盘------内存缓存进程重启就丢

这套方法论不限于 Hermes,任何 systemd 管理的 Python 服务都适用。

相关推荐
2分钟速写快排6 小时前
ggg! 潜行摸鱼被 Trae 爆改成 3D!
人工智能·程序员·数据可视化
深蓝AI7 小时前
EMBRACE 攻击打穿五个 AI 编程工具的浏览器:本地开发机成了最大攻击面
人工智能·程序员
hzy26_119 小时前
排错与纠正 01
程序员
楠风测开15 小时前
接口性能 + AI 压测分析
程序员
彭亚川Allen15 小时前
985 在职研究生到底怎么样?是不是水硕?是不是.....?
前端·后端·程序员
陈随易17 小时前
副业搞钱点子之独立开发
前端·后端·程序员
挖掘狂人18 小时前
Vue nextTick 到底在等什么?一篇讲透原理与那些年踩过的坑
javascript·程序员·编程语言
codigger18 小时前
Vue nextTick 到底在等什么?一篇讲透原理与那些年踩过的坑
程序员·vue·编程·异步更新·#人工智能
LV技术派19 小时前
【成为 AI Native Builder · 01】开篇:为什么 AI 总在返工?
人工智能·程序员·ai编程
深蓝AI1 天前
总榜第一不等于最划算:Intelligence Index v5 换代后,模型选型要算的三笔账
程序员·架构