请慎重使用tcp_tw_recycle毒药

2019-12-30 11:34:13 浏览数 (1)

上图这个服务器“优化”是不是似曾相识,网上有太多太多这样的文章,核心调优方案就是开启 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 配置

0 人点赞