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 服务都适用。

相关推荐
SimonKing17 小时前
那个号称"对标 Spring"的国产框架 Solon,到底行不行?
java·后端·程序员
阿望说AI19 小时前
读完北大 Linian Wang 那篇 Kimi K2 排障文,我把大模型 API 想明白了:Tool Calling 根本不存在
程序员·ai编程
Hilaku1 天前
前端大裁员背后的恐慌:我们还剩什么底牌?
前端·javascript·程序员
卡卡罗特学AI2 天前
曾经人手一个的Superpowers,为什么现在都在卸
人工智能·程序员
阿里嘎多学长2 天前
2026-07-12 GitHub 热点项目精选
开发语言·程序员·github·代码托管
SimonKing2 天前
Spring Boot 4.0 + gRPC 极简集成:4步搞定,比REST还丝滑
java·后端·程序员
Karl_wei2 天前
Harness 企业级落地(二) - 让 AI 读懂项目
程序员·openai·全栈
阿里嘎多学长2 天前
2026-07-14 GitHub 热点项目精选
开发语言·程序员·github·代码托管
猿的天空3 天前
AI视觉原生统一!商汤开源视觉任务大统一模型SenseNova-Vision
人工智能·计算机·ai·程序员·大模型·编程·智能体