Files
dsh_shenxian/dsh-server-docs/04-调整方案/21-guest会话卡顿排查.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
   保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
   工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
   必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
   + ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
   ⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
   验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

11 KiB
Raw Blame History

21 · guest 会话"卡顿 / 断开显示连接中"排查

  • 日期:2026-09-10
  • 触发:用户报障——在另一台电脑用 guest 账号,每次对话后等几分钟就"断开→连接中",提问要等好一会模型才回复,获取会话信息很慢
  • 结论一句话:服务端与模型都不慢(8 轮对话 TTFT 1.0–3.5 s、实例回环 TTFB 2 ms、模型出网 0.3 s、nginx 全部 <5 s);用户看到"看不到流式输出、结果与思考一次性出现"的根因是 nginx 默认 proxy_buffering on 把流攒块下发(已修复并 reload)。另外存在两个可消除的干扰项:① 生产实例启用着 HMR(热重载)客户端;② 无关域名流量打进编排器(默认 vhost 误配置)。
  • 状态:根因已定位并修复(nginx 缓冲)→ 待用户浏览器复验流式;干扰项 A1/A2 待拍板

TL;DR|结论:guest「卡顿 / 显示连接中」排查:服务端与模型都不慢(TTFT 1.0–3.5 s、实例 TTFB 2 ms、nginx 全 <5 s)。 关键:体感根因 = nginx 默认 proxy_buffering on 使流式"一次性出现" + 生产启用 HMR 的干扰(→ 档案 22 的 nginx 修复)。 状态:🔄 已定位;A1 禁 HMR / A2 catch-all 用户已决定暂缓


一、实测证据(全部只读取证,未导出任何对话正文)

维度 实测 判定
每轮 TTFT(turn/start → 首个流式 chunk) 8 轮分别为 1.0 / 1.8 / 1.3 / 1.6 / 1.6 / 1.7 / 3.5 / 1.7 秒 ✅ 服务端与模型都快,"等好一会才回复"不是服务端造成
轮时长 19 / 118 / 291 / 30 / 64 / 46 / 36 / 49 秒(长轮 = 多步工具调用,正常) ✅ 无异常
工具调用 95 次,平均 2.3 s,最慢 79.3 s / 44.2 s(个别命令本身耗时) ✅ 正常
会话规模 8 轮、12 条 user/message、3268 行事件、1.0 MB(压缩) ✅ 无膨胀(档案 14 H3 保留期可继续缓做)
实例自身 HTTP 回环 ttfb=0.002s、CPU 7.1%、RSS 276 MB / 512 MB 上限 ✅ 实例健康
实例 → 模型 API 出网 DNS 1.3 ms / TCP 3.9 ms / TLS 17 ms / TTFB 0.30 s ✅ 出网无碍
nginx(guest 子域) 732 请求:594×200、24×401、1×404、1×302,全部 <5 s ✅ 边缘不慢
24h 内崩溃 / 熔断 / idle-reap 0 条(新增的 [crash-restart] 也无记录) ✅ 实例没被反复重建
系统资源 内存 636/1870 MB、可用 1234 MB、负载 0.08、0 次 OOM ✅ 无资源压力

会话时序里最大的几个间隔(34374 s / 1853 s / 561 s…)全部出现在 turn/end 之后,即用户离开后隔很久再提问 → 属正常空闲,不是掉线。

二、根因定位与修复:"看不到流式输出"(2026-09-10 23:00)

用户补充关键症状:"刚才那轮对话看不到流式输出,结果和思考过程都是一下显示的" → 指向中间代理缓冲。

