TIME_WAIT过多解决方法

2023-05-16

 

之所以起这样一个题目是因为很久以前我曾经写过一篇介绍TIME_WAIT的文章,不过当时基本属于浅尝辄止,并没深入说明问题的来龙去脉,碰巧这段时间反复被别人问到相关的问题,让我觉得有必要全面总结一下,以备不时之需。

 

讨论前大家可以拿手头的服务器摸摸底,记住「ss」比「netstat」快:


shell> ss -ant | awk '
    NR>1 {++s[$1]} END {for(k in s) print k,s[k]}
'  

如果你只是想单独查询一下TIME_WAIT的数量,那么还可以更简单一些:


shell> cat /proc/net/sockstat  

我猜你一定被巨大无比的TIME_WAIT网络连接总数吓到了!以我个人的经验,对于一台繁忙的Web服务器来说,如果主要以短连接为主,那么其TIME_WAIT网络连接总数很可能会达到几万,甚至十几万。虽然一个TIME_WAIT网络连接耗费的资源无非就是一个端口、一点内存,但是架不住基数大,所以这始终是一个需要面对的问题。

为什么会存在TIME_WAIT?

TCP在建立连接的时候需要握手,同理,在关闭连接的时候也需要握手。为了更直观的说明关闭连接时握手的过程,我们引用「The TCP/IP Guide」中的例子:

TCP Close

TCP Close

因为TCP连接是双向的,所以在关闭连接的时候,两个方向各自都需要关闭。先发FIN包的一方执行的是主动关闭;后发FIN包的一方执行的是被动关闭。主动关闭的一方会进入TIME_WAIT状态,并且在此状态停留两倍的MSL时长。

穿插一点MSL的知识:MSL指的是报文段的最大生存时间,如果报文段在网络活动了MSL时间,还没有被接收,那么会被丢弃。关于MSL的大小,RFC 793协议中给出的建议是两分钟,不过实际上不同的操作系统可能有不同的设置,以Linux为例,通常是半分钟,两倍的MSL就是一分钟,也就是60秒,并且这个数值是硬编码在内核中的,也就是说除非你重新编译内核,否则没法修改它:


#define TCP_TIMEWAIT_LEN (60*HZ)  

如果每秒的连接数是一千的话,那么一分钟就可能会产生六万个TIME_WAIT。

为什么主动关闭的一方不直接进入CLOSED状态,而是进入TIME_WAIT状态,并且停留两倍的MSL时长呢?这是因为TCP是建立在不可靠网络上的可靠的协议。例子:主动关闭的一方收到被动关闭的一方发出的FIN包后,回应ACK包,同时进入TIME_WAIT状态,但是因为网络原因,主动关闭的一方发送的这个ACK包很可能延迟,从而触发被动连接一方重传FIN包。极端情况下,这一去一回,就是两倍的MSL时长。如果主动关闭的一方跳过TIME_WAIT直接进入CLOSED,或者在TIME_WAIT停留的时长不足两倍的MSL,那么当被动关闭的一方早先发出的延迟包到达后,就可能出现类似下面的问题:

  • 旧的TCP连接已经不存在了,系统此时只能返回RST包
  • 新的TCP连接被建立起来了,延迟包可能干扰新的连接

不管是哪种情况都会让TCP不再可靠,所以TIME_WAIT状态有存在的必要性。

如何控制TIME_WAIT的数量?

从前面的描述我们可以得出这样的结论:TIME_WAIT这东西没有的话不行,不过太多可能也是个麻烦事。下面让我们看看有哪些方法可以控制TIME_WAIT数量,这里只说一些常规方法,另外一些诸如SO_LINGER之类的方法太过偏门,略过不谈。

ip_conntrack:顾名思义就是跟踪连接。一旦激活了此模块,就能在系统参数里发现很多用来控制网络连接状态超时的设置,其中自然也包括TIME_WAIT:


shell> modprobe ip_conntrack
shell> sysctl net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait  

