TCP系列23—重传—13、RACK重传
一、RACK概述
RACK(Recent ACKnowledgment)是一种新的基于时间的丢包探测算法,RACK的目的是取代传统的基于dupthresh门限的各种快速重传及其变种。前面介绍的各种基于dup ACK的快速重传算法及其变种通过修改dupthresh门限等手段,有些可以迅速的探测到丢包,有些可以精确的探测丢包,但是没有能同时达到迅速和精确两个目标的算法。
RACK基本思想:如果发送端收到的确认包中的SACK选项确认收到了一个数据包,那么在这个数据包之前发送的数据包要么是在传输过程中发生了乱序,要么是发生了丢包。RACK使用最近投递成功的数据包的发送时刻来推测在这个数据包之前传输的数据包是否已经过期(expired),RACK把这些过期的数据包标记为lost。RACK可以修复丢包而不用等一个比较长的RTO超时,RACK可以用于快速恢复也可以用于超时恢复(快速恢复和超时恢复我们会在拥塞控制阶段详细讲解),既可以利用初传的数据包探测丢包也可以利用重传的数据包探测丢包,而且可以探测初传丢包也可以探测重传丢包,因此RACK是一个适应多种场景的丢包恢复机制。
在现今的网络环境中乱序传输是一个比较常见的场景,使用dupthresh和dup ACK来做丢包探测的可靠性越来越低。同时因为传统的基于系列号空间的乱序度来探测丢包时,如果发生报文重传,初传报文和重传报文在系列号空间就会重叠。而RACK基于时间的乱序来探测丢包的时候,重传报文和初传报文在时间线上是不重叠的,因此RACK可以同时利用初传报文和重传报文来探测丢包。
RACK使用的需要三个条件:
1、TCP连接必须使用SACK选项
2、对于每个发送的数据包,发送端必须存储这个数据包的发送时间,时间精度至少要达到毫秒精度。如果连接的RTT小于1ms,那么微秒精度将会更有利于RACK探测丢包。
3、对于每个发送出去的数据包,发送端必须存储这个数据包是否已经重传过。
二、RACK算法描述
RACK目前还是一个实验算法,RACK需要使用到的几个状态变量:
Packet.xmit_ts:数据包上次传输所对应的时间,如果是重传也需要记录这个时间。发送端需要对每个数据包都记录这个时间,且时间精度至少是毫秒
RACK.xmit_ts:在所有被ack number或者SACK确认的数据包中,最近发送的数据包的Packet.xmit_ts
RACK.end_seq:上面用于记录RACK.xmit_ts的数据包的终止系列号
RACK.RTT:上面用于记录RACK.xmit_ts的数据包对应的RTT
RACK.reo_wnd:表示这个TCP连接的时间乱序度,这个变量的单位是时间。RACK使用这个变量来推测丢包
RACK.min_RTT:估计的这个连接的最小RTT
注意这些变量的粒度,每个数据包都有一个Packet.xmit_ts变量,每个TCP连接维护一组RACK.xmit_ts, RACK.RTT, RACK.reo_wnd和RACK.min_RTT变量
算法实现:
1、当传输一个新的数据包或者重传一个旧的数据包的时候,把当前时间记录在与这个数据包对应的Packet.xmit_ts变量中。
2、当接收到一个ACK的时候
Step2.1:根据测量到的RTT更新RACK.min_RTT。
发送端可以使用这个连接的全局最小RTT来维护RACK.min_RTT,也可以使用一个每发送窗口最小RTT的滤波值来维护RACK.min_RTT。
Step2.2:更新RACK.reo_wnd。RACK.reo_wnd默认值为1ms,当探测到包乱序的时候可以设置RACK.reo_wnd=RACK.min_RTT/4
Step2.3:更新RACK.xmit_ts、RACK.RTT 和 RACK.end_seq。
首先在这个ACK新确认的数据包(包括通过ack number和SACK确认的数据包)中排除下面两类重传数据包
1、如果这个数据包中的TSecr指示这个确认包并不是确认的重传数据包。这个实际上是Eifel探测算法,后面我们会进行详细介绍。
2、这个数据包上次重传时间距离当前时间小于RACK.min_rtt。这个也意味着这个数据包多半是虚假重传。
接着在剩余的新确认的数据包中找出最近发送的数据包的Packet.xmit_ts,如果Packet.xmit_ts比RACK.xmit_ts在时间上更靠后,那么更新RACK.xmit_ts = Packet.xmit_ts。如果RACK.xmit_ts发生了更新,那么更新RACK.RTT = Now() - RACK.xmit_ts,RACK.end_seq = Packet.end_seq。如果RACK.xmit_ts没有更新,那么退出针对这个确认包的RACK处理流程,不再执行下面的丢包探测过程。
Step2.4:丢包探测
对于每个还没有被SACK完全确认的数据包,如果在时间上RACK.xmit_ts比Packet.xmit_ts + RACK.reo_wnd更靠后,说明这个数据包已经超过预计的时间乱序度,标记这个数据包为lost状态。另外对于未被标记为lost的数据包,发送端可以等待下次收到ACK确认包的时候再次进行RACK标记处理,也可以设置一个"reordering settling"定时器,以待定时器超时的时候把这个数据包标记为lost。设置定时器的方法可以防止大量丢包或者应用层发送数据受限而造成RTO超时。定时器的超时时间协议给出的是timeout = Packet.xmit_ts + RACK.RTT + RACK.reo_wnd + 1。
这里值得一提的是,RACK功能可以很好的与TLP功能配合,因为RACK可以使用重传包来探测丢包,因此TLP其实可以发送第一个未被确认的数据包来进行丢包探测,这样就可以应用层传输时延。
三、linux实现简介
目前linux中RACK功能受到/proc/sys/net/ipv4/tcp_recovery参数控制,tcp_recovery是一个比特开关,其中0x1比特位控制是否使能RACK,该比特位有效的时候,则打开RACK功能,默认值为0x1,即linux中默认打开RACK功能。
另外就是linux并没有实现"reordering settling"定时器功能。linux中RACK其余处理基于与上面描述的一致了。
目前RFC草案中只说RACK可以在快速恢复和RTO超时恢复阶段使用,我们这里重点关注RACK丢包探测的机制,关于快速恢复和超时恢复,我们后面介绍拥塞控制的时候会在进行详细介绍,同时会再次回顾RACK的相关内容。
四、wireshark示例
我们先简单的看一个示例来理解RACK重传,后面介绍完拥塞控制的时候,会再次引入其他的RACK示例
1、RACK重传基础示例
在进行测试之前我们设置tcp_timestamps=0以关闭TCP的时间戳选项,用来说明RACK虽然是基于时间的丢包探测,但是并不依赖TSopt选项。当然这里打开这个TSopt这个选项也是可以的,只不过为了场景正交,因此这里演示关闭TSopt时候RACK一样可以正常处理。
业务场景:client与server端建立连接后,server端连续发送8个数据包,即No4-No11。其中只有No4和No11成功传输到接收端,中间的6个数据包(我手动设置了高亮显示)都丢失了。其中client与server端的RTT大约稳定在50ms左右。
No1-No3:通过三次握手建立连接,其中TSopt选项未协商成功
No4-No11:server端大约以3ms为间隔,连续发送了8个数据包,其中No5-No10高亮的这6个数据包丢失
No12:client回复对应No4的ACK确认包
No13:client回复对应No12的ACK确认包,通过SACK确认了No11,server端收到这个数据包的时候,更新fackets_out=7,此时dupthresh=3, fackets_out-dupthresh=4, 因此server端把No5、No6、No7、No8数据包标记为lost。
No14:server端先把No5数据包重传出去,对应No14,受限于拥塞控制,其余被标记为lost的数据包暂时还不能进行重传。
No15:No15通过ack number确认了No14这个重传包。server端更新 RACK.xmit_ts=No14的Packet.xmit_ts≈0.072604us,因为目前linux还没有检测到乱序传输(即dupthresh还没有更新),因此RACK.reo_wnd=1000us,此时server端会把RACK.xmit_ts-RACK.reo_wnd≈0.071604us时间点之前发送的数据包都标记为lost。即No9和No10也会被server端标记为lost。
No16-No29:接着在拥塞控制的限制下,对标记为lost的数据包进行重传操作,并在最终数据包传输完毕后关闭这个TCP连接。
补充说明:
1、https://datatracker.ietf.org/doc/draft-ietf-tcpm-rack/?include_text=1
2、https://www.ietf.org/proceedings/94/slides/slides-94-tcpm-6.pdf
TCP系列23—重传—13、RACK重传的更多相关文章
- TCP系列52—拥塞控制—15、前向重传与RACK重传拥塞控制处理对比
一.概述 这里主要简单分析一个丢包重传并恢复的场景,通过不同的设置让这个相同的场景分别触发RACK重传和前向重传,通过对比说明以下问题: Forward Retransmit可以产生只有重传标记的数据 ...
- TCP系列50—拥塞控制—13、Eifel探测下的拥塞撤销
一.概述 我们之前在SACK关闭场景下的拥塞撤销那篇文章中提到过Eifel探测算法(Eifel Detection Algorithm),最早在介绍DSACK和FRTO的时候我们就有提到过Eifel探 ...
- TCP系列45—拥塞控制—8、SACK关闭的拥塞撤销与虚假快速重传
一.概述 这篇文章介绍一下TCP从Recovery状态恢复到Open状态的时候cwnd的更新.我们在tcp重传部分的文章中曾经介绍过虚假重传的概念,Linux在探测到虚假重传的时候就会执行拥塞撤销操作 ...
- TCP系列22—重传—12、Forward Retransmit
一.概述 forward retransmit相关的内容在RFC6675中有描述,可以参考RFC6675 section 4中NextSeg ()的定义.forward retransmit中文名可以 ...
- TCP系列11—重传—1、TCP重传概述
在最开始介绍TCP的时候,我们就介绍了TCP的三个特点,分别是面向连接.可靠.字节流式.前面内容我们已经介绍过了TCP的连接管理,接下来的这部分内容将会介绍与TCP可靠性强关联的TCP重传. 很多网络 ...
- TCP系列24—重传—14、F-RTO虚假重传探测
一.虚假重传 在一些情况下,TCP可能会在没有数据丢失的情况下初始化一个重传,这种重传就叫做虚假重传(Spurious retransmission).发生虚假重传的原因可能是包传输中重排序.传输中发 ...
- TCP系列18—重传—8、FACK及SACK reneging下的重传
一.介绍 FACK的全称是forward acknowledgement,FACK通过记录SACK块中系列号最大(forward-most)的SACK块来推测丢包信息,在linux中使用fackets ...
- TCP系列16—重传—6、基础快速重传(Fast Retransmit)
一.快速重传介绍 按照TCP协议,RTO超时重传是一个非常重要的事件,当RTO超时的时候,TCP会同时通过两种方式非常谨慎的降低发送数据包的速率,一种是基于拥塞控制削减发送窗口的大小,另外一个是通过指 ...
- TCP系列21—重传—11、TLP
一.介绍 Tail Loss Probe (TLP)是同样是一个发送端算法,主要目的是使用快速重传取代RTO超时重传来处理尾包丢失场景.在一些WEB业务中,如果TCP尾包丢失,如果依靠RTO超时进行重 ...
随机推荐
- 帝国cms教程父栏目和子栏目都能在当前栏目高亮
首先在/e/class/userfun.php这个文件里面加上下面代码.上面父栏目的,下面子栏目的.红色代表css样式.自定义吧 function currentPage($classid,$this ...
- sublime text 3安装 package control 插件的方法
自动安装的方法 - 快捷键ctrl+` 或者View->Show Console,输入如下代码 import urllib.request,os;pf='Package Control.sub ...
- python网络编程之线程
一 .背景知识 1.进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别就在于:程序是指令 ...
- python爬xx图代码
今日 好热,照样是挖洞挖不到,看了几天的python爬虫,学会了xpath解析 撸一个代码玩玩] 不要说什么,优化之类的,刚学完,跑了一阵 ,还可以 挺稳定 # -*- coding:utf-8 - ...
- C语言链接属性总结
1.什么是链接属性? 当组成一个程序的各个源文件分别被编译后,所有的目标文件以及那些从一个或多个函数库中引用的函数链接在一起,形成可执行程序. 标识符的链接属性决定如何处理在不同文件中出现的标识符 ...
- 20145209刘一阳 《网络对抗》逆向及BOF基础实践
直接修改程序机器指令,改变程序执行流程 在正式开始实践之前,先对pwn1文件做个备份,以便修改后可以及时恢复到初始状态: 使用指令objdump -d 20145209 | more对目标文件进行反汇 ...
- POJ3259_Wormholes_KEY
题目传送门 题目大意:有F组数据,N表示有N点,M表示有M条边,走一遍边需要花费Ti个时间,还有W个虫洞,可以向前回溯Ti时间,求能否从1点出发,经过一些路或虫洞回到1点后时间为负. 建图后用SPFA ...
- day 6 敌机
1.显示敌机 #-*- coding:utf-8 -*- import pygame import time from pygame.locals import * class HeroPlane(o ...
- php输出带尖括号的内容
有这样的数组 $arr = array( 'facebook' => 'facebook', '<facebook>' => '<facebook>', ); 输出 ...
- Python常见的脚本汇总
1.冒泡排序 lis = [56,12,1,8,354,10,100,34,56,7,23,456,234,-58] def sortport(): for i in range(len(lis)-1 ...