关于Titm_Wait优化,必须要了解的……

服务器
TIME-WAIT是服务器优化必然会谈到的一个话题,而我们常见的问题就是TIME-WAIT过多怎么处理?

[[404167]]

哈喽哈喽大家好,今天要说的话题是关于TCP的TIME-WAIT状态

TIME-WAIT是服务器优化必然会谈到的一个话题,而我们常见的问题就是TIME-WAIT过多怎么处理?

常见的解决方法就是:

1、快速回收

2、链接复用

而这里有个误区就是到底TIME-WAIT要优化到什么程度,有的童鞋甚至看到TIME-WAIT就觉得需要优化,今天就是想聊一下这个话题

要聊明白,还是要从原理来说起

TIME-WAIT是TCP链接的一种状态,之前有写文章介绍过TCP的11中链接状态,有兴趣可以再去看下

这张图整个展示了所有状态的转换过程,总共分为三个部分,上半部分是建立连接的过程,下面部分分成主动关闭和被动关闭的过程

可以看到TIME_WAIT只在主动关闭的过程中出现,实际上TIME_WAIT是TCP为了解决复杂的网络问题提出的一种解决方案

解决什么问题呢?看下面两个场景

  • 四次挥手中,A 发 FIN, B 响应 ACK,B 再发 FIN,A 响应 ACK 实现连接的关闭。而如果 A 响应的 ACK 包丢失,B 会以为 A 没有收到自己的关闭请求,然后会重试向 A 再发 FIN 包。

如果没有 TIME_WAIT 状态,A 不再保存这个连接的信息,收到一个不存在的连接的包,A 会响应 RST 包,导致 B 端异常响应。

此时, TIME_WAIT 是为了保证全双工的 TCP 连接正常终止。

  • 我们还知道,TCP 下的 IP 层协议是无法保证包传输的先后顺序的。如果双方挥手之后,一个网络四元组(src/dst ip/port)被回收,而此时网络中还有一个迟到的数据包没有被 B 接收,A 应用程序又立刻使用了同样的四元组再创建了一个新的连接后,这个迟到的数据包才到达 B,那么这个数据包就会让 B 以为是 A 刚发过来的。

此时, TIME_WAIT 的存在是为了保证网络中迷失的数据包正常过期。

第一种场景下,TIME_WAIT是为了确保被动关闭方收到ACK,连接正常关闭,且不因被动关闭方重传FIN影响下一个连接

第二种场景下,TIME_WAIT保留2个MSL,以确保数据不会丢失

注释:MSL(Maximum Segment Lifetime) 最大分段寿命,它表示一个TCP分段可以存在于互联网系统中的最大时间,由TCP实现,超出这个寿命的分段都会被丢弃,RFC 1122建议是2分钟,但在不同的unix实现上,这个值并不确定

由于以上的两种场景,TCP引入了TIME_WAIT状态来解决,由此可见TIME_WAIT并不是完全不存在才是合理的或以消除TIME_WAIT为优化的一个目标

那么TIME_WAIT具体要怎么优化,什么样的状态是一个合理的状态?

我们还是看常用的两种优化方法,先说不建议使用的一种:快速回收

由上面可知,TIME_WAIT的时长是2MSL,按照RFC建议2分钟的话,就是4分钟,对于高并发的服务器来说,本身local_port就有固定的量,如果4分钟才回收TIME_WAIT,那么端口很快就会被用尽

尽管CentOS系统中,MSL可以通过修改参数tcp_fin_timeout来设置MSL的时间,默认是30s,这样的话,一个四元组(local_ip, local_port, remote_ip,remote_port)会被冻结60s的时间,系统默认可分配端口约30000个,可通一下文件查看过

  1. /proc/sys/net/ipv4/ip_local_port_range 

那么从同一个客户端发起请求,并发只能到500QPS左右

所以提出了快速回收的方法,即TCP连接状态在TIME_WAIT状态的时候,立即回收连接,不等待2MSL,以快速回收资源用于新的连接