我们可以尝试缩小它的设置,比如十秒,甚至一秒,具体设置成多少合适取决于网络情况而定,当然也可以参考相关的案例。不过就我的个人意见来说,ip_conntrack引入的问题比解决的还多,比如性能会大幅下降,所以不建议使用。

tcp_tw_recycle:顾名思义就是回收TIME_WAIT连接。可以说这个内核参数已经变成了大众处理TIME_WAIT的万金油,如果你在网络上搜索TIME_WAIT的解决方案,十有八九会推荐设置它,不过这里隐藏着一个不易察觉的陷阱:

当多个客户端通过NAT方式联网并与服务端交互时,服务端看到的是同一个IP,也就是说对服务端而言这些客户端实际上等同于一个,可惜由于这些客户端的时间戳可能存在差异,于是乎从服务端的视角看,便可能出现时间戳错乱的现象,进而直接导致时间戳小的数据包被丢弃。参考:tcp_tw_recycle和tcp_timestamps导致connect失败问题。

tcp_tw_reuse:顾名思义就是复用TIME_WAIT连接。当创建新连接的时候,如果可能的话会考虑复用相应的TIME_WAIT连接。通常认为「tcp_tw_reuse」比「tcp_tw_recycle」安全一些,这是因为一来TIME_WAIT创建时间必须超过一秒才可能会被复用;二来只有连接的时间戳是递增的时候才会被复用。官方文档里是这样说的:如果从协议视角看它是安全的,那么就可以使用。这简直就是外交辞令啊!按我的看法,如果网络比较稳定,比如都是内网连接,那么就可以尝试使用。

不过需要注意的是在哪里使用,既然我们要复用连接,那么当然应该在连接的发起方使用,而不能在被连接方使用。举例来说:客户端向服务端发起HTTP请求,服务端响应后主动关闭连接,于是TIME_WAIT便留在了服务端,此类情况使用「tcp_tw_reuse」是无效的,因为服务端是被连接方,所以不存在复用连接一说。让我们延伸一点来看,比如说服务端是PHP,它查询另一个MySQL服务端,然后主动断开连接,于是TIME_WAIT就落在了PHP一侧,此类情况下使用「tcp_tw_reuse」是有效的,因为此时PHP相对于MySQL而言是客户端,它是连接的发起方,所以可以复用连接。

说明:如果使用tcp_tw_reuse,请激活tcp_timestamps,否则无效。

tcp_max_tw_buckets:顾名思义就是控制TIME_WAIT总数。官网文档说这个选项只是为了阻止一些简单的DoS攻击,平常不要人为的降低它。如果缩小了它,那么系统会将多余的TIME_WAIT删除掉,日志里会显示:「TCP: time wait bucket table overflow」。

需要提醒大家的是物极必反,曾经看到有人把「tcp_max_tw_buckets」设置成0,也就是说完全抛弃TIME_WAIT,这就有些冒险了,用一句围棋谚语来说:入界宜缓。

有时候,如果我们换个角度去看问题,往往能得到四两拨千斤的效果。前面提到的例子:客户端向服务端发起HTTP请求,服务端响应后主动关闭连接,于是TIME_WAIT便留在了服务端。这里的关键在于主动关闭连接的是服务端!在关闭TCP连接的时候,先出手的一方注定逃不开TIME_WAIT的宿命,套用一句歌词:把我的悲伤留给自己,你的美丽让你带走。如果客户端可控的话,那么在服务端打开KeepAlive,尽可能不让服务端主动关闭连接,而让客户端主动关闭连接,如此一来问题便迎刃而解了。

