Redis 连接池配置不当导致 TIME_WAIT 暴涨、端口被打满的排查与优化
前言
最近线上服务出现了一个比较典型的问题------服务器端口被打满,导致新连接无法建立。排查后发现根因是 Redis 客户端连接池配置不合理,产生了大量短连接,进而导致 TIME_WAIT 状态的连接持续堆积。
这里记录一下整个排查和优化过程,希望能帮到遇到类似问题的同学。
问题现象
线上告警显示服务出现连接异常,登录服务器后通过 netstat 统计 TIME_WAIT 状态的连接数:
bash
netstat -ant | awk '$6=="TIME_WAIT"{c++} END{print c}'
多次执行后发现,TIME_WAIT 连接数在持续攀升:
22644
22934
23499
22640
22775
24984
25503
26096
25853
26123
26630
27101
27518
27791
27146
27327
27858
28190
28638
28033
从 22k 一路涨到 28k+ ,而且没有回落趋势。Linux 默认的本地端口范围是 32768~60999,大约 28000 个端口,此时已经接近打满。
原因分析
排查发现问题出在 Redis 客户端的连接池配置上。原来的配置如下:
go
RdbClient = redis.NewClient(&redis.Options{
Addr: host + ":" + port,
Password: pass,
DB: db,
PoolSize: 100,
MinIdleConns: 10,
MaxIdleConns: 20,
})
这个配置存在几个关键问题:
1. PoolSize 过小
PoolSize: 100 意味着连接池最多持有 100 个连接。在高并发场景下,100 个连接远远不够用。当池内连接全部被占用时,客户端会创建新的连接来处理请求,而这些临时连接用完就关闭,变成了短连接。
2. 空闲连接管理不合理
MinIdleConns: 10、MaxIdleConns: 20 让连接池对空闲连接的保留非常"吝啬"。大量连接在空闲后迅速被回收,等下一波请求来了又得重新建连,造成连接的频繁创建和销毁。
3. 缺少空闲超时配置
没有设置 ConnMaxIdleTime,导致空闲连接的生命周期管理缺失。
核心矛盾
连接池容量不足 + 空闲连接回收过激 → 大量短连接 → TCP 四次挥手后进入 TIME_WAIT → TIME_WAIT 堆积 → 端口耗尽
简单回顾一下 TCP 的 TIME_WAIT 机制:主动关闭连接的一方会进入 TIME_WAIT 状态,默认持续 2 × MSL(通常 60 秒)。在这段时间内,这个端口是不可复用的。所以短连接越多,TIME_WAIT 堆积越严重。
优化方案
调整后的 Redis 客户端配置:
go
RdbClient = redis.NewClient(&redis.Options{
Addr: host + ":" + port,
Password: pass,
DB: db,
PoolSize: poolSize, // 可配置,按实际负载调整
MinIdleConns: 0, // 不强制维护空闲连接
ConnMaxIdleTime: idleTimeout, // 空闲连接超时释放
MaxActiveConns: poolSize * 2, // 限制最大活跃连接数
MaxConcurrentDials: 10, // 限制并发建连数
})
逐项说明:
| 参数 | 调整内容 | 目的 |
|---|---|---|
PoolSize |
固定值 → 可配置变量 | 根据业务实际并发量灵活调整 |
MinIdleConns |
10 → 0 | 避免维护不必要的空闲连接,减少资源浪费 |
ConnMaxIdleTime |
无 → idleTimeout |
让空闲连接有序超时释放,而非突然被回收后又立即重建 |
MaxActiveConns |
无 → poolSize * 2 |
给活跃连接加上天花板,防止突发流量下无限制创建新连接 |
MaxConcurrentDials |
无 → 10 | 限制并发建连的协程数,避免瞬间大量 dial 造成系统抖动 |
关键思路就是:提高连接复用率,减少短连接的产生。
效果
优化上线后,TIME_WAIT 连接数明显下降并趋于稳定,端口耗尽的问题不再出现。
小结
几个 takeaway:
- Redis 连接池的
PoolSize一定要根据实际并发量合理设置,不要拍脑袋给个固定小值 MinIdleConns和MaxIdleConns配置不当会导致连接频繁创建销毁,反而得不偿失- 别忘了配置
ConnMaxIdleTime,让空闲连接的回收有章可循 MaxActiveConns可以作为最后一道防线,防止连接数失控- 遇到端口耗尽问题,先用
netstat看 TIME_WAIT 数量,往往就能找到方向
希望这篇排查记录能对你有所帮助,如果有更好的优化思路,欢迎在评论区交流 🙌