本文主要是介绍TCP Thin-Stream连接,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Thin-stream属性,意味着应用程序以很低的速率发送数据,致使TCP等传输协议的重传机制不能有效的运行。一些场景(类似于在线游戏,控制系统,股票交易等)中,用户体验取决于数据的发送时延,报文丢失对于服务质量来说是灾难性的。极大的时延是由于TCP依赖于应用程序新的报文的发送,进而通过快速重传来启动丢失报文的重传,而不用等待较长时间的RTO超时。
以上提到的时间敏感的交互应用,通常是会产生thin-stream,并且在生命期内一直保持此流量模型。这将导致TCP的高延时。
为了降低报文丢失时的应用层延时,提出了一系列的应对机制。简单来说,如果内核检测到thin-stream,将按如下方式修改重传机制:
1) 在接收到第一个dupACK时,启动快速重传;
2) 不执行指数级退避。
注意,只有在检测到此连接为thin-stream时,才能应用以上的措施。如果inflight报文少于4个,而传统的快速重传需要3个重复ACK,此情况下将不能触发快速重传,此连接可能经历大的重传延时。通过定义InfightSize阈值4,来确定Thin-stream连接。
既然这些机制是针对时间敏感的应用程序,就需要在应用程序中使用IOCTL选项 TCP_THIN_LINEAR_TIMEOUTS 和 TCP_THIN_DUPACK明确的开启,或者通过sysctl选项tcp_thin_linear_timeouts 和 tcp_thin_dupack开启。前两个是针对连接的开关,而后两个是对整个网络命名空间的开关,默认情况下都是关闭状态。
$ cat /proc/sys/net/ipv4/tcp_thin_linear_timeouts
0
$ cat /proc/sys/net/ipv4/tcp_thin_dupack
0
Thin-Stream配置
如下函数do_tcp_setsockopt,选项TCP_THIN_LINEAR_TIMEOUTS设置套接口成员变量thin_lto,取值为0或者1。选项TCP_THIN_DUPACK目前没有使用。
static int do_tcp_setsockopt(struct sock *sk, int level,int optname, char __user *optval, unsigned int optlen)
{switch (optname) { case TCP_THIN_LINEAR_TIMEOUTS:if (val < 0 || val > 1)err = -EINVAL;elsetp->thin_lto = val;break;case TCP_THIN_DUPACK:if (val < 0 || val > 1)err = -EINVAL;break;
Thin-stream判断
如下函数tcp_stream_is_thin,如果inflight报文数量小于阈值4,并且不是位于初始的slowstart阶段,判定此连接为thin-stream。
/* Determines whether this is a thin stream (which may suffer from* increased latency). Used to trigger latency-reducing mechanisms.*/
static inline bool tcp_stream_is_thin(struct tcp_sock *tp)
{return tp->packets_out < 4 && !tcp_in_initial_slowstart(tp);
}
static inline bool tcp_in_initial_slowstart(const struct tcp_sock *tp)
{return tp->snd_ssthresh >= TCP_INFINITE_SSTHRESH;
}
Thin-stream超时处理
如下函数tcp_retransmit_timer,如果应用层通过setsockopt开启了thin_lto,或者在此网络命名空间全局开启了线性超时(tcp_thin_linear_timeouts),并且内核确认了此连接为Thin-stream,将不进行退避处理,由函数__tcp_set_rto根据当前的SRTT设置RTO值。并且将icsk_backoff计数清零,这样在此连接上进行窗口探测等操作时,也不执行退避操作。
void tcp_retransmit_timer(struct sock *sk)
{icsk->icsk_backoff++;icsk->icsk_retransmits++;out_reset_timer:/* If stream is thin, use linear timeouts. Since 'icsk_backoff' is* used to reset timer, set to 0. Recalculate 'icsk_rto' as this* might be increased if the stream oscillates between thin and thick,* thus the old value might already be too high compared to the value* set by 'tcp_set_rto' in tcp_input.c which resets the rto without* backoff. Limit to TCP_THIN_LINEAR_RETRIES before initiating* exponential backoff behaviour to avoid continue hammering* linear-timeout retransmissions into a black hole*/if (sk->sk_state == TCP_ESTABLISHED &&(tp->thin_lto || net->ipv4.sysctl_tcp_thin_linear_timeouts) &&tcp_stream_is_thin(tp) &&icsk->icsk_retransmits <= TCP_THIN_LINEAR_RETRIES) {icsk->icsk_backoff = 0;icsk->icsk_rto = min(__tcp_set_rto(tp), TCP_RTO_MAX);} else {/* Use normal (exponential) backoff */icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);} inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,tcp_clamp_rto_to_user_timeout(sk), TCP_RTO_MAX);
但是,如果在Thin-stream连接上线性重传了6次之后,内核将启用指数级别的退避处理,变量icsk_rto表示的时长每次增大一倍。
/* TCP thin-stream limits */
#define TCP_THIN_LINEAR_RETRIES 6 /* After 6 linear retries, do exp. backoff */
内核版本 5.0
这篇关于TCP Thin-Stream连接的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!