zoukankan      html  css  js  c++  java
  • TCP time_wait close_wait问题(可能是全网最清楚的例子)

    背景

    公司群里,运维发现一个问题,task服务报错(如下)

    The stream or file "/data/logs/adn_task/offer_service.log" could not be opened:
    failed to open stream: Too many open files
    

    测试老大看到了,根据经验就推测是应该是文件句柄使用完了,应该有TCP连接很多没释放,果真发现是很多CLOSE_WAIT的状态

    简单认知

    短链接,一次链接就会占用一个端口,一个端口就是一个文件描述符;
    文件描述符 又称 句柄,linux系统最大的句柄数是65535,可以通过ulimit -a 查看
    image.png

    三次握手

    TCP建立连接需要经过三次握手;
    通俗版本:
    A: 你好,你能听见我说话吗?
    B: 能听到,你能听到我说话吗?
    A:我也能听到,我们开始通信吧

    专业版本:
    建立TCP连接时,需要客户端和服务器共发送3个包。

    • 第一次:客户端发送初始序号x和syn=1请求标志
    • 第二次:服务器发送请求标志syn,发送确认标志ACK,发送自己的序号seq=y,发送客户端的确认序号ack=x+1
    • 第三次:客户端发送ACK确认号,发送自己的序号seq=x+1,发送对方的确认号ack=y+1

    四次挥手

    TCP连接断开需要经过四次挥手;
    通俗版本:
    前提A和B在通话
    A:好的,我的话就说完了(FIN);
    B:哦哦,我知道你说完啦(ACK),我还有说两句哈;A: (没说话,一直听着)
    B:哦了,我也说完了(FIN)
    A:好的,我也知道你说玩了(ACK),挂电话吧

    专业版本:

    • 第一次挥手:客户端发出释放FIN=1,自己序列号seq=u,进入FIN-WAIT-1状态
    • 第二次挥手:服务器收到客户端的后,发出ACK=1确认标志和客户端的确认号ack=u+1,自己的序列号seq=v,进入CLOSE-WAIT状态
    • 第三次挥手:客户端收到服务器确认结果后,进入FIN-WAIT-2状态。此时服务器发送释放FIN=1信号,确认标志ACK=1,确认序号ack=u+1,自己序号seq=w,服务器进入LAST-ACK(最后确认态)
    • 第四次挥手:客户端收到回复后,发送确认ACK=1,ack=w+1,自己的seq=u+1,客户端进入TIME-WAIT(时间等待)。客户端经过2个最长报文段寿命后,客户端CLOSE;服务器收到确认后,立刻进入CLOSE状态。

    状态流转图

    实际例子

    建立连接

    linux上起了一个redis服务
    image.png
    本地起的6379端口

    还是同一台机器上,通过python脚本连接该redis服务:
    image.png

    此时网络连接如下:
    image.png
    关注这两个网络连接,第一个是redis-server的,第二是python脚本的,此时都是ESTABLISHED状态,表示这两个进程建立了连接

    TIME_WAIT情况

    现在断掉python
    image.png
    之前的python的那个连接,是TIME_WAIT状态
    客户端(主动方)主动断开,进入TIME_WAIT状态,服务端(被动方)进去CLOSE状态,就是没有显示了

    等待2MSL(1分钟)后,如下:
    image.png
    TIME_WAIT状态的连接也消失了,TIME_WAIT回收机制,系统ing过一段时间会回收,资源重利用

    CLOSE_WAIT情况

    先建立连接,如下:
    image.png

    关掉redis服务,service redis stop
    image.png
    之前的redis-server的45370端口连接 进入了FIN_WAIT2状态,而python端(被动关闭方)就进去了CLOSE_WAIT状态

    等待30s后,在看连接
    image.png
    只有python的那条CLOSE_WAIT

    再次操作python端的脚本,再次get
    image.png

    关于6379端口(redis端口)的网络连接都没有了
    image.png

    TCP参数设置

    如何快速回收TIME_WAIT和FIN_WAIT
    /etc/sysctl.conf 包含以下配置项
    net.ipv4.tcp_timestamps = 1
    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_fin_timeout = 30
    root权限 执行/sbin/sysctl -p使之生效

    经验之谈

    个人经验,不一定对,如有错误,请指正

    1. 当出现了CLOSE_WAIT大概率是业务代码问题,代码中没有处理服务异常的情况,如上面的例子,python再次请求redis的时候,发现redis挂了,就会主动干掉CLOSE_WAIT状态
    2. 出现大量TIME_WAIT的情况,一般是服务端没有及时回收端口,linux内核参数需要调整优化

    参考资料

    https://www.mobibrw.com/2019/20477

  • 相关阅读:
    解剖SQLSERVER 第十二篇 OrcaMDF 行压缩支持(译)
    解剖SQLSERVER 第十三篇 Integers在行压缩和页压缩里的存储格式揭秘(译)
    解剖SQLSERVER 第十四篇 Vardecimals 存储格式揭秘(译)
    解剖SQLSERVER 第十五篇 SQLSERVER存储过程的源文本存放在哪里?(译)
    解剖SQLSERVER 第七篇 OrcaMDF 特性概述(译)
    解剖SQLSERVER 第八篇 OrcaMDF 现在支持多数据文件的数据库(译)
    解剖SQLSERVER 第九篇 OrcaMDF现在能通过系统DMVs显示元数据(译)
    解剖SQLSERVER 第十篇 OrcaMDF Studio 发布+ 特性重温(译)
    解剖SQLSERVER 第十一篇 对SQLSERVER的多个版本进行自动化测试(译)
    解剖SQLSERVER 第三篇 数据类型的实现(译)
  • 原文地址:https://www.cnblogs.com/jwentest/p/11904192.html
Copyright © 2011-2022 走看看