tcp 的 tlp, er 和 rack

tcp 协议曾引入过很多碎点,因此拧巴复杂,今天简单说两个,tlp(tail loss probe) 和 er(early retransmit)。

tlp 考虑的是怕发出去的报文太少或尾丢,没有足够的 ack/sack 数量足以触发快速重传,这种情况下需要主动发送一个报文(新的或旧的)以期待 receiver 回复的 ack 中携带足够的 sack 段触发快速重传。

而 er 考虑的是即使在发出的报文反馈的 ack/sack 不足以触发快速重传时,也不用怕,放宽约束即可在不足 3 个重复确认时触发快速重传。(3 个 dupack 中的 3 涉及到 reordering,但这是另一个话题,以前说过,不再赘述)

一般而言 tlp 和 er 一起使用,让这些特性显得复杂的一逼,如果看代码的话,一层层缩进的 if 混杂着一坨坨屎一样的 &&,& 和 || 就更让人绝望了。

细节中还有细节的细节,tlp 发新数据还是旧数据,若不明白 tlp 的初衷是希望 receiver 反馈 sack block 触发快速重传,很难理解发什么以及发多少的决策,其实发任意 byte 即可,考虑到捎带的有效性,优先发送新数据。

tlp 的 probe 报文大概率也带不回足量的 sack block,否则早就带回了,也不必触发 tlp 就开始快速重传了,所以如果一个 probe 仅仅带回了有但不足的 sack block,er 便接力,让 sender 在松约束下立即开始快速重传。

如果你花了很长时间来 "牢记" 相关 rfc 的约定和代码实现的 trick,并且你真的做到了,你甚至总结出一些非常容易记忆的 1,2,3,4,你也不必因此而感动,因为这些都不是核心本质,这只让 tcp 的形象越来越拧巴。

仔细看 tlp,er 这一坨坨的规定,很容易发现问题的核心在 "3 次 dupack 才能触发快速重传"。所以为了在一些不太易的场景(比如 thin 管道,尾丢)下迎合和满足触发快速重传的条件,不至于跌入 rto,tlp 和 er 才被设计出来,条件苛刻,代码凌乱。

所以你看,tcp 说在长肥管道下有问题,那么在短瘦管道下岂不是也有问题,tlp,er 就是为此而生的。

我常说,tcp 的代码写得像坨屎不是程序员的问题,而是 tcp 的代码根本就写不好,tcp 的特性是一点点小问题的解决 trick 逐渐像贴胶布一样贴出来的,换谁上也写不好看,这个和 openssl 还不一样。即使不说代码,你去看 rfc 也不好看。

rack 似乎是福音,因为它直接解除了 "3 次 dupack 才能触发快速重传" 这个条件,每当有人咨询我重传的问题时,我都会说你去看 rack 好了。

看 rack 之前的快速重传条件:

c 复制代码
static bool tcp_time_to_recover(struct sock *sk, int flag)
{
        struct tcp_sock *tp = tcp_sk(sk);
        __u32 packets_out;

        /* Trick#1: The loss is proven. */
        if (tp->lost_out)
                return true;

        /* Not-A-Trick#2 : Classic rule... */
        if (tcp_dupack_heuristics(tp) > tp->reordering)
                return true;

        /* Trick#4: It is still not OK... But will it be useful to delay
         * recovery more?
         */
        packets_out = tp->packets_out;
        if (packets_out <= tp->reordering &&
            tp->sacked_out >= max_t(__u32, packets_out/2, sysctl_tcp_reordering) &&
            !tcp_may_send_now(sk)) {
                /* We have nothing to send. This connection is limited
                 * either by receiver window or by application.
                 */
                return true;
        }

        /* If a thin stream is detected, retransmit after first
         * received dupack. Employ only if SACK is supported in order
         * to avoid possible corner-case series of spurious retransmissions
         * Use only if there are no unsent data.
         */
        if ((tp->thin_dupack || sysctl_tcp_thin_dupack) &&
            tcp_stream_is_thin(tp) && tcp_dupack_heuristics(tp) > 1 &&
            tcp_is_sack(tp) && !tcp_send_head(sk))
                return true;

        /* Trick#6: TCP early retransmit, per RFC5827.  To avoid spurious
         * retransmissions due to small network reorderings, we implement
         * Mitigation A.3 in the RFC and delay the retransmission for a short
         * interval if appropriate.
         */
        if (tp->do_early_retrans && !tp->retrans_out && tp->sacked_out &&
            (tp->packets_out >= (tp->sacked_out + 1) && tp->packets_out < 4) &&
            !tcp_may_send_now(sk))
                return !tcp_pause_early_retransmit(sk, flag);

        return false;
}

