Socket.IO频繁触发‘Session ID unknown’错误求助(代理场景)
Socket.IO 连接每隔1小时触发「Session ID unknown」故障排查
问题现象
基于 Node.js + Socket.IO 4.5.1 开发的项目,通过 Apache2 代理部署后整体运行正常,但每隔约1小时所有连接都会触发「Session ID unknown」错误,导致项目运行缓慢。更换为 Nginx 代理后问题依然存在。
环境版本
Apache2: Apache/2.4.54 (Ubuntu) Socket.io Server: 4.5.1 Socket.io Client: 4.5.1
Apache 代理配置
<VirtualHost _default_:443> ServerName socket.myproject.com SSLEngine On SSLCertificateFile /etc/ssl/socket/primary.crt SSLCertificateKeyFile /etc/ssl/socket/private.key SSLCertificateChainFile /etc/ssl/socket/intermediate.crt LoadModule authn_file_module modules/mod_authn_file.so LoadModule authn_core_module modules/mod_authn_core.so LoadModule authz_host_module modules/mod_authz_host.so LoadModule authz_groupfile_module modules/mod_authz_groupfile.so LoadModule authz_user_module modules/mod_authz_user.so LoadModule authz_core_module modules/mod_authz_core.so LoadModule headers_module modules/mod_headers.so LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_balancer_module modules/mod_proxy_balancer.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so LoadModule rewrite_module modules/mod_rewrite.so LoadModule slotmem_shm_module modules/mod_slotmem_shm.so # User daemon # Group daemon Header add Set-Cookie "SERVERID=sticky.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED <Proxy "balancer://nodes_polling"> BalancerMember "http://localhost:1002" route=prod ProxySet stickysession=SERVERID </Proxy> <Proxy "balancer://nodes_ws"> BalancerMember "ws://localhost:1002" route=prod ProxySet stickysession=SERVERID </Proxy> RewriteEngine On RewriteCond %{HTTP:Upgrade} =websocket [NC] RewriteRule /(.*) balancer://nodes_ws/$1 [P,L] RewriteCond %{HTTP:Upgrade} !=websocket [NC] RewriteRule /(.*) balancer://nodes_polling/$1 [P,L] ProxyTimeout 3 </VirtualHost>
客户端代码
this.IO = io(AppConstants.socketBaseUrl, { query: { token:"blablabla...." }, path: '/socket.io', withCredentials: true, transports: ['websocket', 'polling'], secure: true, });
服务端代码
const socketServer = require('socket.io')(Server, { transports: ['websocket', 'polling'], cors: { origin: '*', credentials: true, methods: ['GET', 'POST'], }, });
排查与解决思路
1. 调整代理超时配置
当前 Apache 配置的 ProxyTimeout 3 仅为3秒,会导致代理层主动断开长连接。Socket.IO 长连接需要足够的超时时间,建议将 ProxyTimeout 调整为 3600(1小时)以上,或设置为 0 禁用超时(需结合业务场景评估)。
2. 固化 Socket.IO 会话存储
默认情况下 Socket.IO 会话存在内存中,服务重启或内存回收会导致会话丢失。建议使用 Redis 外部存储持久化会话:
const { createAdapter } = require('@socket.io/redis-adapter'); const { createClient } = require('redis'); const pubClient = createClient({ url: 'redis://localhost:6379' }); const subClient = pubClient.duplicate(); Promise.all([pubClient.connect(), subClient.connect()]).then(() => { socketServer.adapter(createAdapter(pubClient, subClient)); });
3. 优化 Socket.IO 心跳配置
显式配置服务端心跳参数,确保会话保持:
const socketServer = require('socket.io')(Server, { transports: ['websocket', 'polling'], cors: { origin: '*', credentials: true, methods: ['GET', 'POST'], }, pingInterval: 25000, // 25秒发送一次心跳 pingTimeout: 60000, // 60秒未收到响应则断开 });
4. 完善客户端重连逻辑
添加客户端断开监听,确保异常断开后自动重连:
this.IO.on('disconnect', (reason) => { console.log('连接断开:', reason); if (reason !== 'io client disconnect') { this.IO.connect(); } });
5. 排查代理层连接限制
- 检查 Apache 的
MaxRequestWorkers、MaxConnectionsPerChild参数,确保能容纳当前并发连接数。 - 若使用 Nginx,需配置长连接支持:
location /socket.io { proxy_pass http://localhost:1002; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_read_timeout 3600s; proxy_send_timeout 3600s; }
6. 开启日志排查
- 服务端开启 Socket.IO 调试日志,追踪会话丢失细节:
DEBUG=socket.io* node your-server-file.js - 查看 Apache/Nginx 的访问日志、错误日志,确认是否有代理层主动断开连接的记录。
内容的提问来源于stack exchange,提问作者Ahmad Echem
相关产品推荐
相关产品推荐

