TCP连接数以NGINX是否启用长链接对照组实验

前言

由于发现生产环境,时不时会出现502错误BAD GATEWAY考虑是TCP链接不够用的问题,后发现NGINX未开启NGINX到后端服务的长链接,后考虑开启长连接配置,因此有了本次实验。


名词解释

LISTEN: 侦听来自远方的TCP端口的连接请求
SYN-SENT: 再发送连接请求后等待匹配的连接请求
SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认
ESTABLISHED: 代表一个打开的连接
FIN-WAIT-1: 等待远程TCP连接中断请求,或先前的连接中断请求的确认
FIN-WAIT-2: 从远程TCP等待连接中断请求
CLOSE-WAIT: 等待从本地用户发来的连接中断请求
CLOSING: 等待远程TCP对连接中断的确认
LAST-ACK: 等待原来的发向远程TCP的连接中断请求的确认
TIME-WAIT: 等待足够的时间以确保远程TCP接收到连接中断请求的确认
CLOSED: 没有任何连接状态


测试环境及方法

环境 进程 版本
WINDOWS10 NGINX 1.20.2
3.10.0-1160.el7.x86_64 #1 SMP x86_64 x86_64 x86_64 GNU/Linux SPRING-CLOUD-GATEWAY 2.2.7.RELEASE

由于目前测试和生产服务器上nginx版本均是1.16.1不支持upstream的keepalive,于是在本地搭建nginx1.20.2版本,设置本地hosts将网关域名指向127.0.0.1,本地用jmeter进行压测。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

#user nobody;
worker_processes 1;

#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#pid logs/nginx.pid;


events {
worker_connections 1024;
}


http {
include mime.types;
default_type application/octet-stream;
#access_log logs/access.log main;

sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
#keepalive_timeout 65;

#gzip on;

upstream api_backend {
server 127.0.0.1:10000;
#keepalive 16;
#keepalive_requests 10000000;
}

server {
listen 80;
server_name api.drstrong.cn apitest.drstrong.cn apitest1.drstrong.cn;
#ssl on;
ssl_session_timeout 5m;
underscores_in_headers on;
location / {
proxy_pass http://api_backend;
#Proxy Settings
proxy_redirect off;
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_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_max_temp_file_size 0;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
#proxy_http_version 1.1;
#proxy_set_header Connection "";
}

}

}

开启keepalive配置主要有三项配置:

1
2
3
4
5
6
7
8
9
upstream api_backend {
keepalive 16;
}
server{
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}

1、测试通过linux脚本netstat -tan|awk '$1~/tcp/{aa[$NF]++}END{for (h in aa)print h,aa[h]}'获取本时刻各TCP状态的链接数,循环2秒跑次脚本记录在日志中

2、通过grep ‘ESTABLISHED’ 06291458.log | awk ‘{print $2}’ | awk ‘{sum+=$1} END {print “avg=”,sum/NR}’ 命令统计日志中各TCP状态的平均值

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
j=$1
for ((i=1; i<=j; i++))
do
result=`netstat -tan|awk '$1~/tcp/{aa[$NF]++}END{for (h in aa)print h,aa[h]}'`
echo "$result"

tcpstat=`netstat -nat|grep -i "80"|wc -l`
echo "TCP $tcpstat"
gatewaystat=`netstat -nat|grep -i "10000"|wc -l`
echo "GATEWAY-TCP $gatewaystat"
sleep 2
done
1
2
sh test.sh 60 > 06291458.log
grep 'ESTABLISHED' 06291458.log | awk '{print $2}' | awk '{sum+=$1} END {print "avg=",sum/NR}'

启用长连接

无压测(2min分钟样本的平均结果):

1
2
3
4
ESTABLISHED 1710.67
TCP 62.0833
GATEWAY-TCP 0
TIME_WAIT 1341.13

理论吞吐量1200/s 200线程同时启动 压测5分钟

1
2
3
ESTABLISHED 1734.67
GATEWAY-TCP 18.8333
TIME_WAIT 1529.3

理论吞吐量2400/s 200线程同时启动 压测5分钟

1
2
3
ESTABLISHED 1752.37
GATEWAY-TCP 19.0333
TIME_WAIT 1313.37


不启用长连接

理论吞吐量1200/s 200线程同时启动 压测5分钟

1
2
3
ESTABLISHED 1750.8
GATEWAY-TCP 15458.7
TIME_WAIT 16923.8

理论吞吐量2400/s 200线程同时启动 压测5分钟

1
2
3
ESTABLISHED 1704.8
GATEWAY-TCP 15530.8
TIME_WAIT 17072.4


结论

由以上测试数据可知:在未开启nginx到微服务层的长连接的时候,链接网关端口的TCP链接在1W+、TIME_WAIT的链接也在1W+,当开启长连接的时候,TCP、TIME_WAIT的链接维持在20以内。根据理论建立销毁TCP链接需要三次握手四次挥手,保持长连接的性能上肯定是有提升的