kernel: TCP: time wait bucket table overflow的问题剖析及解决方法

kernel: TCP: time wait bucket table overflow的问题剖析及解决方法随着访问量的增大,系统默认的承受能力达到上限,这个时候就会报一些异常。比如/var/log/messages中常见的“kernel:TCP:timewaitbuckettableoverflow”这个信息,本文介绍问题的来源及解决办法。

大家好,又见面了,我是你们的朋友全栈君。

随着访问量的增大,系统默认的承受能力达到上限,这个时候就会报一些异常。比如/var/log/messages中常见的“kernel: TCP: time wait bucket table overflow”这个信息,会发现每隔5s就会报出几行。此时查看连接状态如下:

[root@ZhOu ~]# netstat -an | awk '{print $6}' | sort | uniq -c | sort -rn
  16539 TIME_WAIT
   3159 ESTABLISHED
     23 LISTEN
     20 CONNECTED
      5 STREAM
      4 
      1 I-Node
      1 Foreign
      1 established)
      1 and
      1 9793
      1 938869322
      1 8751
      1 7183
      1 7182
      1 7168
      1 10007

可以看到TIME_WAIT的量还是很高的。下面先看一下TCP连接的过程

这里写图片描述

通过此图先说明几个概念:

TIME_WAIT的产生条件:主动关闭方在发送四次挥手的最后一个ACK会变为TIME_WAIT状态,保留次状态的时间为两个MSL(linux里一个MSL为30s,是不可配置的)

TIME_WAIT两个MSL的作用:可靠安全的关闭TCP连接。比如网络拥塞,主动方最后一个ACK被动方没收到,这时被动方会对FIN开启TCP重传,发送多个FIN包,在这时尚未关闭的TIME_WAIT就会把这些尾巴问题处理掉,不至于对新连接及其它服务产生影响。

TIME_WAIT占用的资源:少量内存(查资料大概4K)和一个fd。

TIME_WAIT关闭的危害:1、 网络情况不好时,如果主动方无TIME_WAIT等待,关闭前个连接后,主动方与被动方又建立起新的TCP连接,这时被动方重传或延时过来的FIN包过来后会直接影响新的TCP连接;

2、 同样网络情况不好并且无TIME_WAIT等待,关闭连接后无新连接,当接收到被动方重传或延迟的FIN包后,会给被动方回一个RST包,可能会影响被动方其它的服务连接。

打印“time wait bucket table overflow”信息的代码:

    void tcp_time_wait(struct sock *sk, int state, int timeo)
    {
        struct inet_timewait_sock *tw = NULL;
        const struct inet_connection_sock *icsk = inet_csk(sk);
        const struct tcp_sock *tp = tcp_sk(sk);
        int recycle_ok = 0;

        if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
            recycle_ok = icsk->icsk_af_ops->remember_stamp(sk);

        if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets)
            tw = inet_twsk_alloc(sk, state);

        if (tw != NULL) {
            struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
            const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
        ....
        } else {
                /* Sorry, if we're out of memory, just CLOSE this * socket up. We've got bigger problems than * non-graceful socket closings. */
                LIMIT_NETDEBUG(KERN_INFO "TCP: time wait bucket table overflow\n");
        } 

此段代码处于tcp套接字关闭流程,此时本机主动关闭tcp套接字,套接字状态=变为time wait,等待对端进行关闭套接字。
从代码可以看出,有两种情况可能导致这样的打印:
1、当tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets时,即当当前处于time wait状态的socket数量超过sysctl_max_tw_buckets(即net.ipv4.tcp_max_tw_buckets)时
2、当inet_twsk_alloc(sk, state)返回为NULL时,出现这样的打印,再看看inet_twsk_alloc(sk, state)的代码:


    struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int state)
    {
        struct inet_timewait_sock *tw =
            kmem_cache_alloc(sk->sk_prot_creator->twsk_prot->twsk_slab,
                     GFP_ATOMIC);
    ...
    return tw;
    }

由此可以看出,当kmem_cache_alloc(从slab中分配内存)失败时,会返回NULL,最终导致这样的打印,这种情况可能的原因为内存不足。
综上,打印出现有两种可能原因:
1) 处于time wait状态的tcp套接字,超过net.ipv4.tcp_max_tw_buckets限制
2) 申请内存失败,可能原因为内存不足

