一、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重传的更多相关文章

  1. TCP系列52—拥塞控制—15、前向重传与RACK重传拥塞控制处理对比

    一.概述 这里主要简单分析一个丢包重传并恢复的场景,通过不同的设置让这个相同的场景分别触发RACK重传和前向重传,通过对比说明以下问题: Forward Retransmit可以产生只有重传标记的数据 ...

  2. TCP系列50—拥塞控制—13、Eifel探测下的拥塞撤销

    一.概述 我们之前在SACK关闭场景下的拥塞撤销那篇文章中提到过Eifel探测算法(Eifel Detection Algorithm),最早在介绍DSACK和FRTO的时候我们就有提到过Eifel探 ...

  3. TCP系列45—拥塞控制—8、SACK关闭的拥塞撤销与虚假快速重传

    一.概述 这篇文章介绍一下TCP从Recovery状态恢复到Open状态的时候cwnd的更新.我们在tcp重传部分的文章中曾经介绍过虚假重传的概念,Linux在探测到虚假重传的时候就会执行拥塞撤销操作 ...

  4. TCP系列22—重传—12、Forward Retransmit

    一.概述 forward retransmit相关的内容在RFC6675中有描述,可以参考RFC6675 section 4中NextSeg ()的定义.forward retransmit中文名可以 ...

  5. TCP系列11—重传—1、TCP重传概述

    在最开始介绍TCP的时候,我们就介绍了TCP的三个特点,分别是面向连接.可靠.字节流式.前面内容我们已经介绍过了TCP的连接管理,接下来的这部分内容将会介绍与TCP可靠性强关联的TCP重传. 很多网络 ...

  6. TCP系列24—重传—14、F-RTO虚假重传探测

    一.虚假重传 在一些情况下,TCP可能会在没有数据丢失的情况下初始化一个重传,这种重传就叫做虚假重传(Spurious retransmission).发生虚假重传的原因可能是包传输中重排序.传输中发 ...

  7. TCP系列18—重传—8、FACK及SACK reneging下的重传

    一.介绍 FACK的全称是forward acknowledgement,FACK通过记录SACK块中系列号最大(forward-most)的SACK块来推测丢包信息,在linux中使用fackets ...

  8. TCP系列16—重传—6、基础快速重传(Fast Retransmit)

    一.快速重传介绍 按照TCP协议,RTO超时重传是一个非常重要的事件,当RTO超时的时候,TCP会同时通过两种方式非常谨慎的降低发送数据包的速率,一种是基于拥塞控制削减发送窗口的大小,另外一个是通过指 ...

  9. TCP系列21—重传—11、TLP

    一.介绍 Tail Loss Probe (TLP)是同样是一个发送端算法,主要目的是使用快速重传取代RTO超时重传来处理尾包丢失场景.在一些WEB业务中,如果TCP尾包丢失,如果依靠RTO超时进行重 ...

随机推荐

  1. mysql 主主架构,多入口 互为备份

    ,中小企业很多都是使用mysql主从方案,一主多从,读写分离等,但是单主存在单点故障,从库切换成主库需要作改动.因此,如果是双主或者多主,就会增加mysql入口,增加高可用.不过多主需要考虑自增长ID ...

  2. spark源码编译记录

    spark在项目中已经用了一段时间了,趁现在空闲,下个源码编译在IDEA里面阅读下,特此记录过程. 前提已经安装maven和git 1.上官网下载源码的包: 2.然后解压到一个文件夹 3.编译,编译的 ...

  3. 爬虫-爬虫介绍及Scrapy简介

    在编写案例之前首先理解几个问题,1:什么是爬虫2:为什么说python是门友好的爬虫语言?3:选用哪种框架编写爬虫程序 一:什么是爬虫? 爬虫 webSpider 也称之为网络蜘蛛,是使用一段编写好的 ...

  4. bit_length

    #当十进制用二进制表示时,最少使用的位数 v=2data=v.bit_length()print(data)

  5. 005---Linux文件与目录管理

    文件与目录管理 路径 绝对路径:从根目录开始的路径为绝对路径 ls /home cd /etc 相对路径:从当前路径开始描述为相对路径 cd ../../:.表示当前目录:..表示上级目录 ls ab ...

  6. F. Make It Connected

    题目链接:http://codeforces.com/contest/1095/problem/F 题意:给你n个点,每个点有个权值,如果在两点之间添一条边,代价为两点权值之和.现在给出m个边可以选择 ...

  7. MongoDB入门---文档操作之增删改

    之前的两篇文章,已经分享过关于MongoDB的集合还有数据库的各种操作,接下来就涉及到最主要的喽,那就是数据方面的操作,在这里叫做文档操作.话不多说,大家来看正文.     首先来看一下它的数据结构: ...

  8. BZOJ1029_建筑抢修_KEY

    题目传送门 这是一道贪心的问题. 总体做法是这样的:先按照报废的快慢从小到大SORT一遍,优先修报废快的.同时开一个大根堆(C++的朋友可以用priority_queue),用来记录已经修了的建筑的耗 ...

  9. day 4 __all__ 包 __init__.py

    1.__all__的作用 如果一个文件中有__all__变量,那么也就意味着这个变量中的元素,不会被from xxx import *时导入 __all__ = ["test1", ...

  10. Selenium 入门到精通系列:三

    Selenium 入门到精通系列 PS:Driver_Element 常用方法 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2 ...