上图这个服务器“优化”是不是似曾相识,网上有太多太多这样的文章,核心调优方案就是开启 tcp_timestamps 和 tcp_tw_recycle。诚然这个“调优“,确实如毒品一般让业务瞬间得到虚幻一般的高潮,但是他的危害也如毒品一般让业务一步步陷入深渊。
然后突然某一天,你发现业务出现端口间歇性出现不通。如幽灵一般出现,又很快消失得无影无踪,让人抓耳挠腮又哭笑不得。
WHY?
如linux-3.16.80 中已经给出警示⚠️
代码语言:c复制 542 tcp_tw_recycle - BOOLEAN
543 Enable fast recycling TIME-WAIT sockets. Default value is 0.
544 It should not be changed without advice/request of technical
545 experts.
It should not be changed without advice/request of technical experts. 翻译一下除非得到技术专家的建议或要求﹐请不要随意修改这个值
说得更直白点,就是除非你知道你在做什么,否则不要乱动。
为什么会这么劝告呢?
Talk is cheap. Show me the code.
代码语言:txt复制//include/net/tcp.h:
#define TCP_PAWS_MSL 60
#define TCP_PAWS_WINDOW 1
/*------------------------------------
// net/ipv4/tcp_metrics.c
*/
bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, bool paws_check)
{
struct tcp_metrics_block *tm;
bool ret;
if (!dst)
return false;
rcu_read_lock();
tm = __tcp_get_metrics_req(req, dst);
if (paws_check) {
if (tm &&
(u32)get_seconds() - tm->tcpm_ts_stamp < TCP_PAWS_MSL &&
(s32)(tm->tcpm_ts - req->ts_recent) > TCP_PAWS_WINDOW)
ret = false;
else
ret = true;
} else {
if (tm && tcp_metric_get(tm, TCP_METRIC_RTT) && tm->tcpm_ts_stamp)
ret = true;
else
ret = false;
}
rcu_read_unlock();
return ret;
}
/*------------------------------------
// net/ipv4/tcp_ipv4.c
*/
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
……
/* VJ's idea. We save last timestamp seen
* from the destination in peer table, when entering
* state TIME-WAIT, and check against it before
* accepting new connection request.
*
* If "isn" is not zero, this request hit alive
* timewait bucket, so that all the necessary checks
* are made in the function processing timewait state.
*/
if (tmp_opt.saw_tstamp &&
tcp_death_row.sysctl_tw_recycle &&
(dst = inet_csk_route_req(sk, &fl4, req)) != NULL &&
fl4.daddr == saddr) {
if (!tcp_peer_is_proven(req, dst, true)) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
goto drop_and_release;
}
}
……
}
tcp_v4_conn_request函数是tcp层三次握手SYN包的处理函数(服务端)
tmp_opt.saw_tstamp:socket 开启了 tcp_timestamp
tcp_death_row.sysctl_tw_recycle:系统内核开启了 tcp_tw_recycle
在系统打开sysctl_tw_recycle后,如果来自同一个源IP(Source IP)的请求,在60s内出现timestamp未递增的包,报文(比如SYN)将丢弃,导致无法建立连接。
所以,如果Client有可能处于NAT环境的情况下,服务器一定不要开启sysctl_tw_recycle。另外,必须开启tcp_timestamp后开启sysctl_tw_recycle才能生效。所以tcp_timestamp=0,sysctl_tw_recycle=1的骚操作也别想了。
PS:Linux 从4.12内核版本开始移除了 tcp_tw_recycle 配置