而快速回收的弊端,相信都有了解,就是关于快速回收引发的SYN无法得到ACK的问题,具体如下:

TCP有一种行为,可以缓存每个连接最新的时间戳,后续请求中如果时间戳小于缓存的时间戳,即视为无效,相应的数据包会被丢弃。Linux是否启用这种行为取决于tcp_timestamps和tcp_tw_recycle,因为tcp_timestamps缺省就是开启的,所以当tcp_tw_recycle被开启后,实际上这种行为就被激活了。在nat环境中会出现时间戳错乱的情况,后面的数据包就被丢弃了,具体的 表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK。因为NAT设备将数据包的源IP地址都改成了一个地址(或者少量的IP地址),但是却基本上不修改TCP包的时间戳,则会导致时间戳混乱

建议:如果前端部署了三/四层NAT设备,尽量关闭快速回收,以免发生NAT背后真实机器由于时间戳混乱导致的SYN拒绝问题

而另一种优化方式就是建议的方式:复用

由上面的分析可以确定,并发上不去是因为四元组被冻结2MSL时长导致没有新的资源可用,而四元组在被冻结的时间内是不能被使用的,所以提出了复用的方式,但是复用是有前提的,它需要tcp_timestamps同时开启,看下内核关于这部分的代码

reuse的前提是收到最后一个包后超过1s,所以正常的情况下开启reuse是可以达到快速复用TIME_WAIT状态的socket链接的,而且也不会有像recycle那样的“副作用”

除了以上两种解决TIME_WAIT的方式,还有一个参数是必须要关注的,就是tw_buckets,可以通过

  1. cat /proc/sys/net/ipv4/tcp_max_tw_buckets 

查看该参数值,这个值是TIME_WAIT可以达到的最大数量,当TIME_WAIT存在的数量和tcp_max_tw_buckets相同时,会处于tw_buckets溢出状态,默认是4096

当弃用reuse的时候,在一个高并发的服务器上,TIME_WAIT并不会快速回收,而是复用之前的链接,这样的情况下TIME_WAIT必然会保持一定的数量,那么tw_buckets就很关键,如果按照local_port在3w左右,那么tw_buckets如果是默认4096的情况下,TIME_WAIT也会很快到达瓶颈,无法再增加

所以应该保持tw_buckets至少在local_port之上,虽然长时间大量TIME_WAIT会消耗一定的内存资源,但是对于现在的服务器,TIME_WAIT所占用的内存是可以容忍的

总结:

结合上面的分析,recycle在内核4.1以后就被弃用了,所以它并不是TIME_WAIT优化的最好方案,最好的方式就是通过reuse进行复用,复用的前提是开启tcp_timestamps,并且要关注tw_buckets溢出的情况,适当增加tw_buckets,以应对并发量

本文转载自微信公众号「运维研习社」,可以通过以下二维码关注。转载本文请联系运维研习社公众号。

 

责任编辑:武晓燕 来源: 运维研习社
相关推荐

2018-09-21 11:11:34

备份离线自动

2018-11-08 12:07:38

备份手动磁盘

2015-10-23 15:22:16

AsyncTask基础Android

2011-06-23 17:13:07

SEO

2016-12-23 08:59:00

AB 测试CRO

2023-04-26 16:34:12

2017-10-29 06:50:30

前端开发CSSWeb

2022-01-26 23:16:25

开源NLP 库GitHub

2018-07-12 11:11:46

人工智能AI术语

2021-04-27 22:27:19

手机安卓苹果

2018-04-19 13:43:15

区块链人工智能Go语言

2017-09-22 06:58:06

窄带物联网NB-IoT物联网

2024-02-23 18:32:17

2018-09-25 08:33:38

数据库锁JavaSQL

2010-08-11 13:07:50

DB2china

2010-08-02 11:33:17

IBM DB2

2018-08-03 15:30:33

2019-06-20 17:39:12

Android启动优化

2019-12-24 10:19:44

泛型反射注解

2021-09-05 08:46:29

CSPM网络安全网络攻击
点赞
收藏

51CTO技术栈公众号