负载均衡与健康检查:Nginx 配置 WebSocket 负载均衡、健康检查端点
信令服务器跑起来了,单个节点也能正常工作。但问题来了——用户量一上来,单节点扛得住吗?我在早期的一个项目中就吃过这个亏。当时觉得信令服务器轻量,一台机器绰绰有余。结果上线第三天,并发连接数直接打穿CPU,用户集体掉线。嗯,从那以后,我再也不敢轻视负载均衡了。
说白了,WebRTC的信令服务器虽然不像媒体服务器那样吃带宽,但它要维持大量长连接。单节点一旦挂掉,所有用户的通话都会中断。所以我们需要Nginx来做两件事:把流量分散到多个信令节点,以及自动剔除故障节点。
为什么WebSocket负载均衡比HTTP更棘手?
你想想看,普通HTTP请求是短连接,请求完就断开。Nginx随便轮询一下就行。但WebSocket是长连接,一旦建立,客户端和服务器要保持长时间的通信。
这里有个坑:WebSocket的升级过程。客户端先发一个HTTP Upgrade请求,Nginx得把这个请求转发到同一个后端节点。如果后续的WebSocket帧被转发到别的节点,连接就断了。
我在项目中遇到过这种情况:配置了普通的HTTP负载均衡,结果WebSocket连接频繁断开。查了半天才发现,Nginx默认的负载均衡策略会把WebSocket的后续帧分发到不同节点。解决方案就是启用ip_hash或sticky会话保持。
Nginx配置WebSocket负载均衡
先看一个基础配置。我个人习惯把WebSocket的负载均衡单独写一个upstream块,方便管理。
upstream signaling_servers {
# 使用ip_hash保证同一个客户端的请求始终落到同一台后端
ip_hash;
# 后端信令服务器列表
server 192.168.1.10:8080 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.12:8080 backup; # 备用节点
}
server {
listen 443 ssl;
server_name signaling.example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
location /ws {
# 关键:升级WebSocket协议
proxy_pass http://signaling_servers;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 保持长连接的超时设置
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
# 传递真实IP
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
}
这里有几个要点:
- ip_hash:确保同一个IP的请求始终转发到同一台后端。WebSocket长连接必须这么做。
- proxy_read_timeout:设长一点。WebSocket连接可能持续几十分钟甚至几小时,默认60秒超时会导致连接被切断。
- Upgrade头:必须显式传递,否则Nginx不会识别WebSocket协议。
sticky模块或基于Cookie的会话保持。
健康检查:自动剔除故障节点
光有负载均衡还不够。如果某个信令服务器挂了,Nginx还继续往它转发请求,那用户就彻底连不上了。我们需要健康检查来自动剔除故障节点。
Nginx开源版自带的健康检查比较基础,就是上面配置里的max_fails和fail_timeout。它的逻辑是:如果连续max_fails次请求失败,就把这个节点标记为不可用,等待fail_timeout秒后再尝试。
但这种方式有个问题:它只能检测到Nginx转发请求失败的情况。如果后端进程还在,但业务逻辑已经卡死(比如内存泄漏导致响应缓慢),Nginx可能检测不到。
所以我建议在信令服务器里单独暴露一个健康检查端点。这个端点不参与业务逻辑,只做简单的存活检测。
实现健康检查端点
以Node.js为例,在信令服务器里加一个轻量级的HTTP端点:
const http = require('http');
const express = require('express');
const app = express();
// 健康检查端点
app.get('/health', (req, res) => {
// 检查WebSocket服务器是否正常运行
const wsServer = req.app.get('wsServer');
const isHealthy = wsServer && wsServer._server.listening;
if (isHealthy) {
res.status(200).json({
status: 'ok',
uptime: process.uptime(),
connections: wsServer.clients.size
});
} else {
res.status(503).json({
status: 'error',
message: 'WebSocket server not running'
});
}
});
// 信令服务器主逻辑
const server = http.createServer(app);
const WebSocket = require('ws');
const wss = new WebSocket.Server({ server });
app.set('wsServer', wss);
server.listen(8080, () => {
console.log('Signaling server running on port 8080');
});
这个端点返回的信息很关键:
- HTTP状态码:200表示正常,503表示异常。Nginx的负载均衡器会根据状态码判断节点是否健康。
- 连接数:可以辅助判断节点是否过载。如果连接数超过阈值,可以考虑暂时不分配新连接。
- 运行时间:快速判断节点是否刚重启过。
Nginx主动健康检查(商业版 vs 开源方案)
Nginx Plus(商业版)内置了主动健康检查功能,可以定期向后端发送请求,检测端点是否正常。配置如下:
upstream signaling_servers {
zone signaling 64k;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
# 主动健康检查
health_check interval=5s fails=3 passes=2 uri=/health;
}
但如果你用的是Nginx开源版,也有替代方案。我推荐用nginx_upstream_check_module这个第三方模块。它提供了类似商业版的主动健康检查功能。
安装这个模块后,配置如下:
upstream signaling_servers {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
# 主动健康检查
check interval=3000 rise=2 fall=5 timeout=1000 type=http;
check_http_send "GET /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
参数说明:
| 参数 | 含义 | 推荐值 |
|---|---|---|
| interval | 检查间隔(毫秒) | 3000(3秒) |
| rise | 连续成功几次后标记为健康 | 2 |
| fall | 连续失败几次后标记为不健康 | 5 |
| timeout | 检查请求超时时间(毫秒) | 1000 |
整体架构图
下面这张图展示了Nginx负载均衡+健康检查的完整流程:
配置验证与测试
配置写好了,怎么验证它是否生效?我一般会做这几步:
- 检查Nginx配置语法:
nginx -t,确保没有拼写错误。 - 模拟节点故障:手动停掉一个信令服务器进程,观察Nginx是否把请求转发到其他节点。
- 查看健康检查日志:在Nginx的access log里,可以看到健康检查请求的痕迹。如果某个节点连续返回503,Nginx会把它标记为不可用。
- 压力测试:用WebSocket压测工具(比如wsbench)模拟大量连接,观察各节点的负载是否均衡。
- WebSocket负载均衡必须启用会话保持(ip_hash或sticky)
- 健康检查端点要独立于业务逻辑,只做存活检测
- 主动健康检查比被动检测更可靠,能提前发现故障
- 备用节点可以在主节点全部故障时兜底
我曾经在一个生产环境中遇到过这样的情况:三个信令节点,其中一个因为内存泄漏导致响应越来越慢,但进程还在。被动健康检查检测不到,Nginx继续往它转发请求,结果那台机器上的用户全部卡顿。后来加了主动健康检查,检测到响应时间超过阈值就自动剔除,问题才解决。
嗯,负载均衡和健康检查这块,说白了就是给信令服务器加一层保险。配置起来不复杂,但能避免很多线上事故。你想想看,用户正在视频通话,突然掉线了,那体验得多糟糕。所以这一步,值得花时间做好。
公众号:蓝海资料掘金营,微信deep3321