• HAproxy和TIME WAIT的一次问题排查


    近日平稳运行了将近4年的发号器突然出现问题,在元旦0分的时候出现短暂的性能下降,导致发号失败率飙高到一个不可接收的值,哎,意外总是发生在你想不到的地方。

    这几天赶紧和小伙伴们赶紧追查原因,制定改造方案,下面记录一下分析和定位问题的过程,以便后期查阅,并不在同一个地方跌倒两次。

    一、分析过程

    1、现象

    现象是业务所用的uuid服务的6052端口出现性能下降,导致成功率下降。

    2、日志

    出问题第一反应就是去看日志,我们HAProxy的日志级别是notice,具体的报错如下

    Jan  1 00:00:17 localhost haproxy30864: Server uuid6051/s2 is DOWN, reason: Socket error, info: "Cannot assign requested address", check duration: 0ms. 1 active and 1 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.

    Jan  1 00:00:22 localhost haproxy30873: Server uuid6051/s2 is UP, reason: Layer4 check passed, check duration: 268ms. 2 active and 1 backup servers online. 0 sessions requeued, 0 total in queue.

    很简单,HAproxy认为rs的s2 down了,但是我们通过其他手段发现,s2其实并没有任何问题,这个报错应该不是s2真down引发,而是HAproxy认为s2 down引发,所以问题根源还要在HAproxy所在的服务器上继续找。

    3、架构

    简单描述一下我们的集群架构,我们使用4台物理服务器,每2台一组。每台服务器上部署2个实例,分别为6051和6052端口,前面通过HAproxy来对后端的rs进行健康检查和负载均衡。2台服务器上的HAproxy之间通过keepalive保持高可用。

    4、寻找线索

    由于当时现场保存不全,各种信息已经无法重放。(ps:凸显监控的重要性啊,没有历史数据和现场回放追问题太痛苦了)只好进行现场monitor, 在各种横向对比的过程中我们发现某一台服务器的cpu idle在案发时刻有较为明显的变化,再进一步发现这台服务器的time-wait非常的高,其他服务器的仅在200-300,这台服务器的可以达到 2w-3w,看来当天晚上的问题和高time-wait有关系了。

    5、定位问题

    高time-wait的情况一般发生在短连接的情况下,所以我们决定通过压测重现现场,以便判断。最终通过压测重现了当天的现象,HAproxy都报错信息完全一致,至此基本可以判定当天的报错就是由于time-wait过高引发的。

    另外,在和开发的沟通中发现,有用长连接的也有用短连接的,而使用短连接的业务出现报错的情况更为突出,这也侧面验证了我们的判断。

    二、优化过程

    如果要优化,那么要先说说tcp的各种状态转化和连接建立。

    本例问题的根本原因就在于由于短连接主动关闭,导致HAproxy也会主动关闭其和后端的链接,导致HAproxy本地出现大量的time- wait状态,而linux建立tcp连接受限于port,time-wait状态会占用大批量的port,如果所有port都被占用之后,就无法在新建 立连接,也就会出现上面的报错。

    至此,优化思路应该有了,其一,加大可用port端口,其二,加快time-wait状态回收。

    1、增加可用port数

    增加可用端口的方法比较简单,linux中由ip_local_port_range控制,默认一般为32768到61000,可以通过如下命令修改

    cat /proc/sys/net/ipv4/ip_local_port_rang

    echo “1024 61000” > /proc/sys/net/ipv4/ip_local_port_rang

    另外,由于tcp建立连接需要通过4元组确定,即srcip:srcport-dstip:dstport,故可以通过增加rs上uuid实例数,也就是增加新port数目来增加,每增加一个port即可以增加57000+的连接。

    2、快速回收time-wait状态

    time-wait状态,是在tcp关闭连接的时候的一个状态,它会在client端(发起关闭的端)存活2MSL(2分钟,maximun segment lifetime,最大分节生命期),在这个期间分配出去的port不会被复用,这样就会导致port资源的大量消耗也就导致了问题的出现。

    “TCP 4次握手关闭连接流程图”

    接下来说一下有那些参数对快速回收time-wait状态有效果

    net.ipv4.tcp_tw_recyle

    Enable fast recycling TIME-WAIT sockets. Default value is 1.It should not be changed without advice/request of technical experts

    net.ipv4.tcp_tw_reuse

    Allow to reuse TIME_WAIT sockets for new connections when it is safe from protocol viewpoint. It should not be changed without advice/request of technical experts

    net.ipv4.tcp_fin_timeout

    This specifies how many seconds to wait for a final FIN packet before the socket is forcibly closed. This is strictly a violation of the TCP specification, but required to prevent denial-of-service attacks. In Linux 2.2, the default value was 180.

    net.ipv4.tcp_max_tw_buckets

    The maximum number of sockets in TIME_WAIT state allowed in the system. This limit exists only to prevent simple denial-of-service attacks. The default value of NR_FILE*2 is adjusted depending on the memory in the system. If this number is exceeded, the socket is closed and a warning is printed.

    尤其是tcp_max_tw_buckets,这个是全局的限定,虽然tcp建立连接要依赖于4元组,socket的port可以服用,但是对于 tw buckets来说是按照合计计算的。一旦设定某一个数值之后,如果超过限定值,系统会立刻回收资源,并在message中记录一条warning。

    localhost kernel: TCP: time wait bucket table overflow

    三、总结

    1、监控是最最重要的,没有“现场”,哪里谈“破案”

    2、重现是第二重要的,万事不能靠猜,只有能重现才能验证问题并验证之后的解决方案

    3、信息准确,只要在一个准确的信息上才能进行分析,信息不准确只会把你引到错误的路上

  • 相关阅读:
    CentOs 安装 Mysql
    安装 CentOs 系统 及 Python 及 Scrapy 框架
    对IOC的理解
    SQL语句优化 -- 以Mysql为例
    探讨 java中 接口和对象的关系
    Java中组合 设计技巧 实例
    【题解】Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths Codeforces 741D DSU on Tree
    【题解】Tree-String Problem Codeforces 291E AC自动机
    【题解】打地鼠 SDOI2011 模拟 行列无关
    【题解】新型城市化 HAOI2017 网络流 二分图最大匹配 强连通分量
  • 原文地址:https://www.cnblogs.com/billyxp/p/4210675.html
Copyright © 2020-2023  润新知