Open WALL-E opened 7 years ago
为什么TCP状态迁移需要TIME-WAIT这个状态
不像Windows 可以修改注册表修改2MSL 的值,linux 是没有办法修改MSL的,tcp_fin_timeout 不是2MSL 而是Fin-WAIT-2状态。
[appuser@bjsh19-33-237 ~]$ ss -s
Total: 168 (kernel 249)
TCP: 7625 (estab 86, closed 7526, orphaned 0, synrecv 0, timewait 7526/0), ports 312
slabtop
8925 7515 84% 0.25K 595 15 2380K tw_sock_TCP
每个TIME-WAIT大概占用0.3k字节。1M个TIME-WAIT,也就占用300M内存而已。
tw_reuse 只对客户端起作用,开启后客户端在1s内回收
tw_recycle 对客户端和服务器同时起作用,开启后在 3.5*RTO 内回收,RTO 200ms~ 120s 具体时间视网络状况。
内网状况比tw_reuse 稍快,公网尤其移动网络大多要比tw_reuse 慢,优点就是能够回收服务端TIME_WAIT数量。
对内网服务器而言(除LVS和防火墙),开启这两个参数是安全的。
客户端A <==> [NAT设备B] === [NAT设备C] <==> 服务端D
客户端A和服务端D开启tw_reuse 和 tw_recycle 是有风险的,服务端D上风险相对会更大一些,因为他的连接数要大的多。
这种情况下,尽管tcp_timestamp已经开启,迷途的TCP分节还是有可能会插入到正常的TCP连接中,导致TCP传输发生异常,本质的原因是多个客户端的系统时间不一致导致的。假如,所有客户端的时间是完全一致的话,TCP传输依然还是很安全。对服务端来说,原理基本一样。
总的来说,在高负载的服务器上出现大量的TIME-WAIT,十几万或是更多,这并不是一个问题,或者说并不一定需要优化。换句话说,即使是调整了内核参数,减小了TIME-WAIT的数量,对服务器的性能来说,改变是微不足道的。
用反证法来证明:假如TIME-WAIT有问题的话,或者在多数情况下都需要优化的话,为什么linux内核的那帮黑客不解决呢,TCP协议可是已经出现了30多年了。
核心数据结构 @include/net/inet_timewait_sock.h
struct inet_timewait_death_row {
/* Short-time timewait calendar */
int twcal_hand;
unsigned long twcal_jiffie;
struct timer_list twcal_timer;
struct hlist_head twcal_row[INET_TWDR_RECYCLE_SLOTS];
spinlock_t death_lock;
int tw_count;
int period;
u32 thread_slots;
struct work_struct twkill_work;
struct timer_list tw_timer;
int slot;
struct hlist_head cells[INET_TWDR_TWKILL_SLOTS];
struct inet_hashinfo *hashinfo;
int sysctl_tw_recycle;
int sysctl_max_tw_buckets;
};
void dccp_time_wait(struct sock *sk, int state, int timeo)
{
struct inet_timewait_sock *tw = NULL;
if (dccp_death_row.tw_count < dccp_death_row.sysctl_max_tw_buckets)
tw = inet_twsk_alloc(sk, state);
if (tw != NULL) {
/*......*/
} else {
/* Sorry, if we're out of memory, just CLOSE this
* socket up. We've got bigger problems than
* non-graceful socket closings.
*/
DCCP_WARN("time wait bucket table overflow\n");
}
dccp_done(sk);
}
从代码的逻辑上看,不管是timewait超出限制,还是内存用尽,系统都会打印错误日志。
关于tcp_tw_recycle和tcp_tw_reuse的源码逻辑比较复杂,暂且不读。
测量timewait持续时间的脚本 https://github.com/WALL-E/tcp-ip-labs/blob/master/timewait/t.sh
include/net/inet_hashtables.h sourcecode
MSL
实际上,对于当前的网络环境,这个值已经变得没有意义了,一个数据包不可能在网络中存活2分钟(120s),这个时间内,数据包几乎可以从北京到旧金山跑120个来回。
另外,IP层使用了另一个变量来表示数据包的存活时间,就是TTL,这个值和时间无关,而是发送端初始化,然后每经过一个路由器就减1,当TTL为零的时候,路由器丢弃这个数据包。
现在为什么大家还用这个名词来表示时长,仅仅是习惯了而已。
结论:2MLS只是一个时间长度,只是一个名词,已经没有实际意义啦。
猜想: ip协议和tcp协议设计之初的目的是要在不同的协议层来独立控制数据包的存活时间,显然,TCP层的MSL没有被广泛应用,至于为什么和TCP状态TIME_WAIT纠缠不清,这只是一个副作用。
那为什么是2MSL,而不是3MSL或者是4MSL,这个原因用中国话来讲,和有再一再二,没有再三再四,是一个意思。
请忘记2MSL吧, 记住1分钟就可以啦!