正常的三次握手情况如下

image-ehyu.png

问题

1、服务,CPU消耗从15%消耗突增到了80%,问题在哪

问题背景:线上一直4核单需要支持2000QPS一直无异常,CPU利用率维持在15%左右。但是在某次上线后,每次请求增加一次redis访问,线上CPU利用率飙升至80%。

请看命令

问题出现在connect选择端口的过程中

由于底层是遍历查找

如果内核现在只剩下一个端口可用的情况下,每次的遍历查找消耗就会极大。同时内核为了防止多进程选择端口冲突,会进行加锁。这个两个原因造成性能问题。

2、偶发的线上访问耗时,该如何排查和处理

详情参考队列溢出导致的超时问题

connect可能发生的问题

1、服务端,connect过程由于底层是遍历查找

image-a1jb.png

如果内核现在只剩下一个端口可用的情况下,每次的遍历查找消耗就会极大。同时内核为了防止多进程选择端口冲突,会进行加锁。这两个原因可能造成性能上的突发问题。

队列溢出可能会导致超时问题

客户端connect包发出时会启动一个重传定时器,用做重试机制

现在我们将视角转换到服务端

如果服务端的连接队列已经满了,那么对于connect的请求就会丢弃,从而造成客户端进行重试,用户体验上就是页面的显示就给人一种网络不好,十分卡顿的现象。

客户端在1S以后进行了第一次握手重试,接下来又在3,7,15,31,63S等时间共重试6次(这个重试了多少次要看具体的tcp_syn_retries设置的值为多少)

所以加入服务器上出现了半/全连接队列溢出导致的丢包问题,那接口的响应至少时1S以上

三次握手相关的优化方法

➤ 如果请求频繁,请弃用短连接改用长连接

➤ 如果可能,尽量合并请求!

➤ 客户端注意 ip_local_port_range 要够用

➤ 客户端连接不同的服务端

➤ 打开 SYN cookie 避免半连接队列溢出

➤ 服务端通过 backlog 和 net.core.somaxconn 控制合适的连接队列长度

➤ 服务端应该尽快 accept 让应用取走连接

参考资料