为高负载网络优化Nginx和Node.js的方法

2019-10-17 21:13:16王旭


net.ipv4.tcp_fin_timeout

这是处于TIME_WAIT状态的连接在回收前必须等待的最小时间。改小它可以加快回收。

如何检查连接状态

使用netstat:

netstat -tan | awk '{print $6}' | sort | uniq -c

或使用ss:

ss -s

NginX

ss -s
Total: 388 (kernel 541)
TCP: 47461 (estab 311, closed 47135, orphaned 4, synrecv 0, timewait 47135/0), ports 33938

Transport Total IP IPv6
* 541 - -
RAW 0 0 0
UDP 13 10 3
TCP 326 325 1
INET 339 335 4
FRAG 0 0 0

随着web服务器的负载逐渐升高,我们就会开始遭遇NginX的某些奇怪限制。连接被丢弃,内核不停报SYN flood。而这时,平均负荷和CPU使用率都很小,服务器明明是可以处理更多连接的状态,真令人沮丧。

经过调查,发现有非常多处于TIME_WAIT状态的连接。这是其中一个服务器的输出:

有47135个TIME_WAIT连接!而且,从ss可以看出,它们都是已经关闭的连接。这说明,服务器已经消耗了绝大部分可用端口,同时也暗示我们,服务器是为每个连接都分配了新端口。调优网络对这个问题有一点帮助,但是端口仍然不够用。

经过继续研究,我找到了一个关于上行连接keepalive指令的文档,它写道:

设置通往上游服务器的最大空闲保活连接数,这些连接会被保留在工作进程的缓存中。

有趣。理论上,这个设置是通过在缓存的连接上传递请求来尽可能减少连接的浪费。文档中还提到,我们应该把proxy_http_version设为"1.1",并清除"Connection"头部。经过进一步的研究,我发现这是一种很好的想法,因为HTTP/1.1相比HTTP1.0,大大优化了 TCP连接的使用率,而Nginx默认用的是HTTP/1.0。

按文档的建议修改后,我们的上行配置文件变成这样:

upstream backend_nodejs {
server nodejs-3:5016 max_fails=0 fail_timeout=10s;
server nodejs-4:5016 max_fails=0 fail_timeout=10s;
server nodejs-5:5016 max_fails=0 fail_timeout=10s;
server nodejs-6:5016 max_fails=0 fail_timeout=10s;
keepalive 512;
}

我还按它的建议修改了server一节的proxy设置。同时,加了一个 p roxy_next_upstream来跳过故障的服务器,调整了客户端的 keepalive_timeout,并关闭访问日志。配置变成这样:

server {
listen 80;
server_name fast.gosquared.com;

client_max_body_size 16M;
keepalive_timeout 10;

location / {
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_pass http://backend_nodejs;
}

access_log off;
error_log /dev/null crit;
}

采用新的配置后,我发现服务器们占用的socket 降低了90%。现在可以用少得多的连接来传输请求了。新的输出如下:

ss -s