实战!一次网络问题排查( 六 )


实战!一次网络问题排查

文章插图
 
image-20200527235838846
那怎么判断服务端有没有发生accept queue(全连接队列)满呢?在linux 可以采用如下指令:
1netstat -s | grep "listen"每隔几秒打印一次,如下图所示:
实战!一次网络问题排查

文章插图
 
image-20200527235626558
如果overflowed 代表队列溢出次数一直在增加,是accept 队列大小不够或者队列中连接等待处理时间太长导致的 。
另外通过ss 命令可以看具体端口的队列占用情况,如下所示:
实战!一次网络问题排查

文章插图
 
image-20200528000349200
Send-Q 这列代表第四列端口上全连接队列的最大值,Recv-Q 代表当前队列有多少个连接,如果长期是满的,代表可以适当增加全连接队列大小了 。
6.5 如何修改accept queue(全连接队列)大小呢?答:accept queue(全连接队列)取决于 min(backlog, somaxconn),backlog是在socket创建的时候传入的,somaxconn是一个os级别的系统参数,somaxconn 定义了系统中每一个端口最大的监听队列的长度, 这是个全局的参数, 默认值为128 。
- 可以通过 echo 1024 >
/proc/sys/net/core/somaxconn 来临时修改somaxconn这个参数;
- 可以在/etc/sysctl.conf 中添加如下 net.core.somaxconn = 1024 然后在终端中执行sysctl -p 让配置永久生效;
对于JAVA后端程序,在创建Socket 时是可以传入参数设置backlog 大小的,很多人可能没关注过这个这个参数,看到很多程序直接使用的默认构造函数创建Socket 的 。

实战!一次网络问题排查

文章插图
 
服务端Socket构造函数
参考自JDK 1.8 文档
如上图所示,在创建Socket 时,可以通过传入backlog 设置全连接队列大小 。如果不传这个参数,默认值是50,Tomcat 默认短连接,这个值默认是100,Nginx默认是511 。
6.6 为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?答:虽然按道理,挥手过程中的四个报文都发送完毕,主动关闭连接的一方应当是可以直接进入CLOSE状态了,但是必须考虑到网络环境是十分复杂且不可靠的,有可以四次挥手最后一个ACK丢失 。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文,假设在Client发送出最后的ACK回复,但该ACK 如果丢失,Server没有收到ACK,Server会重复发送FIN片段 。所以Client不能立即关闭,它必须确认Server接收到了第四次挥手的ACK 。Client会在发送出ACK之后进入到TIME_WAIT状态 。Client会设置一个计时器,等待2MSL的时间 。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL 。这个2MSL是两倍的MSL(Maximum Segment Lifetime) 。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送加上一个回复所需的最大时间 。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接 。
6.7 如果三次握手连接已经建立,但是客户端突然出现故障了怎么办?答:首先,从协议设计角度来讲,客户端如果出现故障,服务端肯定不能一直死等客户端,所以考虑这种情况的存在,TCP 协议中服务端有个计时器,每次收到客户端的响应报文都会重置这个计时器,服务端有个超时时间,通常是2个小时,2个小时没收到客户端的数据,服务端会每隔75秒发送探测报文段,连续10次探测报文没响应,认为客户端出现问题,服务器会关闭这个连接 。一般程序设计者不会依赖这个机制,2个小时实在太长,框架里面都会自己做连接的检查,无效连接的关闭,例如连接池的连接驱逐策略,Apollo等框架的连接保活等 。
作 者:安琪拉的博客
原文链接:
https://mp.weixin.qq.com/s/z9O62VQn75Rhk5vS42AD-Q




推荐阅读