负载均衡部署的socket.io无法路由到全部三台服务器,如何测试路由效果?
Socket.io 多实例负载均衡路由分发测试方案
前置配置排查
先确认单台实例有流量的根因,排除配置问题后再做分发测试:
- 检查nginx负载配置,确认是否开启了
ip_hash、sticky_cookie等会话保持规则。Socket.io默认使用长连接,本地测试所有请求均来自同一IP时,开启会话保持会导致所有连接被路由到同一台实例,这是该问题最常见的诱因。 - 单独验证3台Socket.io实例的可用性,分别执行命令
curl http://localhost:<实例对应端口>/socket.io/?EIO=4&transport=polling,确认每个实例都能正常返回响应,无服务挂掉、端口占用等问题。 - 确认nginx上游配置中3台实例的权重均为非0值,没有设置下线、备份等规则。
路由分发效果测试方法
1. 无粘性会话场景测试
- 关闭nginx所有会话保持配置,负载策略修改为默认的轮询(
round_robin)。 - 提前在每台Socket.io服务中新增
/instance-id接口,返回当前实例的唯一标识(可以用启动时传入的环境变量、服务端口等作为标识)。 - 编写批量测试脚本模拟多客户端连接:
const { io } = require('socket.io-client'); const fetch = require('node-fetch'); const NGINX_URL = 'http://你的nginx负载监听地址'; const TEST_CONN_COUNT = 100; // 测试连接数,可自行调整 const stat = {}; let finishedCount = 0; async function runSingleTest() { const socket = io(NGINX_URL, { transports: ['websocket', 'polling'], forceNew: true }); socket.on('connect', async () => { // 获取当前连接所属的实例标识 const res = await fetch(`${NGINX_URL}/instance-id`, { headers: { 'socket-id': socket.id } }); const instanceId = await res.text(); stat[instanceId] = (stat[instanceId] || 0) + 1; finishedCount++; socket.disconnect(); if (finishedCount === TEST_CONN_COUNT) { console.log('==== 路由分发统计结果 ===='); console.table(stat); } }); } // 错开时间发起连接,避免瞬时并发过高 for (let i = 0; i < TEST_CONN_COUNT; i++) { setTimeout(runSingleTest, i * 100); }
- 运行脚本后查看统计结果,轮询模式下3台实例的连接数差值不会超过10%即为分发正常。
2. 有粘性会话场景测试
- 开启nginx粘性会话配置后,可通过自定义请求头模拟不同来源IP的客户端,本地测试时需要先在nginx配置中添加如下规则:
set_real_ip_from 127.0.0.1; real_ip_header X-Forwarded-For;
- 修改测试脚本,每个连接携带不同的
X-Forwarded-For请求头,运行后验证:相同IP的请求会落到同一台实例,不同IP的请求均匀分布到3台实例即为分发正常。
3. 长连接存活分布验证
- 批量建立100个以上长连接保持不断开,分别登录3台Socket.io服务器,执行命令
ss -antp | grep <实例运行端口> | grep ESTAB | wc -l统计每个实例的活跃长连接数,确认分布符合配置的负载策略。 - 可手动停止其中1台实例,观察连接是否会自动漂移到另外2台正常运行的实例,验证容灾场景下的路由分发逻辑。
注意事项
- Socket.io握手阶段会先发起2个polling请求再升级为websocket协议,要确保nginx的负载规则对所有transport类型的请求都生效,不要只针对websocket请求做负载。
- Redis适配器仅负责多实例之间的事件同步,不影响负载均衡路由逻辑,路由分发异常不需要排查Redis侧配置。
内容的提问来源于stack exchange,提问作者Miluzz
相关产品推荐
相关产品推荐

