• tcp协议在定位中的应用


    1. 问题背景

        线上服务变得卡顿。发现 open too many files错误。

    2. 定位经过

       首先查看linux服务器负载是否高,CPU,MEM,磁盘读写IOPS(发现高,但是很快排除了,因为是错误日志打印太多到本地磁盘)使用netstat 查看当时的连接情况,有条件的可以看监控软件。发现整体负载不高,事后回顾,如果整体负载不高,那么应该考虑是否有系统设置的限制。

     查看linux tcp配置参数, cat/etc/sysctl.conf 或者sysctl -a,发现有人修改了net.ipv4.tcp_max_tw_buckets默认参数,有人把它改小了。当时没有留意,后面发现才是它是一种错误。为啥会把它改小。发现网上有一些人云亦云的博客,说为了提高性能,限制time_wait数量,把数目改小了,所以大家也跟风改。这是正确的吗?

       使用netstat -antp 命令,使用shell awk uniq 去重,统计IP,发现每个IP发现100.xxx.xxx.xx地址的time_wait特别多,而且地址不固定。100开头的是内部地址。

       使用tcpdump命令查看里面的发送内容,发现就是app的接口服务,还有是一些健康检测的报文。原来是公司使用了阿里云的SLB均衡负载。通过分析报文得知,每次请求,服务都主动关闭了连接,发送FIN,从而产生了time_wait。 所以纠正了我之前的认知。time_wait并不一定是请求方产生的,而是主动关闭连接方产生的。这个通过tcp状态转移图可以看出。

       怀疑阿里云SLB均衡负载是不是有问题。在阿里云提交工单,发问有没有配置可以让均衡负载IP固定下来。问了好几次得到答非所问,最后一次技术支持人员才回答到正轨上,回答说不支持。查看文档,SLB http 7层均衡负载,经过tengine,性能有损耗(相对tcp4层均衡负载),会把长连接转为短连接。然后文档说在压测的情况下会导致后端服务器有大量time_wait.

      怀疑代码框架有问题,但是在本地测试,发现正常,都是客户端主动发起断开请求,服务端没有产生time_wait。通过tcpdump获取报文,与线上的发出报文对比。发现线上的请求方http header 带有connect:close。 本地测试加上了header,问题就复现了。

      换个代码框架测,使用python flask,发现不能复现。通过tcpdump报文分析,发现flask默认使用http 1.0协议进行应答。使用http 1.1 需要设置,设置完毕后,python flask框架也能复现了。所以,每个框架实现http,而http是一种协议,所以成熟的框架在http请求里面的表现都应该是一致的。

      怀疑是客户端请求有问题。让客户端请求头 加上keep-alive: timeout=3,max=1 , 经过测试,3s超时后并没有关闭,后面看文章,发现客户端的超时设置只是一种没有约束力的通知,最终由服务端来决定超时时间。

       后面通过排查,客户端的同事说请求没有带上connect:close 的头,但是线上tcpdump看有这个头,怀疑是其他地方加上的,并通过发工单给阿里云,确认了connect:close是SLB均衡负载产品主动给请求加上的,以达到实现变成短连接的目的。这个也是http 1.1协议的定义,http1.1默认使用长连接,要带上这个参数来关闭长连接。

       如果长连接的话,服务端可以复用连接,不用每次三次握手。如果是客户端主动关闭的话,服务端不会产生time_wait,但是会产生close_wait,而通过tcp状态转移图,close_wait在对端发回应答,即可马上回收(后续描述又是一个问题)。而time_wait需要等待2MSL,这个时间比较久(这个没有按照RFC协议规定时间,一般几分钟左右),回收连接比较慢,会造成堆积。

     但是目前系统负载不高,time_wait数量不多。所以尽管time_wait产生堆积,也不足以产生性能问题。反复排查,time_wait数量很固定,与想tcp_max_tw_buckets这参数阈值很接近。怀疑是设置的问题。通过查看官方说法:

        This limit exists only to prevent simple DoS attacks, you _must_ not lower the limit artificially,but rather increase it (probably, after increasing installed memory),if network conditions require more than default value.

       所以网上的那些优化性能的文章,误导了很多人,不应该随便调tcp的参数。把tcp_max_tw_buckets恢复默认值,后续观察得到缓解。

      但是open too many files的问题,还是时不时出现,这个导致服务阻塞。所以后续文章分析一下close_wait的问题,其中再分析一下tcp连接连接,释放连接过程中遇到的问题。

  • 相关阅读:
    管道命令'|' 和xargs find命令找到后把所有找到的删除
    UVa
    【手势交互】9. PS Move
    jquery时间格式化插件
    Android学习路线(十三)Activity生命周期——暂停和恢复(Pausing and Resuming )一个Activity
    hdu 2604 Queuing (矩阵高速幂)
    【Linux驱动】TQ2440 DM9000E网卡驱动移植(Linux-2.6.30.4)
    bzoj2648 SJY摆棋子
    Hive编程指南_学习笔记01
    通信协议中的转义符
  • 原文地址:https://www.cnblogs.com/studyNT/p/13975597.html
Copyright © 2020-2023  润新知