【转】记一次TIME_WAIT网络故障

本文涉及的产品
公网NAT网关,每月750个小时 15CU
简介:

前段时间,组里遇到个问题:线上某个业务出现了短连接太多,造成tw_bucket溢出。

这个问题比较常见,网上常见的方法有开启reuse和快速回收(对于NAT结构的网络,慎重开启快速回收和reuse这2个参数,具体原因可以自行百度)。


出于复习下基础知识的目的,网上找了篇博客,


下面是原始博文地址:https://huoding.com/2012/01/19/142  【火丁笔记,里面介绍了很多调优、故障排查的方法】

直接贴他的博文吧:


--  原文从下面开始

最近发现一个PHP脚本时常出现连不上服务器的现象,调试了一下,发现是TIME_WAIT状态过多造成的,本文简要介绍一下解决问题的过程。

遇到这类问题,我习惯于先用strace命令跟踪了一下看看:

shell> strace php /path/to/file
EADDRNOTAVAIL (Cannot assign requested address)

从字面结果看似乎是网络资源相关问题。这里顺便介绍一点小技巧:在调试的时候一般是从后往前看strace命令的结果,这样更容易找到有价值的信息。

查看一下当前的网络连接情况,结果发现TIME_WAIT数非常大:

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

补充一下,同netstat相比,ss要快很多:【备注:使用ss -s 命令也可列出概览,但是不如awk这种显示优雅 】

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

重复了几次测试,结果每次出问题的时候,TIME_WAIT都等于28233,这真是一个魔法数字!实际原因很简单,它取决于一个内核参数net.ipv4.ip_local_port_range:

shell> sysctl -a | grep port
net.ipv4.ip_local_port_range = 32768 61000

因为端口范围是一个闭区间,所以实际可用的端口数量是:

shell> echo $((61000-32768+1))
28233

问题分析到这里基本就清晰了,解决方向也明确了,内容所限,这里就不说如何优化程序代码了,只是从系统方面来阐述如何解决问题,无非就是以下两个方面:

首先是增加本地可用端口数量。这点可以用以下命令来实现:

shell> sysctl net.ipv4.ip_local_port_range="10240 61000"

其次是减少TIME_WAIT连接状态。网络上已经有不少相关的介绍,大多是建议:

shell> sysctl net.ipv4.tcp_tw_reuse=1
shell> sysctl net.ipv4.tcp_tw_recycle=1

注:通过sysctl命令修改内核参数,重启后会还原,要想持久化可以参考前面的方法。

这两个选项在降低TIME_WAIT数量方面可以说是立竿见影,不过如果你觉得问题已经完美搞定那就错了,实际上这样可能会引入一个更复杂的网络故障。

关于内核参数的详细介绍,可以参考官方文档。我们这里简要说明一下tcp_tw_recycle参数。它用来快速回收TIME_WAIT连接,不过如果在NAT环境下会引发问题。

RFC1323中有如下一段描述:

An additional mechanism could be added to the TCP, a per-host cache of the last timestamp received from any connection. This value could then be used in the PAWS mechanism to reject old duplicate segments from earlier incarnations of the connection, if the timestamp clock can be guaranteed to have ticked at least once since the old connection was open. This would require that the TIME-WAIT delay plus the RTT together must be at least one tick of the sender’s timestamp clock. Such an extension is not part of the proposal of this RFC.

大概意思是说TCP有一种行为,可以缓存每个主机最新的时间戳,后续请求中如果时间戳小于缓存的时间戳,即视为无效,相应的数据包会被丢弃。

Linux是否启用这种行为取决于tcp_timestamps和tcp_tw_recycle,因为tcp_timestamps缺省就是开启的,所以当tcp_tw_recycle被开启后,实际上这种行为就被激活了,当客户端或服务端以NAT方式构建的时候就可能出现问题,下面以客户端NAT为例来说明:

当多个客户端通过NAT方式联网并与服务端交互时,服务端看到的是同一个IP,也就是说对服务端而言这些客户端实际上等同于一个,可惜由于这些客户端的时间戳可能存在差异,于是乎从服务端的视角看,便可能出现时间戳错乱的现象,进而直接导致时间戳小的数据包被丢弃。如果发生了此类问题,具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK,我们可以通过下面命令来确认数据包不断被丢弃的现象:

shell> netstat -s | grep timestamp
... packets rejects in established connections because of timestamp

安全起见,通常要禁止tcp_tw_recycle。说到这里,大家可能会想到另一种解决方案:把tcp_timestamps设置为0,tcp_tw_recycle设置为1,这样不就可以鱼与熊掌兼得了么?可惜一旦关闭了tcp_timestamps,那么即便打开了tcp_tw_recycle,也没有效果。

好在我们还有另一个内核参数tcp_max_tw_buckets(一般缺省是180000)可用:

shell> sysctl net.ipv4.tcp_max_tw_buckets=100000

通过设置它,系统会将多余的TIME_WAIT删除掉,此时系统日志里可能会显示:「TCP: time wait bucket table overflow」,不过除非不得已,否则不要轻易使用。

总体来说,这次网络故障本身并没什么高深之处,本不想罗罗嗦嗦写这么多,不过拔出萝卜带出泥,在过程中牵扯的方方面面还是值得大家品味的,于是便有了这篇文字。










本文转自 lirulei90 51CTO博客,原文链接:http://blog.51cto.com/lee90/2065987,如需转载请自行联系原作者
相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
目录
相关文章
|
11月前
|
网络协议 Cloud Native
为什么需要 TIME_WAIT 状态
为什么需要 TIME_WAIT 状态
为什么需要 TIME_WAIT 状态
|
SQL druid 关系型数据库
MySQL连接超时时间wait_timeout导致间歇性报错:communication link failure
MySQL连接超时时间wait_timeout导致间歇性报错:communication link failure
786 1
|
测试技术 开发者
压测场景下的 TIME_WAIT 处理
压测场景下的 TIME_WAIT 处理
压测场景下的 TIME_WAIT 处理
|
弹性计算 负载均衡 网络协议
为何客户端突然出现大量TIME_WAIT堆积
本文介绍了一个在阿里云环境下某客户端ECS机器上突然发现TIME_WAIT突然增高的问题和排查过程。通过问题分析介绍了TCP TIME_WAIT快速回收的代码逻辑,以及TCP timestamps option字段对快速回收的影响。
为何客户端突然出现大量TIME_WAIT堆积
|
网络协议 测试技术
TIME_WAIT过多及解决
最近用http_load做压测,跑出来一大串“Cannot assign requested address ”的错误,查了一下,是TIME_WAIT过多导致的。因为短时间内有太多连接,所以占用了大量端口,同时关闭连接后又处于TIME_WAIT状态,端口不能复用,所以慢慢的无端口可用,所以就“Cannot assign requested address”了。
1112 1
|
数据采集 网络协议
一次TIME_WAIT和CLOSE_WAIT故障和解决办法
昨天解决了一个curl调用错误导致的服务器异常,具体过程如下: 里头的分析过程有提到,通过查看服务器网络状态检测到服务器有大量的CLOSE_WAIT的状态。   在服务器的日常维护过程中,会经常用到下面的命令:   它会显示例如下面的信息: TIME_WAIT 814CLOSE_WAIT 1FIN_WAIT1 1ESTABLISHED 634SYN_RECV 2LAST_ACK 1 常用的三个状态是:ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。
2705 0
|
网络协议 Linux PHP
TCP TIME_WAIT状态解析及问题解决
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhaobryant/article/details/80557158 一、TCP四次挥手过程 TCP在建立连接时需要握手,同理,在关闭连接的时候也需要握手。
2586 0
|
网络协议 测试技术 Go
|
Web App开发 网络协议 关系型数据库
|
网络协议 开发工具 Perl