再看下 rack 后的:

c 复制代码
static bool tcp_time_to_recover(struct sock *sk, int flag)
{
        struct tcp_sock *tp = tcp_sk(sk);

        /* Trick#1: The loss is proven. */
        if (tp->lost_out)
                return true;

        /* Not-A-Trick#2 : Classic rule... */
        if (!tcp_is_rack(sk) && tcp_dupack_heuristics(tp) > tp->reordering)
                return true;

        return false;
}

很多逻辑都收入 rack 逻辑了,这就清爽了许多。

rack 是一个非常自然的丢包探测方案,包括我自己在内的传输圈子内部早在 2013 年之前就都自行设计出了时间序探测算法,后来看了 tlp 和 er 反而有点懵,因为它们是为不合理打补丁,而不是为问题提供方案。

本质上,rack 在跟踪时间序中的传输行为,它跟踪的正是时间戳本身,"更晚传输的报文 p 已经被确认,在 p 之前更早传输的未确认报文 pj 视为丢失",为了给乱序保留余地,rack 保留了一个乱序时间窗口 d,在标记并重传一个 pj 之前会等待一小段时间。乱序时间窗口 d 自然也不必像 reordering 个 dupack 触发 fr 时那般复杂拧巴,根据 "乱序是路径属性而不是协议属性",d 被限制在 minrtt / 4 到 srtt 之间,完全取消了复杂的乱序度的计算。这就把 rack 全部看懂了。

但同样也是时间序,很多人不明白 tcp 的 rto 为什么不能直接是 rtt,至多加上一个不太大的余量,这很合理,超过 rtt + 小余量 的时间收不到 ack,报文就算丢了,但当获得了更官方的解释后,捎带 ack,delay ack,各平台相异的实现等一大坨一大坨的东西就全搅和进来成一锅粥了。

rack 在标记一个报文丢失时与 rto 估算不同,rack 不需要估算,它用一个 recent ack 做参照,人家都被确认了,你们更早发送的有什么理由不被确认,那就是丢了呗。你看,有了 recent ack 参照就不需要再考虑那一坨坨的污秽逻辑了。

最后看一下 rack-tlp,来自 rfc8985,一张图,不说话:

浙江温州皮鞋湿,下雨进水不会胖。

相关推荐
易连EDI—EasyLink2 小时前
易连EDI–EasyLink实现OCR智能数据采集
网络·人工智能·安全·汽车·ocr·edi
@insist1232 小时前
信息安全工程师考点精讲:身份认证核心原理与分类体系(上篇)
大数据·网络·分类·信息安全工程师·软件水平考试
SmartRadio2 小时前
ESP32-S3 双模式切换实现:兼顾手机_路由器连接与WiFi长距离通信
开发语言·网络·智能手机·esp32·长距离wifi
_.Switch3 小时前
东方财富股票数据JS逆向:secids字段和AES加密实战
开发语言·前端·javascript·网络·爬虫·python·ecmascript
金色光环4 小时前
FreeModbus释放底层的 TCP 监听端口
服务器·网络·tcp/ip
数智化精益手记局4 小时前
拆解物料管理erp系统的核心功能,看物料管理erp系统如何解决库存积压与缺料难题
大数据·网络·人工智能·安全·信息可视化·精益工程
发光小北5 小时前
Modbus TCP 转 Profibus DP 网关如何应用?
网络协议
灰子学技术5 小时前
Envoy HTTP 过滤器处理技术文档
网络·网络协议·http
Olivia051405147 小时前
Voohu:音频变压器的屏蔽接地技术对50Hz工频噪声抑制的影响
网络·机器人·信息与通信
2401_873479407 小时前
企业安全团队如何配合公安协查?IP查询在电子取证中的技术实践
tcp/ip·安全·网络安全·php