排查基础思路:
- tsar -i 1 --live 查看当前 TCP 重传率情况 tcp/retran 这一列。
- 知识点:
- TCP 重传率是 tcp 重传的报文数/总共发出去的报文数
- 在请求很少的情况下,可能是个别波动导致的;请求多的情况下,可能是大面积网络问题导致
- ss -anti | grep -B 1 retrans 这个命令可以过滤到哪些连接出现了重传。
- 根据 [3] 找到比较严重的连接后,用 tcpdump -i any "host xxx" 实际抓包看下情况,一般可能是对端没响应 ACK 导致重传。
- 其他根据实际情况可以再具体分析。
背景知识:
拥塞控制窗口:
发送端发送数据的发送窗口SWND通常是min(CWND,RWND),其中RWND是接收方接受队列中可容纳数据的大小,CWND则表示当前网络上能够在不发生拥塞的情况下能够容纳的数据大小。CWND的变化由TCP的拥塞控制状态机控制,变动的规则如下:
- TCP_CA_Open 连接建立是的初始状态,在这个状态下CWND根据是否触达慢启动的阈值来缓慢增加。
- TCP_CA_Disorder 当收到DACK或者SACK是,说明接收端收到了乱序的报文,此时转变为TCP_CA_Disorder状态,CWND不再变化,即每收到一个包,就会发送一个包。
- TCP_CA_CWR 当出现网络拥塞时,会进入TCP_CA_CWR状态,例如,收到一个ECE标记的TCP ECN首部时,是接收方显示通知发送方出现了拥塞,此时会进入TCP_CA_CWR状态。在这个状态下,CWND会有序减少。
- TCP_CA_Recovery TCP在收到连续三个相同的ACK后会进入tcp_fastretrans_alert逻辑,然后开始快速重传,在这个过程中,会把sock设置为TCP_CA_Recovery状态,直到快速重传的所有报文都被确认后回到TCP_CA_Open,在TCP_CA_Recovery状态下,CWND会每隔两个ACK报文减少一次,与TCP_CA_CWR表现一致。
- TCP_CA_Loss 当出现RTO超时,进入TCP_CA_Loss状态,会打断其他状态,此时会将CWND设置为一个MSS,即只有之前发送的报文全都被确认才会继续开始慢启动的窗口恢复。
RTO/PTO/RACK/Window Probe定时器:
可以看到TCP中与发送数据相关的,默认支持的定时器事件有4种,分别是:
- RACK(Recent ACKnowledgment),收到ack报文时,对比ack报文确认的报文的发送时间,来判定是否有仍为收到ack确认的报文出现了丢包,例如本地按照事件顺序发送了1,2,3三个数据包,在RTO时间内收到了2的ack确认报文,则认为1已经丢失了,RACK能够利用重传报文的ack数据包进行丢包的判定,比起传统的只依靠序列号来进行判定的方式提升了效率。
- send_loss,即Probe Timeout,当发送了当前缓冲区中的最后一个可以发送的报文时,如果长时间未发送报文,则会导致长时间无法收到ack,这样会导致未确认的报文无法触发sack等快速重传的机器来避免触发RTO,为了解决这个问题,Linux引入了TLP算法,即在最后一个正常的数据包发送之后,如果经过PTO的时间没有数据发送,则会发送当前序号最大的一个数据包。
- retransmit_timer,即重传定时器,当有数据包发送时,内核会复制一份数据包进入重传队列,如果经过RTO的超时时间依然没有被ack,则认为已经丢包,进行重传操作。
- window probe,这个定时器主要的目的是为了解决在双方都没有数据包的长连接情况下的窗口探测问题,当定时器触发时,会发送一个窗口为0的报文,用于查询窗口是否增大。