首页/AI/大模型部署与运维速查/SSE 心跳:防中间设备断流

SSE 心跳:防中间设备断流

长生成期间链路可能被判空闲而断开:周期发送 SSE 注释行做心跳,并把各层 idle 超时设得大于心跳间隔;客户端需能忽略注释行。

流式长连接为什么会中途断掉

服务端推送(SSE)依赖一条长期保持的 HTTP 响应。链路上的网关、负载均衡、CDN 都会统计「多久没有数据流过」,超过各自设定的空闲阈值就把连接判为死连接主动回收。长生成任务里可能出现几十秒没有内容输出的阶段(比如思考、检索、工具调用),这段时间恰好落在判空闲的窗口内,于是客户端看到的是回答中途静默然后报错。

基本信息

协议基础HTML 规范定义的 Server-Sent Events,基于 HTTP 长响应
心跳载体以冒号开头的注释行,不进入数据通道
生效层次应用层心跳,与 TCP 保活机制是两回事
间隔取值常见做法是十几秒到半分钟,需小于链路最短空闲阈值
客户端要求解析器需能忽略注释行,官方实现均支持

典型使用场景

  • 长生成任务:推理中间存在较长的静默期,需要持续证明连接存活
  • 经过多层代理:请求路径上有 CDN 或企业出口代理时,各层超时都要一起考虑
  • 移动与弱网客户端:连接容易被网络中间设备回收,心跳能维持会话
  • 长轮询替代方案:需要服务端在无数据时也维持响应通道的场景
  • 排查断流原因:把心跳间隔与各层超时对照,能快速定位是哪一层在切连接

心跳行与各层配合

心跳行与各层配合
: ping

(以冒号开头的行为 SSE 注释,数据通道不受影响)

链路各层空闲阈值需大于心跳间隔:
  客户端读超时   > 心跳间隔
  反向代理读超时 > 心跳间隔
  CDN 空闲超时   > 心跳间隔
推荐做法:心跳间隔取链路最短阈值的二分之一到三分之一

断流点定位

现象可能所在层核对方式
静默固定时长后中断,数值稳定某一层的空闲超时被触发用固定间隔心跳,观察实际断开的时间点
只有经过 CDN 的域名中断CDN 侧空闲超时更短对比直连与经 CDN 两条路径
低并发正常、高并发中断连接数或资源限制而非超时核对连接数与文件描述符上限
日志显示上游连接被关闭反向代理读超时先触发检查代理的读超时配置
客户端本地中断客户端自身读超时或网络切换抓客户端侧日志确认
心跳间隔参考链路最短的空闲容忍度:上线前把 CDN、代理与客户端的超时值扫一遍对齐,任何一层短于心跳间隔都会成为断流的那一环。
验证方法:在最长的真实链路上跑一次超长生成任务,确认实际断开时间点大于任务时长,而不是只在内部网络里测试。

易错点

  • 只调反向代理超时:CDN 或企业代理的空闲阈值更短,流式仍会被中途切断
  • 心跳间隔大于某一层阈值:心跳还没发出连接就被回收,等于没有心跳
  • 心跳写成数据行:注释与数据的写法不同,写错会污染数据通道,客户端解析出错
  • 忽略 TCP 保活机制:应用层心跳与内核保活作用层次不同,只依赖后者无法防止中间设备按空闲判定断开

数据来源与参考

  • HTML 规范:Server-Sent Events(html.spec.whatwg.org)
  • Nginx 官方文档:代理超时(nginx.org/en/docs)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