参考文档:

  1. tcp短连接TIME_WAIT问题解决方法大全(1)——高屋建瓴
  2. tcp短连接TIME_WAIT问题解决方法大全(2)——SO_LINGER
  3. tcp短连接TIME_WAIT问题解决方法大全(3)——tcp_tw_recycle
  4. tcp短连接TIME_WAIT问题解决方法大全(4)——tcp_tw_reuse
  5. tcp短连接TIME_WAIT问题解决方法大全(5)——tcp_max_tw_buckets
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TIME_WAIT过多解决方法 的相关文章

  • C 中经过的时间

    include
  • 什么时候 Thread.sleep(1000) 睡眠时间少于 1000 毫秒?

    在这篇有趣的文章中程序员对时间的看法是错误的 http infiniteundo com post 25509354022 more falsehoods programmers believe about time wisdom 其中之一
  • 如何在我的 Lua 脚本中添加“睡眠”或“等待”?

    我正在尝试通过更改一天中的时间来为游戏制作一个简单的脚本 但我想快速完成 这就是我要说的 function disco hour minute setTime 1 0 SLEEP setTime 2 0 SLEEP setTime 3 0
  • 请求完成时间大于 ActiveRecord 和 View 时间之和

    以下是一些示例请求完成时间 Completed 200 OK in 1054ms Views 10 8ms ActiveRecord 455 6ms Completed 200 OK in 1410ms Views 11 6ms Activ
  • 为什么 System.nanoTime() 比 System.currentTimeMillis() 慢(性能)?

    今天我做了一个快速基准测试来测试速度性能System nanoTime and System currentTimeMillis long startTime System nanoTime for int i 0 i lt 1000000
  • 计算轮班工作时间并检测

    我有个问题 我的英语很差 我需要用PHP做一个加班计算 已经有一个代码可以实现这一点 但当工作时间超过2天时 计算就会出错 工作开始 2018 09 09 13 43 工作结束 2018 09 11 07 13 结果 07 18 04 00
  • 将单独的月、日和年值转换为时间戳

    我有月份值 1 12 日期值 1 31 和年份值 2010 2011 2012 我还有一个小时值和一个分钟值 我怎样才能把这个给strtotime 它可以以某种方式将其转换为时间戳吗 当您已经知道年月和日期时 为什么将字符串转换为日期 us
  • PHP 中的 NOW() 函数

    是否有 PHP 函数以与 MySQL 函数相同的格式返回日期和时间NOW 我知道如何使用date 但我想问是否有专门用于此的功能 例如 返回 2009 12 01 00 00 00 您可以使用date https www php net m
  • 将 time.Time 转换为字符串

    我正在尝试将数据库中的一些值添加到 string在围棋中 其中一些是时间戳 我收到错误 无法在数组元素中使用 U Created date 类型 time Time 作为类型字符串 我可以转换吗time Time to string typ
  • 将 Python 中的日期与日期时间进行比较

    所以我有一个日期列表 datetime date 2013 7 9 datetime date 2013 7 12 datetime date 2013 7 15 datetime date 2013 7 18 datetime date
  • `SystemTime::now` 是否受夏令时影响?

    在时间 T 我调用SystemTime now duration since UNIX EPOCH 在时间 T 10 当夏令时开始时 我调用相同的调用 我可以预期这两个实例之间会出现任何奇怪的行为吗 SystemTime本身完全独立于时区
  • 获取特定时区一天开始时的时间对象

    如何获取代表给定时区特定日期的一天开始时间的 ruby Time 对象 date Date today date to time in time zone America New York beginning of day 目前输出 gt
  • CLOCKS_PER_SEC 与 std::clock() 的结果不匹配

    我正在使用以下短程序来测试std clock include
  • 除了在断点处停止之外,如何测量一大块代码的时间?

    我正在 Windows 上开发 C 游戏 模拟 图形应用程序 编辑开始 如果重要的话 我正在使用 Visual Studio 2013 编辑完 Setup 我正在使用 QueryPerformanceCounter 测量从一帧到下一帧的时间
  • 在旧版本的 MySQL (<5.5.0) 中模拟 TO_SECONDS()

    出于性能和简单性的原因 我想以秒的形式获取 MySQL 3 x 服务器中 DATETIME 列的内容 或者实际上任何数字类型 我只是想在使用 UNIX TIMESTAMP 时避免所有明显的时区问题 the我表中的日期确实来自不同的区域设置
  • Protractor:单击按钮后如何等待页面完成?

    在测试规范中 我需要单击网页上的按钮 然后等待新页面完全加载 emailEl sendKeys jack passwordEl sendKeys 123pwd btnLoginEl click Here need to wait for p
  • 处理时区转换的 JavaScript 库

    是否有一个 JavaScript 库可以处理时区转换 并考虑 DST 规则和此类内容 我知道有类似的问题 但我见过的问题似乎都没有真正适合我的问题的答案 我想在时区 A 创建一个日期并能够对其进行操作 添加天数 小时等 然后将其转换为另一个
  • PHP 时间间隔

    我正在寻找一个看起来应该非常简单的解决方案 但似乎我不能在这里找到任何好的答案 而且我自己似乎无法让它发挥作用 我正在寻找的是设置开始时间 结束时间 然后迭代给定时间间隔之间的一组时间 例如 上午 9 00 下午 5 00 是开始时间 这些
  • 计算 Spotfire 中同一列的时间差

    我是 Spotfire 的初学者 我对某些列值的差异计算有疑问 示例表可能是这样的 id timestamp state 1 7 1 2016 12 00 01 AM 1 2 7 1 2016 12 00 03 AM 0 3 7 1 201
  • jQuery 时间戳之前的时间?

    下面是一个非常好的 jQuery 插件 与他们在 SO 上使用的插件非常相似 对我来说问题是它用它来转换时间

