定制TCP重传策略
背景说明
TCP报文重传遵循指数退避原则,在弱网场景下包到达率较低,时延较高。因此新增通过编程接口定制TCP重传策略的能力,包括定制线性退避次数、最大重传次数、最大重传间隔时间,以优化弱网场景的包到达率和时延。
接口说明
- 调用setsockopt针对指定socket定制TCP重传策略
- 接口:
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); int getsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
optname传递枚举,optval传递结构体起始地址。
- 枚举:
TCP_SOCK_RETRANS_POLICY_CUSTOM 100
结构体:struct tcp_sock_retrans_policy { uint8_t tcp_linear_timeouts_times; /* number of times linear backoff */ uint8_t tcp_retries_max; /* maximum retransmission times */ uint8_t tcp_rto_max; /* maximum RTO time, unit:second */ uint8_t unused; };
其中:
- tcp_linear_timeouts_times表示线性退避次数,范围:取值是在0到32之间。
非0:定制线性退避次数。
- 指数退避:发生报文重传时,RTO值直接翻倍
- 线性退避:发生报文重传时,RTO值保持不变
- tcp_retries_max表示最大重传次数,范围:取值是在0到64之间。
非0:定制最大重传次数。
最大重传次数需要大于sysctl选项net.ipv4.tcp_retries1(最小重传次数,默认3次)。
- tcp_rto_max表示最大重传间隔时间,单位为秒,不允许设置小数,范围:取值是0或者在20到120之间。
非0:定制最大重传间隔时间。
- tcp_linear_timeouts_times表示线性退避次数,范围:取值是在0到32之间。
- 接口:
使用说明
- 开启TCP重传策略定制能力。通过如下命令,将net.ipv4.tcp_sock_retrans_policy_custom配置为1:
[root@localhost ~]# sysctl -w net.ipv4.tcp_sock_retrans_policy_custom=1
设置线性退避4次,最大重传10次,最大重传间隔时间20秒:
tcp_sock_retrans_policy policy = {0}; policy.tcp_linear_timeouts_times = 4; policy.tcp_retries_max = 10; policy.tcp_rto_max = 20; setsockopt(sockfd, SOL_TCP, TCP_SOCK_RETRANS_POLICY_CUSTOM, (const void*)&policy, sizeof(struct tcp_sock_retrans_policy));
- 恢复为默认策略:
tcp_sock_retrans_policy policy = {0}; setsockopt(sockfd, SOL_TCP, TCP_SOCK_RETRANS_POLICY_CUSTOM, (const void*)&policy, sizeof(struct tcp_sock_retrans_policy));
- 关闭TCP重传策略定制能力:
[root@localhost ~]# sysctl -w net.ipv4.tcp_sock_retrans_policy_custom=0
定制TCP重传策略功能在HCE2.0版本内核进行修改,在HCE2.0版本glibc中使用该功能,需要在用户态代码中添加TCP_SOCK_RETRANS_POLICY_CUSTOM 宏以及对应的结构体tcp_sock_retrans_policy。
约束限制
- 只针对ESTABLISHED状态的TCP链接生效。
- 支持IPv4和IPv6,由于历史原因,TCP相关sysctl选项都挂在net.ipv4下,实际以net.ipv4.tcp打头的sysctl选项,对IPv4和IPv6均生效。
- 应用级TCP重传策略优先级高于其他全局级TCP重传配置。
- 定制TCP重传策略可能会增加系统负载,需要根据系统资源合理定制,建议定制的线性退避次数不超过6次。
- 如果定制的最大重传次数小于net.ipv4.tcp_retries1(默认值3),则将无法触发网络探测,可能导致部分网络变更场景报文不通。
- 如果定制的最大重传次数非0,则其必须大于等于线性退避次数,否则返回错误。
- 如果只定制最大重传间隔时间,不定制最大重传次数,那么实际最大重传次数可能会大于net.ipv4.tcp_retries2(默认值15,描述最大重传次数或时间,下简称R2)。RFC6069规定,如果R2使用次数描述,则必须换算成时间。为避免使能本功能后TCP过早断连,该换算过程使用系统默认TCP_RTO_MAX(120s)而不是定制的最大重传时间,因此对外表现为实际重传次数多于R2。
- 由于TCP-TLP算法,未收到ACK的尾包可能会被Loss Probe定时器选中做一次重传,用于后续触发快速重传。该次重传不计入本功能定制的重传次数内。