该打印不影响系统的正常功能,当出现这种情况时,出现异常的套接字打印完成后会立即释放,不再等对端确认关闭。但有隐患,如果表示处于time wait的socket太多,则可能导致无法创建新的连接。这种可能是业务代码在socket关闭的处理上有些问题,可能存在大量半关闭的socket。另外,也可能表示内存不足,需要关注。

解决方法

既然知道了TIME_WAIT的用意了,尽量按照TCP的协议规定来调整,对于tw的reuse、recycle其实是违反TCP协议规定的,服务器资源允许、负载不大的条件下,尽量不要打开,当出现TCP: time wait bucket table overflow,需要调整/etc/sysctl.conf中下面参数:

net.ipv4.tcp_max_tw_buckets = 50000 
调大timewait 的数量

net.ipv4.tcp_fin_timeout = 10  
如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2 状态的时间。对端可以出错并永远不关闭连接,甚至意外当机。缺省值是60 秒。2.2 内核的通常值是180 秒,3你可以按这个设置,但要记住的是,即使你的机器是一个轻载的WEB 服务器,也有因为大量的死套接字而内存溢出的风险,FIN- WAIT-2 的危险性比FIN-WAIT-1 要小,因为它最多只能吃掉1.5K 内存,但是它们的生存期长些。

net.ipv4.tcp_tw_recycle= 1   
启用timewait 快速回收

net.ipv4.tcp_tw_reuse = 1    
开启重用,允许将TIME-WAIT sockets 重新用于新的TCP 连接

net.ipv4.tcp_keepalive_time = 15  
当keepalive 启用的时候,TCP 发送keepalive 消息的频度,缺省是2 小时  

设置完毕,查看messages中的信息和连接状态,一切正常了。

参考文章

http://benpaozhe.blog.51cto.com/10239098/1767612

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/132818.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Recyclerview 刷新「建议收藏」

    Recyclerview 刷新「建议收藏」前言:recyclerview比起listview功能上更加丰富外(如横向列表),在Item复用上也更加灵活,比如listview的某个Item数据需要更新,要通过notifyDataSetChanged方法对全部Item进行刷新,而recyclerview则可以精准刷新。介绍:(1)notifyItemChanged(position)只刷新该position的Item,即只是该Item调用onBindViewHolder,因此如果对数据源进行插、移除操作不能改方法只刷新操作的Item,毕竟该

    2025年5月31日
    3
  • PotPlayer使用技巧和常用快捷键

    PotPlayer使用技巧和常用快捷键常用快捷键Alt+K屏幕旋转

    2022年5月21日
    79
  • C#中保存Gif文件设置透明无效果

    C#中保存Gif文件设置透明无效果在C#中使用Graphics.Clear(Color.Transparent)生成gif格式透明文件时,设置透明不起作用。使用Bitmap.MakeTransparent方法同样也不能使gif文件透明。这两个问题也是微软的设计使然,和gif文件格式有关系。如果要在c#中编程实现透明色,必须另写代码,下面是一位老外的代码/// &lt;summary&gt;/// Make the i…

    2022年7月21日
    15
  • encrypt函数_crypt12

    encrypt函数_crypt12数据加密数据加密利用密码技术对信息进行加密,实现信息的隐蔽,从而起到保护信息安全的作用。它通过加密算法和加密秘钥将原来是明文的文件或数据进行处理,使其成文不可读的一段代码,也就是所谓的“密文”,来达到

    2022年8月6日
    8
  • pytest运行_python缓存机制

    pytest运行_python缓存机制前言pytest运行完用例之后会生成一个.pytest_cache的缓存文件夹,用于记录用例的ids和上一次失败的用例。方便我们在运行用例的时候加上–lf和–ff参数,快速运行上一

    2022年7月30日
    10
  • 基于SSM的景区旅游管理系统

    基于SSM的景区旅游管理系统项目运行截图首页展示信息攻略管理酒店管理技术描述开发工具:idea/eclipse数据库:mysqlJar包仓库:Maven前段框架:Html/Thymeleaf后端框架:spring+springmvc+mybatis+SpringBoot资料说明基于SSM的景区旅游管理系统,整体包含前后台页面,整体采用SSM框架,SpringBoot作为基础框架,前端页面采用Thymele

    2022年5月8日
    65

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号