也即处理到52.5-60s这个时间轮的时候,其实外面时间已经过去了112.5s,处理已经完全滞后了。不过由于TIME_WAIT状态下的Socket(inet_timewait_sock)所占用内存很少,所以不会对系统可用资源造成太大的影响。但是,这会在NAT环境下造成一个坑,这也是笔者文章前面提到过的Bug。
上面的计算如果按照图和时间线画出来,应该是这么个情况:
也即TIME_WAIT状态的Socket在一个period(7.5s)内能处理完当前slot的情况下,最多能够存在112.5s!
如果7.5s内还处理不完,那么响应时间轮的轮转还得继续加上一个或多个perod。但在tcp_tw_max_buckets的限制,应该无法达到这么严苛的条件。
PAWS(Protection Against Wrapped Sequences)使得TIME_WAIT延长事实上,以上结论还是不够严谨。TIME_WAIT时间还可以继续延长!看下这段源码:
enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, const struct tcphdr *th) { ...... if (paws_reject) NET_INC_STATS_BH(twsk_net(tw), LINUX_MIB_PAWSESTABREJECTED); if (!th->rst) { /* In this case we must reset the TIMEWAIT timer. * * If it is ACKless SYN it may be both old duplicate * and new good SYN with random sequence number <rcv_nxt. * Do not reschedule in the last case. */ /* 如果有回绕校验失败的包到达的情况下,或者其实ack包 * 重置定时器到新的60s之后 * / if (paws_reject || th->ack) inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN, TCP_TIMEWAIT_LEN); /* Send ACK. Note, we do not put the bucket, * it will be released by caller. */ /* 向对端发送当前time wait状态应该返回的ACK */ return TCP_TW_ACK; } inet_twsk_put(tw); /* 注意,这边通过paws校验的包,会返回tcp_tw_success,使得time_wait状态的 * socket五元组也可以三次握手成功重新复用 * / return TCP_TW_SUCCESS; }上面的逻辑如下图所示:
注意代码最后的return TCP_TW_SUCCESS,通过PAWS校验的包,会返回TCP_TW_SUCCESS,使得TIME_WAIT状态的Socket(五元组)也可以三次握手成功重新复用!
这段逻辑很微妙,会在笔者下一篇<<解Bug之路>>里面进行详解! 总结
如果不仔细分析就下定结论,很容就被自己之前先入为主的一些不够严谨的结论所困扰。导致排查一些复杂问题的时候将思路引导向错误的方向。笔者在追查某个问题的时候就犯了这样的错误。当种种猜测都和事实矛盾时,必须怀疑起自己之前笃定的结论并尝试着推翻它,整个过程即艰辛又快乐!