WebSocket作为一种全双工通信协议,已经成为现代Web应用的标配。但在实际部署中,我们很少让客户端直接连接后端WebSocket服务,而是通过Nginx这样的反向代理来中转。这种架构设计主要基于以下考虑:
提示:WebSocket协议本质上是一个升级版的HTTP连接,建立握手后转为持久化的TCP通道。这也是为什么Nginx能无缝支持WebSocket代理。
下面是一个生产环境中验证过的配置模板,我们逐项解析关键参数:
nginx复制location /chat {
proxy_pass http://websocket_cluster;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 保持连接活跃
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
# 传递客户端真实信息
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_set_header X-Forwarded-Proto $scheme;
# 缓冲区优化
proxy_buffer_size 16k;
proxy_buffers 4 32k;
}
Upgrade $http_upgrade:告知后端这是协议升级请求Connection "upgrade":确认升级到WebSocket协议proxy_http_version 1.1:WebSocket必须使用HTTP/1.1对于高并发场景,需要配置upstream实现多节点负载:
nginx复制upstream websocket_cluster {
# 加权轮询
server 10.0.0.1:8080 weight=5;
server 10.0.0.2:8080;
# 保持会话一致性(可选)
ip_hash;
# 健康检查
check interval=3000 rise=2 fall=3 timeout=1000;
}
注意:如果使用
ip_hash保持会话,当后端服务器增减时需要谨慎,可能导致会话中断。
HTTPS环境下的WebSocket(wss://)需要特别注意:
nginx复制server {
listen 443 ssl;
server_name chat.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# 强化SSL配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
location /ws {
# 保持与HTTP相同的代理配置
}
}
防止单个客户端占用过多资源:
nginx复制location /ws {
# 限制每个IP的连接数
limit_conn ws_conn 10;
# 限制连接建立速率
limit_req zone=ws_req burst=20;
}
# 在http块中定义限制区域
limit_conn_zone $binary_remote_addr zone=ws_conn:10m;
limit_req_zone $binary_remote_addr zone=ws_req:10m rate=10r/s;
检查步骤:
tail -f /var/log/nginx/error.logtelnet backend_ip 8080101 Switching Protocols可能原因:
nginx复制# 内核参数优化(/etc/sysctl.conf)
net.core.somaxconn = 65535
net.ipv4.tcp_max_tw_buckets = 1440000
# Nginx worker配置
worker_processes auto;
worker_rlimit_nofile 100000;
events {
worker_connections 4096;
multi_accept on;
}
nginx复制location /nginx_status {
stub_status;
allow 10.0.0.0/8;
deny all;
}
通过curl http://localhost/nginx_status获取关键指标:
nginx复制log_format websocket '$remote_addr - $upstream_addr [$time_local] '
'"$http_upgrade" $status $body_bytes_sent';
access_log /var/log/nginx/websocket.log websocket;
使用GoAccess等工具分析:
在实际部署中,我们团队发现WebSocket连接在Nginx和后端服务之间保持长连接时,TCP的TIME_WAIT状态堆积是个常见问题。解决方法是在Nginx和后端服务之间启用keepalive:
nginx复制upstream backend {
server 10.0.0.1:8080;
keepalive 32; # 每个worker保持的连接数
}
这个配置让Nginx与后端复用TCP连接,而不是为每个WebSocket新建连接,实测可降低30%以上的连接建立开销。