找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2062

积分

0

好友

325

主题
发表于 昨天 00:34 | 查看: 0| 回复: 0

今天遇到一个线上服务卡顿的问题,具体是外部访问经过 Nginx 代理的 MCP (Model Context Protocol) SSE (Server-Sent Events) 端点时,连接会一直卡住。排查与解决问题的过程记录如下,希望能给遇到类似场景的伙伴一些参考。

故障现象

该服务前端配置了一个 Nginx 作为反向代理,初始配置如下:

server {
    listen 8081;
    server_name xx.xx.xx;

    location / {
        proxy_pass http://svc-bot-prod:12213;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_connect_timeout 300;
        proxy_send_timeout 300;
        proxy_read_timeout 300;
        proxy_buffer_size 128k;
        proxy_buffers 8 64k;
        proxy_busy_buffers_size 128k;
        proxy_temp_file_write_size 128k;
    }
}

直接访问服务的根路径 https://xx.xx.xx/ 是正常的,返回预期的 JSON 响应。

浏览器中返回的JSON错误信息

但是,当访问 SSE 端点 https://xx.xx.xx/sse 时,浏览器会一直处于加载状态,请求被挂起。

浏览器Network面板显示请求卡住的截图

排查过程

首先,我们怀疑是后端服务本身的问题。于是进入服务 Pod 内部以及从 Nginx Pod 内部直接向后端服务发起测试:

sh-4.4$ curl http://127.0.0.1:12213/sse
event: endpoint
data: /message?sessionId=1oVX80qW7YS5ZdKgUdfnv
sh-4.4$ curl http://svc-bot-prod:12213/sse
event: endpoint
data: /message?sessionId=1oVX80qW7YS5ZdKgUdfnvQ

测试结果表明,绕过 Nginx 代理直接访问后端服务的 /sse 端点,SSE 流能够立即返回数据,连接是正常的。这说明后端服务本身没有问题。

接着,查看后端服务的 Pod 日志,发现大量与 “canceled” 相关的记录,时间点恰好与外部访问卡住的时间吻合:

2026-01-29 11:29:34.8595|INFO|ModelContextProtocol.Server.McpServer|Server (WebAPI 1.0.0.0) message processing canceled.
2026-01-29 11:29:34.8595|INFO|200|ModelContextProtocol.Server.McpServer|||Server (WebAPI 1.0.0.0) message processing canceled.-|chatbot-porta-backend-prod-788b885fdf-w2btf||GET-|curl/7.61.1|ModelContextProtocol.McpSessionHandler.LogEndpointMessageProcessingCanceled
2026-01-29 11:32:25.6742|INFO|200|ModelContextProtocol.Server.McpServer|||Server (WebAPI 1.0.0.0) message processing canceled.-|chatbot-porta-backend-prod-788b885fdf-w2btf||GET-|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0|ModelContextProtocol.McpSessionHandler.LogEndpointMessageProcessingCanceled
2026-01-29 11:32:25.6742|INFO|ModelContextProtocol.Server.McpServer|Server (WebAPI 1.0.0.0) message processing canceled.
...

日志显示连接被取消,这通常是代理或客户端主动中断了连接。结合之前“直连正常、代理后卡住”的现象,问题根源指向了 Nginx 的默认代理行为与 SSE 这种长连接、流式响应协议的不兼容。

问题根因与解决方案

Nginx 默认的 proxy_buffering 是开启的,它会缓冲上游服务器(即后端应用)的响应数据。对于普通的 HTTP 请求,这可以提高性能。但对于 Server-Sent Events 这种需要实时、持续推送数据的流式连接来说,缓冲机制是致命的:

  1. 实时性失效:Nginx 会等待接收完一定量的数据(缓冲区满)或连接关闭后,才将数据一次性发送给客户端,导致客户端长时间收不到任何消息。
  2. 连接超时:由于数据被缓冲,连接看起来处于“静默”状态,可能触发客户端或 Nginx 自身的超时设置,最终断开连接,体现在后端日志中就是 “canceled”。

因此,解决方案的核心是为 SSE 端点配置独立的 Nginx location,并关闭缓冲和相关缓存

以下是为 /sse 路径添加的专用配置:

location /sse {
    # 配置代理的后端服务器地址
    proxy_pass http://svc-bot-prod:12213;

    # 关键配置1:关闭响应缓冲,实现数据实时透传
    proxy_buffering off;
    # 关键配置2:关闭缓存,防止响应被缓存
    proxy_cache off;

    # 设置长超时,适应SSE长连接特性
    proxy_read_timeout 3600s;
    proxy_connect_timeout 3600s;

    # SSE 需要 HTTP/1.1
    proxy_http_version 1.1;
    # 清除 Connection 头,避免发送关闭信号
    proxy_set_header Connection '';

    # 传递必要的代理头部
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # 关键配置3:禁用加速缓冲(X-Accel-Buffering),确保流式输出
    proxy_set_header X-Accel-Buffering no;
}

配置要点解析

  • proxy_buffering off;:这是最重要的指令,它告诉 Nginx 不要缓冲来自后端服务的响应体,收到数据后立即转发给客户端。
  • proxy_cache off;:作为双重保险,防止任何层级的缓存干扰流式输出。
  • proxy_http_version 1.1;proxy_set_header Connection '';:确保使用 HTTP/1.1 并保持连接持久化,这是 SSE 协议的基础。
  • proxy_set_header X-Accel-Buffering no;:这个头部对 Nginx 自身尤其重要,它会覆盖可能存在的 proxy_buffering 默认值,强制禁用缓冲。
  • 超时设置:将 proxy_read_timeoutproxy_connect_timeout 设置为一个很大的值(如3600秒),以避免在长连接空闲期间被意外断开。

验证结果

在 Nginx 配置中添加上述 /sselocation 块,并执行 nginx -s reload 重载配置后,再次从外部访问 https://xx.xx.xx/sse

浏览器开发者工具Console显示SSE连接成功,接收到 endpoint 事件

如图所示,SSE 连接立即建立,并成功收到了 event: endpoint 事件数据,问题得到解决。后端服务的 “canceled” 日志也随即消失。

总结

当使用 Nginx 代理 SSE、WebSocket 等长连接或流式服务时,必须特别注意其默认的缓冲行为。通用代理配置往往无法满足这类场景的实时性要求。最佳实践是针对具体的流式端点路径,配置独立的 location 块,并明确关闭缓冲和缓存,同时调整超时和 HTTP 版本设置。

这次排查也提醒我们,面对“内部正常、外部异常”的网络问题时,中间件(如 Nginx、API 网关)的配置是需要优先排查的方向。希望这个案例能帮到你。如果你在部署微服务或处理高并发架构时遇到其他问题,欢迎来 云栈社区 交流探讨。




上一篇:职场反思:我都为工作吃了苦,为何还要被质问“不够热爱”?
下一篇:深入剖析Linux Mesa 3D图形栈:从Gallium3D架构到NIR编译与生态演进
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-1 01:30 , Processed in 0.475468 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表