一、背景
TCP连接经历了三次握手,当我们开发一个netty程序,运行在线上环境后,如何对其进行监控,并适时地进行参数调优。
本文以我们生产环境的一个通道程序,看一看三次握手的过程,以及Linux系统关于创建http连接的参数设置情况。
二、流程图
网上有很多关于tcp三次握手的讲解时序图,这里结合了两个队列的出入操作,详情见下:
三、linux机器(centos)的参数
优化TCP三次握手涉及到的参数主要有以下几个,另外就是绕开三次握手的策略。
参数 | 默认值 | 建议值 | 备注 |
---|---|---|---|
/proc/sys/net/ipv4/tcp_syn_retries | 5 | SYN报文重传的次数(客户端) | |
/proc/sys/net/ipv4/tcp_abort_on_overflow | 0 | 0 | 调试的时候,设置为1的时候,accept队列满后,服务端会发送reset报文给客户端 |
/proc/sys/net/ipv4/tcp_synack_retries | 2 | SYN+ACK报文重传的次数 | |
/proc/sys/net/ipv4/tcp_max_syn_backlog | 262144 | 半连接队列的长度 | |
/proc/sys/net/core/somaxconn | 128 | 全连接队列的长度 |
1、SYN报文重传的次数
2、开关tcp_abort_on_overflow
当accept队列满的时候,如果值设为1,server会返回reset报文给client;默认值是0,服务端会抛弃TCP第三次握手,回到第二次握手----由服务端重新发送SYN+ACK报文给客户端。
这里就会有一个重试发送的次数问题,见下一段。
3、SYN+ACK报文重传的次数
4、半连接队列的长度
tcp_max_syn_backlog的长度一般都远比somaxconn大,这就跟买东西讲价钱一样,真心诚意的往往比问价格的人少之又少。
TCP SYN FLOOD恶意DOS攻击就是建立大量的半连接状态的请求,然后丢弃而不进行第三次握手,真是害人~
半连接syns队列的连接要取出来给全连接队列,而全连接accept队列中的连接,在服务端accept()的时候触发取出。
也就是说,TCP三次握手,到建立连接完成,无论是半连接队列还是全连接队列,都不保留该连接。
5、全连接队列的长度
全连接队列的大小取决于:min(backlog, somaxconn) . backlog是在socket创建的时候传入的,somaxconn是一个os级别的系统参数。
- nginx默认是511
- tomcat默认是100
- netty的默认情况,见下文的源码分析
如何查看全队列的长度
linux机器分析netty端口是8889的tcp连接情况:
# ss -lnt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:8889 *:*
其中Send-Q 就是指全连接队列的长度为128,Recv-Q则是指在队列中和等待进队列的数量。
如果Recv-Q 大于 Send-Q 的话,则会出现客户端无法和服务端建立连接的异常情况。
调大nginx的backlog
netty listen()
public static final ChannelOption<Integer> SO_BACKLOG = valueOf("SO_BACKLOG");
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,<