Nginx作为反向代理服务器,TCP连接数及状态异常
Nginx 运行主机较多 TIME_WAIT 状态连接:
一、基础知识
- TIME_WAIT 只会出现在主动关闭连接的一端(CLOSE_WAIT 只会出现在被动关闭连接的一端);
- nginx 配置文件:upstream 块中的 keepalive 数值控制启用 nginx 和后端的长连接时 Nginx 到 upstream 服务器的空闲 keepalive 连接的最大数量;
- 在 nginx 反向代理的场景下:当 nginx 启用了长连接(启用 http1.1 且配置相关配置项),同时 keepalive 的数值略小,在长连接不够用时 Nginx 会新建连接来处理新的请求,且处理完主动关闭回收连接,此时 nginx 端就会出现大量 TIME_WAIT 状态的连接;如果未启用长连接,每次请求处理完之后由后端 server 主动关闭连接,在大并发的场景下:后端 server 就会出现大量 TIME_WAIT 状态的连接(nginx 会报 no live upstream);
- TIME_WAIT 是本机主动关闭连接时留下的,理论上对系统基本影响不大;不影响性能且各状态连接数综合远小于可用端口数的话不用在意,数量过多则考虑优化;
二、可选优化方向如下:
-
优化连接配置(评估长连接的使用);nginx 作为反向代理服务器时,在于 client 端(如浏览器)交互时充当 server 端,与后端 upstream 交互时充当 client 端;对应的长连接配置也分为两部分:
- 如果使用长连接(结合
proxy_http_version 1.1;
和proxy_set_header Connection "";
使用),要注意合理分配 keepalive 的数值,且端口号要足够,避免 Nginx 端大量的 TIME_WAIT 以及耗尽端口之后出现客户端连接失败的问题; - keepalive 数值(长连接的数量)估算:根据 QPS 和平均响应时间大体能计算出需要的长连接的数量,比如 10000 QPS 和 100 毫秒响应时间就可以推算出需要的长连接数量大概是 1000,然后将 keepalive 设置为这个长连接数量的 10%到 30%
- 与 client 端交互时启用长连接关键配置参数及说明如下:
# 开启从client到nginx的连接长连接支持,指定每个 TCP 连接最多可以保持多长时间 # keepalive_timeout的值应该比 client_body_timeout 大 keepalive_timeout 60; # keepalive_requests指令用于设置一个keep-alive连接上可以服务的请求的最大数量,当最大请求数量达到时,连接将被关闭 keepalive_requests 1000;
- 与后端 upstream 交互时启用长连接关键配置参数及说明如下:
# 启用nginx和后端server(upstream)之间长连接支持(必设项,否则很影响nginx性能),HTTP协议中从1.1版本才支持长连接;启用时需要评估upstream的keepalive参数(默认是关闭的,比较懒的同学可以设置为500) proxy_http_version 1.1; # 每次访问完后端server后如何处理本次连接,默认配置是close(会给后端server带来大量的TIME_WAIT连接,降低后端server性能),设置为""结合proxy_http_version设置连接保持; proxy_set_header Connection "";
- 如果使用长连接(结合
-
修改内核参数(增大系统可用端口范围、开启 socket 重用和快速回收等):编辑 /etc/sysctl.conf,酌情添加下述配置:
net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_timestamps=1 net.ipv4.tcp_tw_reuse=1 net.ipv4.tcp_max_tw_buckets = 5000 net.ipv4.tcp_max_syn_backlog = 8192 net.ipv4.tcp_keepalive_time = 1200 net.ipv4.ip_local_port_range = 1024 65000 net.ipv4.tcp_tw_reuse = 1
二、常用命令:
- 查看各状态的连接数命令(netstat):
netstat -ant | awk '/^tcp/ {++S[$NF]} END {for (a in S) print (a,S[a])}'
- 查看各状态的连接数(ss):
ss -s
- 命令行配置内核参数:将 net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_timestamps 配置为 1:
sysctl -w net.ipv4.tcp_timestamps=1
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -p