tcpip拥塞控制、重传、丢包、优化
弱⽹环境是丢包率较⾼的特殊场景,TCP 在类似场景中的表现很差,当 RTT 为 30ms 时,⼀旦丢包率达到了 2%,TCP 的吞吐量就会下降89.9%[3],从下⾯的表中我们可以看出丢包对 TCP 的吞吐量极其显著的影响:
概念理解
4种计时器
1.重传计时器:Retransmission Timer A发报⽂时创建计时器,计时器到期内收到回报⽂ACK,就撤销计时器
2.持久计时器:Persistent Timer B告诉A,接收窗⼝填满了(0窗⼝通报),告诉A停⽌发送,进⼊等待,直到B发送报⽂告诉A已有“⾮零窗⼝”,但此时若这个报⽂丢失,B⾃⼰不知道,等着A发数据过来,双⽅都进⼊等待死锁,解决这个问题要在A端创建持久计时器,当收到B发送过来的0窗⼝通报报⽂后,计时器启动,计时器过期后,A发⼀个探测报⽂给B,询问是否有⾮0窗⼝,如果超时还没ack恢复则发探查报⽂,如果超时前收到到ack回复依然是0窗⼝,则将计时器复位并且翻倍时间值(1,2,4,8最⼤60s),如此循环,直到收到B的重开窗⼝确认包。
3.保活计时器:Keeplive Timer 长连接中A发送数据给B,发送⼏个数据包之后,A出故障了,B等待2⼩时后发10个探测报⽂段(每个75分钟发⼀次),如果没有响应就终⽌连接
4.时间等待计时器:Timer_Wait Timer time_wati状态下发出的给被关闭端ack报⽂后等待时间(30~120s),⼀般设置⼀个msl(最长报⽂寿命)是60s
包重传的原因
tcp可靠性通过序列号和ack确认包保障,当tcp发送包之后,将这个包的副本数据段放到重传队列上启动重传计时器
1、如果对⽅反馈ack,则销毁数据段和计时器
2、如果对⽅没有反馈ack,则在计时器到期后发起重传
快速重传:A向B发送4个tcp报⽂段(n1,n2,n3,n4),B只收到(n1,n2,n4),其中n3丢失(也许只是延时到达),B发现失序⽴即⽣成重复ACK包(重复确认n3),且发送三次给A,A重传该数据包
超时重传:定时器超时之后,重传包,计时器的时间为“⼤于平均往返延迟”
伪超时和重传:过早的判断了超时时间,导致发送⽅触发重传,RTT(连接往返时间)增长超过RTO(重传超时时间)
包失序:ip层的包没有按顺序传输,严重失序时,接收⽅误以为包丢失,通知发送端重传,需要设置合理的重传阀值解决
包重复:重传包含⼀个数据包,以及两个副本,多次重复会导致B收到过多重复包,从⽽B⽣成重复的ack,容易触发伪快速重传,使⽤sack 避免
sack:当出现包失序、⽹络丢包导致的接收⽅数据序队列出现空洞,sack选项可以提供确认信息(描述乱序、空洞),帮助A⽅有效的重传。
拥塞控制
作⽤1:防⽌A向B发送过多数据,导致B⽆法处理
作⽤2:防⽌tcp任意连接的⼀⽅向⽹络发送⼤量数据,导致⽹络拥塞崩溃
拥塞窗⼝⼤⼩(cwnd),双⽅的接收窗⼝⼤⼩(rwnd)
tcp三次握⼿中双⽅通过ack交换接收窗⼝⼤⼩,rwnd有带宽延迟乘积决定
客户端能同时传输的最⼤数据段的数量值就是 cwnd和接收⽅rwnd的最⼩值min(cwnd,rwnd),在linux中为tcp_init_cwnd10,就是10个
tcp传输中A的拥塞窗⼝⼤⼩根据B的响应进⾏调整
1、线性增长:经过⼀个RTT,拥塞窗⼝⼤⼩会加⼀(是不是慢启动)
2、积式减少:发送⽅发送的数据丢包的时候,拥塞控制阀值会减半
例如默认linux,A同时能发10个数据段,我们⽹络是10M,RTT是40ms,每个数据段1460字节,根据BDP(带宽延迟积)计算,双⽅窗⼝⼤⼩上限35
a>b 10段 0.5RTT
a<b 0.5RTT
a>b 10段+10 0.5RTT 经过⼀次rtt,窗⼝段数加倍
a<b 0.5RTTtcpip协议栈中的协议主要定义
a>b 20段+20 0.5RTT 经过⼆次rtt,窗⼝段数加倍
第三次开始(3.5RTT)窗⼝数稳定在上限35,需要140ms时间
三次握⼿就是1.5RTT
弱⽹环境下(丢包率⾼)导致 TCP 性能问题的三个重要原因:
TCP 的拥塞控制在发⽣丢包时会进⾏退让,减少能够发送的数据段数量,但是丢包并不⼀定意味着⽹络拥塞,更多的可能是⽹络状况较差;
TCP 的三次握⼿带来了额外开销,这些开销不只包括需要传输更多的数据,还增加了⾸次传输数据的⽹络延迟;
TCP 的重传机制在数据包丢失时可能会重新传输已经成功接收的数据段,造成带宽的浪费;
优化
了解接收数据库包的流程
1、⽹卡收到数据包
2、将数据包从⽹卡硬件缓存转移到服务器内存中。
3、通知内核处理
4、经过icp/ip协议逐层处理
5、应⽤程序通过read()从socket buffer读取数据
⽹卡接收数据包转移到主机内存
1、驱动在内存创建⼀块缓冲区(sk_buffer)
2、驱动将这个缓冲区的地址、⼤⼩信息(即接收描述符)加⼊到rx_ring_buffer。缓冲区地址是DMA使⽤的物理地址
3、驱动通知⽹卡有个新描述符
4、⽹卡从rx_ring_buffer取出描述符,得知缓冲区地址和⼤⼩
5、⽹卡将数据包通过DMA直接写到sk_buffer
⽹卡丢包原因1
驱动处理速度跟不上⽹卡接收包速度,驱动来不及分配缓冲区,⽹卡的数据⽆法实时写到sk_buffer,导致⽹卡内存缓冲区写满,开始丢弃部分数据,引起丢包。这部分丢包为rx_fifo_errors,在/proc/net/dev 中体现为filo 字段增长,在ifconfig 中体现为overruns指标增长。
⽹卡发起硬中断通知内核处理
硬中断:由硬件⾃⼰⽣产,具有随机性,硬中断被cpu接收后,触发执⾏中断处理程序,中断程⼒程序只会处理关键性、短时间内可完成的⼯作,剩余耗时交给软中断完成。(上半部分)
软中断:由硬中断对应的中断处理程序⽣成,⼀般是代码内实现好的,不具随机性。(下半部分)
数据被⽹卡通过DMA写到sk_buffer,⽹卡⽴即发起⼀个硬中断。cpu接收后,⾸先进⼊上半部分,cpu中断处理后,由⽹卡驱动程序发起软中断处理,进⼊下半部分,软中断处理程序开始消费sk_buffer 中的数据,交给内核协议栈处理。
通过中断,能够快速响应⽹卡数据请求,但是如果数量⼤,硬中断过多,导致cpu⼤量时间处理中断,效率降低。解决⽅案是内核、驱动采⽤NAP(new api)进⾏处理数据,即轮询+中断,数据量⼤时,⼀次硬中断后通过轮询接收⼀定数量数据包才后返回,减少硬中断导致的效率降低。
ifconfig 下重点字段意思
RX errors 总的收包的错误数量,包含 too-long-frames 错误,Ring Buffer 溢出错误,crc 校验错误,帧同步错误,fifo overruns 以及 missed pkg 等等
RX dropped 表⽰数据包已经进⼊了⽹卡的接收缓存fifo队列 Ring Buffer,并且开始被系统中断处理准备进⾏数据包拷贝(从⽹卡缓存fifo队列拷贝到系统内存),但由于此时的系统原因(⽐如内存不够等)导致这个数据包被丢掉,即这个数据包被Linux系统丢掉。
RX overruns 表⽰了 fifo 的 overruns,这是由于 Ring Buffer(aka Driver Queue) 传输的 IO ⼤于 kernel 能够处理的 IO 导致的,⽽ Ring Buffer 则是指在发起 IRQ 中断请求之前的那块 buffer。表⽰这个数据包还没有被进⼊到⽹卡的接收缓存fifo队列就被丢掉,因此此时⽹卡的fifo是满的。为什么fifo会是满的?因为系统繁忙,来不及响应⽹卡中断,导致⽹卡⾥的数据包没有及时的拷贝到系统内存,fifo是满的就导致后⾯的数据包进不来,即这个数据包被⽹卡硬件丢掉。所以,个⼈觉得遇到overruns⾮0,需要检测cpu负载与cpu中断情况。很明显,overruns 的增⼤意味着数据包没到 Ring Buffer 就被⽹卡物理层给丢弃了,⽽ CPU ⽆法及时的处理中断是造成 Ring Buffer 满的原因之⼀,这样就会导致因为 interruprs 分布的不均匀 (都压在 core0),没有做 affinity ⽽造成的丢包。
RX frame 表⽰ misaligned 的 frames。
error是出现了⽹络错误,dropped是出现了格式不正确被丢弃的包,overruns 驱动缓冲不⾜或者⽹络中
断处理不及时导致的缓冲溢出的数量
丢包排查思路
⽹卡⼯作在数据链路层,数据量链路层,会做⼀些校验,封装成帧。我们可以查看校验是否出错,确定传输是否存在问题。然后从软件层⾯,是否因为缓冲区太⼩丢包。
物理硬件⽅⾯
查看⼯作模式是否正常
ethtool eth0 | egrep 'Speed|Duplex'查看检验是否正常
ethtool -S eth0 | grep crc
软件层⾯overruns 和 buffer size ethtool -g eth0
ethtool -G eth0 rx 2048
ethtool -G eth0 tx 2048
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论