跳 检查 结果
应用层 dsh 是否发 X-Accel-Buffering: no(若发则 nginx 自动不缓冲) ❌ 未发(全包 grep 无命中)
编排器代理 src/supervisor/proxy.ts 转发方式 ✅ 正确流式:upRes.pipe(reply.raw)、WS 走 upgrade 隧道,不缓冲
传输形态 客户端用 WebSocket 还是 HTTP 流 guest 子域 101 计数 = 0(全站 159 条 101 属其他页面)→ 聊天走 HTTP 流式,正受 nginx 缓冲影响
前面还有没有一层 nginx 日志真实客户端 IP(是否 Cloudflare) 125.85.124.119 / 113.248.166.66 / 154.40.35.3 → 无 CF 段,单层 nginx
nginx 配置 nginx -T 全局搜 proxy_buffering ❌ 只有 proxy_send_timeout 60,没有任何 proxy_buffering off → 默认 on 生效 ⇒ 流被攒成大块

修复(已执行):在两个 443 站点块(主域 + 通配子域)的 location / 增加:

proxy_buffering off;      # 关键:流式响应逐块透传
proxy_cache off;          # 避免任何缓存介入
proxy_send_timeout 3600s; # 与 proxy_read_timeout 对齐

执行与验证:备份 → 写配置 → nginx -t 通过 → nginx -s reload → 生效确认(nginx -T | grep -c "proxy_buffering off" = 2)→ https://dsh.alotbuy.com/login.html 200、编排器直连 200。

回滚副本:/www/server/panel/vhost/nginx/dsh.alotbuy.com.conf.bak-20260910-2300-pre-buffering(改动前原文,56 行)。

⚠️ 宝塔面板注意:在面板里保存/修改站点配置会按模板重写该 vhost,可能抹掉这 3 行 → 若流式又变回"一次性显示",先检查这 3 行是否还在。

三、两个可消除的干扰项(待拍板)

① 生产实例启用了 HMR(热重载)客户端 —— 头号嫌疑

  • 证据:dsh-web-app/cordis.patch.yml 第 148-149 行挂着 - id: client-hmr / name: '@deepseek-ai/dsh-client-hmr' → 每个实例都启用;其客户端持续请求 /plugins/events。nginx 记录该路径在 guest 子域上以 ≈65 s 间隔出现(21:43:38 → 21:44:43 → 21:45:48 …),并夹杂 401(21:45:53)与 302(22:39:36,实例未运行时的守卫跳转)。
  • 影响:HMR 是开发期热重载能力,生产环境无用;但它会周期性建立/重试一条通道,UI 上很可能就是"连接中"的来源,并且每次实例重启后都会产生 401/302 重试噪音。
  • 建议修复(低风险、可回滚):在 profile patch 层按档案 09 已实证的手法禁用该行:
    - id: client-hmr
      name: '@deepseek-ai/dsh-client-hmr'
      disabled: true
    
    生效需重启实例;先在 admin 或 guest 单个实例验证(页面功能是否正常、/plugins/events 请求是否消失)。

