目录
1. 前言
在日常运维工作中,有一种场景比较常见,就是用nginx做为反向代理服务器对外提供服务,在高并发的场景中,最容易出现批量的 TIME_WAIT,从而导致服务不可用,下面,围绕这个场景展开话题
2. 情景描述
在使用nginx做反代的时候,当访问量较多,处于高并发的场景,TCP 会出现很多 TIME_WAIT的连接:
一段时间后,大部分 TIME_WAIT 会消失或全部消失,TCP连接被回收,一般情况下,这是正常的现象,但是在一些极端情况下,持续长时间的高并发,会出现大量的 TIME_WAIT,当TCP连接数总数超过65535时,新建立的TCP会话就会失败,提示connect异常等(所以有时候,可能 time_wait 只有两三万,但服务已不可用了)
TCP连接状态统计
netstat -antp|awk '{ print $6}' |sort |uniq -c |sort -rn
3. 问题分析
上面的问题主要从几方面来分析
nginx做反向代理时,当有大量的短连接时,会导致 TCP 连接处于 TIME_WAIT状态(这是正常的),但持续高并发的场景, 部分 TIME_WAIT 连接被回收,但新的 TIME_WAIT 连接还接连产生,每一个 TCP 连接,将占用一个本地端口(上限65535),释放的连接跟不上新产生的连接,从而导致连接数爆了。
因此,总结根本原因是
- 存在大量短连接
- 等待 TIME_WAIT回收时间过长,跟不上新增的会话速度,Time_Wait的默认时间是2倍的MLS,就是240秒钟
4. 问题解决
解决上述场景的问题,可以从以下方面进行
- 开启 HTTP keep-alive,保持存活时间
- 开启 time_wait 状态的 socket 重用
- 缩减 time_wait 时间,Time_Wait的默认时间是2倍的MLS,就是240秒钟
5. 概念术语
5.1 TCP主要状态详解
状态 | 说明 |
SYN-SENT(客户端发起时状态) | 发送连接请求后等待匹配的连接请求,连接成功了就变为ESTABLISHED,正常情况下SYN_SENT状态非常短暂,当发现有很多SYN_SENT出现时,可能 是中毒了在扫描其他机器,也有可能是被扫描中 |
SYN_RCVD(服务端接收) | 等待连接,如果连接成功了就变为ESTABLISHED,正常情况下SYN_RCVD状态非常短暂,收到大量的SYN_RCVD,则有可能被SYN Flood攻击了 |
ESTABLISHED | 连接建立状态 |
FIN-WAIT-1 | 等待远程TCP连接中断请求,或先前的连接中断请求的确认 |
FIN-WAIT-2 | FIN-WAIT-2 |
CLOSE-WAIT | 等待从用户发来的连接中断请求 |
LAST-ACK | 等待连接中断请求的确认 |
TIME-WAIT | 等待远程TCP接收到连接中断请求的确认 |
5.2 TCP状态路线图
客户端发起连接和关闭连接时的状态:
客户端 -> SYN_SENT -> ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT -> 会话结束
服务器提供服务和关闭连接是的状态:
服务端 -> SYN_RCVD -> ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> 会话结束
从上面可以看出,一个正常的客户请求到服务端响应,建立会话连接的过程到最终会话结束的时候的一个完整路线。
附件
- TCP三次握手和四次挥手原理图
- TCP三次握手用于建立连接
TCP四次握手用于关闭连接