v4.9.6 SSEServerTransport多mcp_server容器Pod兼容性问题
例行检查
- [x] 我已确认目前没有类似 issue
- [x] 我已完整查看过项目 README,以及项目文档
- [x] 我使用了自己的 key,并确认我的 key 是可正常使用的
- [x] 我理解并愿意跟进此 issue,协助测试和提供反馈
- [x] 我理解并认可上述内容,并理解项目维护者精力有限,不遵循规则的 issue 可能会被无视或直接关闭
你的版本
- [ ] 公有云版本
- [x] 私有部署版本, 多pod部署mcp_server, 具体版本号: 4.9.6
问题描述
当前使用SSEServerTransport的实现在多mcp_server容器Pod部署时存在会话不连贯问题。由于会话状态存储在Pod内存中(transportMap),当负载均衡器将初始SSE请求和后续POST请求分发到不同Pod时,系统无法找到对应的transport实例,导致请求挂起直到超时。这严重影响了系统在Kubernetes等容器编排环境下的可扩展性和可靠性。
复现步骤
- 部署当前代码到两个或多个Pod的Kubernetes集群:
const transportMap: Record<string, SSEServerTransport> = {};
app.get('/:key/sse', async (req, res) => {
const transport = new SSEServerTransport(`/${key}/messages`, res);
transportMap[transport.sessionId] = transport;
// 设置服务器和处理程序...
await server.connect(transport);
});
app.post('/:key/messages', (req, res) => {
const { sessionId } = req.query as { sessionId: string };
const transport = transportMap[sessionId];
if (transport) {
transport.handlePostMessage(req, res);
}
// 如果transport不存在,请求会挂起
});
- 配置负载均衡器(如Nginx或Kubernetes Ingress)分发请求
- 客户端(fastgpt容器pod)首先连接到
/:key/sse端点获取sessionId - 然后客户端发送POST请求到
/:key/messages?sessionId=xxx - 观察当请求随机分发到不同mcp server Pod时出现的连接挂起超时情况
预期结果
- 系统应该能够处理多Pod环境中的请求,无论请求分发到哪个Pod
- GET和POST请求应该能够跨Pod正常工作
- 客户端体验应保持一致,不受底层Pod分配的影响
- 即使GET和POST请求被路由到不同的Pod,也不应出现挂起或超时
- 系统应该在水平扩展时保持会话一致性,支持无状态水平扩展
实现方案可以采用Redis等共享存储保存会话状态,并通过StreamableHTTPServerTransport的无状态模式或者改进的SSEServerTransport处理机制来解决这个问题。
解决方案
重构以支持分布式部署,可以采用以下方法之一:
方案1:在无状态模式下使用StreamableHTTPServerTransport
- 使用sessionIdGenerator: undefined初始化
- 为每个请求创建新的transport/server实例
- 使用Redis进行跨Pod会话状态存储
方案2:简化SSE + 共享会话存储
- SSE端点仅返回带sessionId的URL,然后关闭
- 在Redis中存储会话数据并设置适当的TTL
- 为每个POST请求创建新的transport/server
实现要求
- 在Redis中存储最小化的会话数据,而不是内存中
- 为每个请求创建新的transport而不是重用
- 对StreamableHTTP使用无状态模式或在发送endpoint后关闭SSE连接
- 处理请求前通过分布式存储验证会话
- 这种架构可以实现跨多个Pod的水平扩展,同时保持会话一致性。
sse 默认不支持多副本,改造起来 过于复杂 ,意义 不大 。 httpsreamable 协议大部分 client 还未支持,还需要等待支持,这个比较容易适配多副本。
higress 有对应负载方案,不过不太普适。
感觉等待 HTTP streamable 成熟即可,这东西有状态感觉意义没多大,感觉无状态+单次流连接的模式足够了,还稳定。
sse 默认不支持多副本,改造起来 过于复杂 ,意义 不大 。 httpsreamable 协议大部分 client 还未支持,还需要等待支持,这个比较容易适配多副本。
感觉现在client升级到最新版都支持streamable了,其次 mcp spec 在2025-03-26版本已废弃sse,推荐使用streamable。
建议 mcp server模块可支持streamable,开放非 /sse 的路径,如spec文档例子中的 /mcp ,如果需要兼容旧sse可保留旧代码。这样对于私有部署用户来说是灵活的,可根据自身部署方式和需求按需选择。
已支持 https://github.com/labring/FastGPT/pull/4695,无需额外部署 mcp_server