② 无关域名流量打进编排器(默认 vhost 误配置)

  • 证据:编排器 24h 收到的 Host 分布 —— evertwins.com 880 次、裸 IP 47.77.182.89 640 次、www.evertwins.com 307 次、wp. / staging.evertwins.com 各 95 次;而本机没有这些域名的 vhost 文件。
  • 成因:nginx include /www/server/panel/vhost/nginx/*.conf 顺序加载,未显式 default_server 时第一个 server 块即该端口默认站点,我们的 dsh vhost 恰成默认 → 所有未匹配 Host(含扫描器、/.env 探测)都被转进业务进程。
  • 影响:无关流量与扫描落在业务进程上;访问这些域名会看到 dsh 登录页(品牌混淆)。
  • 建议修复:加一个 catch-all 默认站点(return 444,或 server_name _; + 444)并 nginx -t 校验;约 1 分钟,可回滚。

四、还需客户端侧取证

服务端已能证明"轮次一旦开始就很快",无法从服务端看到"用户按下发送 → 消息抵达服务端"之间的耗时。请在有问题的电脑上:

  1. 打开 DevTools → Network,复现"连接中"的瞬间,看:
    • /api/session/prompt 的 Waiting(TTFB) 与是否长时间 pending;
    • 是否有 WebSocket/EventSource 反复重连(/plugins/events、/api/... 101/未完成);
    • Console 是否有 401 / 断线报错。
  2. 记录该电脑的网络环境(是否走 VPN/代理、Wi-Fi 信号、运营商)——"网络很卡"的体感与 401 重试可能叠加。
  3. 若 DevTools 显示 /api/session/list 等请求本身很快而 UI 仍"卡",则属前端渲染/长轮次等待,另案处理。

五、待拍板

# 措施 风险 需要
A1 禁用 client-hmr(profile patch,含 admin/guest 全量或先单例) 低(生产无用;可回滚=删行) 需重启实例
A2 修默认 vhost:加 catch-all return 444 低(仅影响未匹配域名) nginx -t + reload
A3 客户端 DevTools 取证(用户侧) — 用户在问题电脑操作一次
A0 nginx 关闭响应缓冲(流式修复) — ✅ 已完成(2026-09-10 23:00,见 §二)

六、"刷新后载入历史会话要几分钟"排查与优化(2026-09-10 23:15)

新症状:刷新后载入历史会话要几分钟,体感"网络很卡"。

取证(nginx 访问日志解析,4000 行窗口内 guest 子域 823 个请求):

发现 数据
单次刷新要下载一个巨大的插件 bundle GET /plugins/??<45 个 client.js 拼接>&rev=<hash> → 实发 980 KB / 930 KB(含 dsh-client-hmr、typert-registry、api-gateway、~30 个 dsh-client-ui-* 面板)
另有哈希静态资源 /assets/vendor-CCJJTK99.js = 209 KB
大量小 API 轮询(每次刷新都打) agentPresets/list 131、commands/list 105、modelCatalog 78、syncInspectManifest 76、subagents/list 73、session/list 68 …

根因(两条叠加):

  1. 反代响应未被 gzip 压缩:全局 gzip_proxied 只列了 expired no-cache no-store private auth,不含 any → dsh 反代出来的 JS/JSON 大多不满足条件 → 那个 ~930 KB 的 bundle 以未压缩体积下发(日志 $body_bytes_sent 即实发字节,若压缩过应是 250 KB 量级)。
  2. 哈希资源无长缓存:/assets/* 与 /plugins/*&rev=* 每次刷新都可能重新拉取 ~1.2 MB。

叠加 200+ 次小请求的往返延迟,在链路质量差的电脑上就表现为"几分钟"。

优化(已执行,档案 21 · 2026-09-10 23:15):在 dsh vhost 两个 443 站点块中

  • location / 增加 gzip_proxied any;(放开反代压缩)
  • 新增 location ~* ^/assets/ → 同代理参数 + gzip_proxied any; + expires 30d(哈希文件名 → 可长缓存)

执行:备份(*.bak-YYYYMMDD-HHMM-pre-gzip)→ 写配置 → nginx -t 通过 → reload → 生效确认(gzip_proxied any ×4、/assets/ 长缓存块 ×2)→ 主域 200。

预期效果:那个 ~930 KB bundle → 约 250 KB(gzip 后);重复刷新时 /assets/* 走浏览器缓存。

验证方法:用户刷新后,取该请求的 $body_bytes_sent 对比 —— 预期从 ~930 KB 降到 250–300 KB 量级。

仍待排查(若压缩后依旧慢):① 该电脑链路本身(建议本地测速 / 是否走 VPN);② 每次刷新的 200+ 次小请求往返(属客户端行为,受 R2 限制不能改官方 dsh,只能靠降 RTT 或减少刷新)。

七、红线遵守

  • 排查全程只读:仅 ps/free/journalctl/nginx 日志/会话文件解压统计,未导出、未展示任何对话正文(分析器只输出时间戳与事件类型)。
  • 建议项不触碰 R1(不升级 dsh)与 R2(不改官方主程序);A1 走 profile patch 层官方机制,A2 仅改 nginx 站点配置。