事情本身不复杂,线索都在日志里。Ubuntu 22.04 上 nginx 1.24 反代一个消息推送服务,前端 EventSource 十分钟才收到一条消息,直连后端 8080 是秒级推送,nginx 里看不到任何报错。

第一反应是「中间还有一层 CDN,同样会对流式响应做缓冲和 gzip」,验证下来不成立。

排查方向其实有限,先把可能性排一排。nginx 默认开启 proxy_buffering,后端按小块写出的数据被攒在缓冲区里等满才发。少数情况下是上游响应没带 Content-Type: text/event-stream,nginx 按普通文本处理并压缩。

另外,keepalive_timeout 到期主动断开,前端每隔一段就重连一次,看起来像丢消息。

第一件事是确认响应头里有没有被加上缓冲标记

curl -sI -H 'Accept: text/event-stream' https://push.example.com/sse | grep -iE 'content-type|transfer-encoding'

然后在该 location 上关闭缓冲并禁用压缩

printf 'location /sse { proxy_pass http://127.0.0.1:8080; proxy_buffering off; gzip off; proxy_read_timeout 3600s; }\n' > /etc/nginx/conf.d/sse.conf && nginx -t && nginx -s reload

补上事件流所需的响应头

printf 'proxy_set_header X-Accel-Buffering no;\n' >> /etc/nginx/conf.d/sse.conf && nginx -s reload

等前面都确认过,再用 curl 观察消息到达的时间间隔

curl -N -H 'Accept: text/event-stream' https://push.example.com/sse | head -5

改完先别撤,确认这几项。curl -N 每秒都能打出新消息,浏览器 DevTools 的 EventStream 面板里消息时间戳连续,不再出现十分钟才一条的间隔。

容易忽略的是,X-Accel-Buffering 是应用侧能自救的一招,后端加上这个头 nginx 就会关缓冲;流式接口的 read_timeout 也要放大,否则长连接会被主动切掉。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。

作者 9823189