zoukankan      html  css  js  c++  java
  • tcp_tw_recycle和tcp_timestamps导致connect失败问题

    近来线上陆续出现了一些connect失败的问题,经过分析试验,最终确认和
    proc参数tcp_tw_recycle/tcp_timestamps相关;

    1. 现象

    第一个现象

    模块A通过NAT网关访问服务S成功,⽽而模块B通过NAT⽹网关访问
    服务S经常性出现connect失败,抓包发现:服务S端已经收到了了syn包,但没有
    回复synack;另外,模块A关闭了了tcp timestamp,⽽而模块B开启了了tcp
    timestamp;

    第二个现象

    不同主机上的模块C(开启timestamp),通过NAT网关(1个出
    口ip)访问同一服务S,主机C1 connect成功,⽽而主机C2 connect失败;

    2. 分析

    根据现象上述问题明显和tcp timestmap有关;查看linux 2.6.32内核源码,发
    现tcp_tw_recycle/tcp_timestamps都开启的条件下,60s内同一源ip主机的
    socket connect请求中的timestamp必须是递增的。

    源码函数

    tcp_v4_conn_request(),该函数是tcp层三次握⼿手syn包的处理理函数
    (服务端);
    源码⽚片段:

    if (tmp_opt.saw_tstamp &&
        tcp_death_row.sysctl_tw_recycle &&
        (dst = inet_csk_route_req(sk, req)) != NULL &&
        (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
        peer->v4daddr == saddr) {
        if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
            (s32)(peer->tcp_ts - req->ts_recent) >
                TCP_PAWS_WINDOW) {
            NET_INC_STATS_BH(sock_net(sk),
        LINUX_MIB_PAWSPASSIVEREJECTED);
            goto drop_and_release;
        }
    }

    tmp_opt.saw_tstamp:该socket支持tcp_timestamp
    sysctl_tw_recycle:本机系统开启tcp_tw_recycle选项
    TCP_PAWS_MSL:60s,该条件判断表示该源ip的上次tcp通讯发⽣生在60s

    TCP_PAWS_WINDOW:1,该条件判断表示该源ip的上次tcp通讯的
    timestamp 大于 本次tcp

    分析

    主机client1和client2通过NAT⽹网关(1个ip地址)访问serverN,由于
    timestamp时间为系统启动到当前的时间,因此,client1和client2的timestamp
    不不相同;根据上述syn包处理理源码,在tcp_tw_recycle和tcp_timestamps同时开
    启的条件下,timestamp⼤的主机访问serverN成功,⽽而timestmap小的主机访问
    失败;

    参数:/proc/sys/net/ipv4/tcp_timestamps - 控制timestamp选项开启/关闭
    /proc/sys/net/ipv4/tcp_tw_recycle - 减少timewait socket释放的超时时间

    3. 解决⽅方法

    echo 0 > /proc/sys/net/ipv4/tcp_tw_recycle;
    tcp_tw_recycle默认是关闭的,有不少服务器器,为了提⾼高性能,开启了该选
    项;

    个人建议

    为了解决上述问题,个人建议关闭tcp_tw_recycle选项,而不是timestamp;
    因为 在tcp timestamp关闭的条件下,开启tcp_tw_recycle是不起作用的;而tcp
    timestamp可以独⽴立开启并起作⽤用。

    源码函数: tcp_time_wait()

    源码⽚片段

    if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
        recycle_ok = icsk->icsk_af_ops->remember_stamp(sk);
    ......
    if (timeo < rto)
        timeo = rto;
    if (recycle_ok) {
        tw->tw_timeout = rto;
    } else {
        tw->tw_timeout = TCP_TIMEWAIT_LEN;
        if (state == TCP_TIME_WAIT)
            timeo = TCP_TIMEWAIT_LEN;
    }
    inet_twsk_schedule(tw, &tcp_death_row, timeo,
        TCP_TIMEWAIT_LEN);

    timestamp和tw_recycle同时开启的条件下,timewait状态socket释放的超时
    时间和rto相关;否则,超时时间为TCP_TIMEWAIT_LEN,即60s;
    内核说明⽂文档 对该参数的介绍如下:
    tcp_tw_recycle - BOOLEAN
    Enable fast recycling TIME-WAIT sockets. Default value is 0.
    It should not be changed without advice/request of technical
    experts.

  • 相关阅读:
    Nodejs
    webpack与gulp的区别
    gulpjs
    Commonjs、AMD、CMD
    建造者模式
    工厂模式
    设计模式分类
    python的接口
    Python代码教你批量将PDF转为Word
    什么是“堆”,"栈","堆栈","队列",它们的区别?
  • 原文地址:https://www.cnblogs.com/chuyiwang/p/9997007.html
Copyright © 2011-2022 走看看