随机推荐

  • android -- 蓝牙 bluetooth (四)OPP文件传输

    在前面android 蓝牙 bluetooth xff08 一 xff09 入门文章结尾中提到了会按四个方面来写这系列的文章 xff0c 前面已写了蓝牙打开和蓝牙搜索 xff0c 这次一起来看下蓝牙文件分享的流程 xff0c 也就是蓝牙应用
  • 智能制造:三体智能革命

    赵敏 宁振波 郭朝晖是走向智能研究院资深专家 xff0c 三体智能革命 编委会中三位重要作者 他们从去年5月起多次参加了中国工程院主持的 中国智能制造发展战略研究报告 的研讨 评审与修订工作 xff0c 对该报告的形成过程 研究主旨和详细内
  • 程序员读书和练习的方法(个人观点)

    lt 传送门 gt 针对本文的交流探讨 gt 总宗旨 xff1a 打好计算机通用理论基础 通用实战能力 xff0c 便于需要时对各领域的无障碍深钻 时间宝贵 xff0c 不要为了学习而学习 计算机通用理论基础 xff1a 计算机各领域理论基
  • 信息系统项目管理01——信息化和信息系统

    第一章 信息化和信息系统 考选择 xff0c 重要程度5颗星 文章目录 1 1 信息系统与信息化1 信息的质量属性 xff08 第3页 xff09 2 信息的传输模型 xff08 第4 5页 xff09 3 信息化从 小 到 大 分为5个层
  • 白话经典算法系列之七 堆与堆排序

    堆排序与快速排序 xff0c 归并排序一样都是时间复杂度为O N logN 的几种常见排序方法 学习堆排序前 xff0c 先讲解下什么是数据结构中的二叉堆 二叉堆的定义 二叉堆是完全二叉树或者是近似完全二叉树 二叉堆满足二个特性 xff1a
  • 当执行systemctl enable xxx.service时,报Failed to execute operation: Invalid argument

    Install 部分中的WantedBy 61 multi user target 看看有没有出现拼写输入错误
  • VR行业发展的前景和现状?

    标题 VR行业发展的前景和现状 xff1f 1 一个新事物的产生 xff0c 总是伴随着看好和唱衰两种声音 这两种态度自然有其可以理解的地方 xff0c 因为摆在我们面前的是未知 xff0c 而坐在餐桌前的两拨人 xff0c 站在不同的角度
  • class path resource [templates/] cannot be resolved to absolute file path because it does not reside

    报错 xff1a 在运行springcloud代码的时候报错 xff0c 但是不影响正常启动 分析 xff1a 经过谷歌和百度发现FreeMarkerConfigurationFactory中存在以下方法 xff1a span class
  • write javaBean error, fastjson version 1.2.68, class org.springframework.web.multipart.support.Stand

    一 问题背景 这两天在springboot项目中遇到个让人摸不着头脑的问题 xff0c 一个接口准备上传excel文件并解析到数据库中 xff0c 结果运行的时候报错了 xff0c 具体信息如下 xff1a ERROR span class
  • CommandNotFoundError: Your shell has not been properly configured to use ‘conda activate‘. To initia

    64 CommandNotFoundError Your shell has not been properly configured to use conda activate To initialize your shell run c
  • android -- 蓝牙 bluetooth (五)接电话与听音乐

    前段时间似乎所有的事情都赶在一起 xff0c 回家 集体出游 出差 xff0c 折腾了近一个月 xff0c 终于算暂时清静了 xff0c 但清静只是暂时 xff0c 估计马上又要出差了 xff0c 所以赶紧把蓝牙这一部分的文章了结下 xff
  • anaconda使用国内数据源

    anaconda后默认走的是官方镜像 xff0c 但是相对来说 xff0c 不使用翻墙软件的话还是使用国内源下载会比较便捷 默认镜像 xff1a span class token operator span https span class
  • flink消费kafka数据写入阿里hologres(java版)

    一 需求背景概述 由于公司业务需要将kafka的数据写入到hologres中 xff0c 但是发现flinksql那种简便的方式会各种报错 很有可能是我包引用的不对 xff0c 但是找了阿里支持也没有解决 xff0c 无奈只能使用flink
  • linux和本地(mac)之间的文件传输

    一 使用SecureCRT的sftp传输 xff08 推荐 xff09 SecureCRT安装在这里就不介绍了 xff0c 大家可以参考一下这篇文章 xff1a https blog csdn net so geili article de
  • hbase的介绍及使用

    一 hbase简介 1 hbase产生背景 以前Google存储大量的网页信息 xff0c 如何存储 xff0c 如何计算 xff0c 如何快速查询就成为了一个问题 xff0c 后来在2003年Google发表了3篇论文提供了解决思路 xf
  • scala学习第三篇之类型参数(泛型)

    概述 xff1a 类型参数 xff0c 说白了就是泛型 xff0c 什么是泛型 xff1f 广泛的类型 xff0c 啥类型都有可能 xff0c 是一种更加通用的表示 xff0c 或者定义 Scala中定义泛型的方式和java中稍微有点不同
  • idea如何引入同级本地module中的类

    一 工程目录结构如图所示 其中 xff0c spark study是父module xff0c spark commen spark core是子module 2 需求 在spark core中需要使用spark commen中的类 xff
  • linux下双击执行.sh脚本文件

    1 当写好一个 sh脚本文件后 xff0c 给他赋予执行权限后 xff0c 双击的时候 xff0c 默认是以文本编辑器打开的 xff0c 无法运行该脚本文件 2 打开终端 3 输入如下命令 xff0c 需要联网 xff1a sudo apt
  • H5实现微信分享

    H5页面如何实现微信分享功能 微信分享文档地址 xff1a https developers weixin qq com doc offiaccount OA Web Apps JS SDK html 步骤一 xff1a 绑定域名 xff0
  • TIME_WAIT过多解决方法

    之所以起这样一个题目是因为很久以前我曾经写过一篇介绍TIME WAIT的文章 xff0c 不过当时基本属于浅尝辄止 xff0c 并没深入说明问题的来龙去脉 xff0c 碰巧这段时间反复被别人问到相关的问题 xff0c 让我觉得有必要全面总结