性能文章>三次握手四次挥手性能分析>

三次握手四次挥手性能分析原创

2年前
355236

概述

三次握手首要目的是同步序列号。只有同步了序列号才能进行稳定可靠的传输,TCP的特性是依赖序列号实现的,比如流量控制、消息重发,这就是三次握手报文被称为 SYN 的原因,SYN的全称叫做Synchronize Sequence Numbers
性能测试知识库
image.png

第一次握手

客户端向服务器 发送 syn 序列号后进入SYN-SENT状态,此时服务端维护了一个半连接队列: tcp_max_syn_backlog 。半连接队列溢出后,新的连接就会被drop,无法建立新的连接。通过设置 tcp_max_syn_backlog 参数来修改半连接队列。
如果 SYN 半连接队列满了,不一定就非要丢弃。只要开启 tcp_syncookies 参数就可以绕过半连接队列。

  1. 0 表示关闭该功能
  2. 1 表示半连接队列溢出时再启用
  3. 2 表示无条件开启

syncookie 可以用于应对 DDOS攻击(恶意构造大量的 SYN 报文,造成半连接队列溢出,导致客户端的连接无法建立)
性能测试知识库

第二次握手

客户端发出syn之后,等待服务器回复ACK 报文。正常情况下,服务器会在几毫秒内返回 syn+ack,状态变更为syn_rcvd。但如果客户端一直没有收到 syn+ack,则会重发 syn,重试的次数由 tcp_syn_retries 参数控制,默认6 次。第 1 次重试发生在 1 秒钟后,接着以翻倍的方式在第 2、4、8、16、32 秒做 6 次重试,总耗时1+2+4+8+16+32+64=127 秒最后一次重试等待 64 秒,如果仍然没有收到ack,则返回 connection timeout。

第三次握手

客户端接收到服务端syn+ack之后,向服务端发送最终的ack确认。客户端进入Established状态

  1. 此时服务端维护的是全连接队列。全连接队列在(backlog,net.core.somaxconn)之间取最小值,backlog由应用程序传入
  2. 如果服务端没有接收到客户端的最终 ack,服务端会重发 syn+ack。重传次数由tcp_synack_retries 控制
  3. 全连接个数如果超出队列长度,新的全连接就会被 drop。服务端在执行 drop 的时候,可以选择发送 reset 来通知客户端,让客户端不再重发
  4. Client 服务端接收到最终 ack 之后,三次握手完成。Tcp数据包在全连接队列中等待服务调用
  5. echo 3 > /proc/sys/net/ipv4/tcp_fastopen 绕过三次握手

backlog

tomcat里面,backlog叫accept_count
mysql,nginx,redis里面,backlog名字没有变化

net.ipv4.tcp_abort_on_overflow = 0 表示不发送 reset

第一次挥手

image.png

  1. 主动方发送一个 fin报文,主动关闭连接,此时主动方从established进入fin-wait1。

第二次挥手

  1. 被动方接收到fin报文之后,回复ack,连接状态从established变为close_wait,等待进程调用close函数关闭连接
  2. 主动发接收到ack之后,状态会在几十ms内从fin_wait1变为fin_wait2,此时主动方就已经完全关闭连接了
  3. 如果主动方一直收不到对方返回的ack报文,主动方会重发fin报文,重发次数由 tcp_orphan_retries 控制
    性能测试知识库

第三次挥手

  1. 被动方进入 close_wait状态时,read 函数返回 0。
  2. 被动方的应用程序通过read函数来判断对方已经发送关闭,然后调用close()函数,进而触发内核发送 fin 报文,此时被动方的状态变为 last_ack。
    性能测试知识库

close_wait异常

  1. 被动方应用程序没有调用close关闭连接,也就不会发出FIN 包,进而导致tcp状态全部堆积在close_wait
  2. 客户端提交或回滚事务时,没有关闭(即没发送fin)与数据库的连接,导致数据库因为连接超时而主动关闭(现在变成了数据库主动发送fin了)。此时,原先的客户端就会出现大量close_wait状态连接堆积
  3. 应用程序响应慢:应用程序不能及时响应主动方的关闭请求或者来不及判断read()函数,也会导致close_wait堆积

第四次挥手

主动方收到fin 报文之后回复ack,同时连接的状态由fin_wait2 变为 time_wait,系统默认大约60s后time_wait状态的连接才会彻底关闭。被动方收到 ACK 报文后,连接就会关闭。
Timewait 时间过长或者总数过多,会导致大量的端口被占用,新的连接无法建立。因此需要做几手处理
设置 net.ipv4.tcp_max_tw_buckets,控制 timewait 总数
设置 net.ipv4.tcp_tw_reuse = 1,开启端口复用
设置 net.ipv4.ip_local_port_range,扩大端口范围
image.png

image.png

点赞收藏
飞天小子

13软件测试,10年性能测试,5年性能培训,10万字性能博主,项目经理,微信uhz2008

请先登录,查看3条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

服务器之 ECC 内存的工作原理

服务器之 ECC 内存的工作原理

从 Linux 内核角度探秘 JDK MappedByteBuffer

从 Linux 内核角度探秘 JDK MappedByteBuffer

日常Bug排查-连接突然全部关闭

日常Bug排查-连接突然全部关闭

6
3