Python中redis-py连接池导致服务器大量CLOSE_WAIT问题的再讨论与解决方案
今天服务器突然提示一台 redis 无法连接了 登上去一看 发现到这个 redis 服务器的连接基本都是 CLOSE_WAIT 状态 有十几万条 导致没法再建立新的连接
至于 redis 的用法也是 很传统的用法 就是服务启动的时候会初始化一个 redis.StrictRedis 的连接 然后就直接用
至于连接池 其实 StrictRedis 内部的实现就是用连接池的
后来查了 google 发现这个
http://russellluo.com/2017/10/redis-py-pool-cannot-handle-idle-close-wait-connections.html
v2 上也有人发过讨论: https://www.v2ex.com/t/237326 但没有提供解决方案
参考了第一个的方案 改进了一下 redis 连接池的 get_connection 方法 更新上去之后 效果很明显 确保了一个进程一条连接 失效了重新建立新的连接
看起来很完美的样子
我的疑问就是 既然都有这个问题 也有解决方案在那里 为什么这个 issue 都没人关注呢 还是大家都没遇到过这个问题吗
Python中redis-py连接池导致服务器大量CLOSE_WAIT问题的再讨论与解决方案
这叫我想起来之前遇到过的数据库连接未释放的问题了,关注生命周期是关键
这个问题我遇到过,redis-py的连接池管理不当确实容易导致CLOSE_WAIT堆积。核心原因是连接没有正确释放,导致TCP连接处于半关闭状态。
先看一个典型的问题代码:
import redis
import time
# 错误示例:每次请求都创建新连接池
def get_data_bad():
pool = redis.ConnectionPool(host='localhost', port=6379)
r = redis.Redis(connection_pool=pool)
return r.get('key')
# 正确做法:复用全局连接池
pool = redis.ConnectionPool(host='localhost', port=6379, max_connections=10)
def get_data_good():
r = redis.Redis(connection_pool=pool)
try:
return r.get('key')
finally:
r.connection_pool.release(r.connection_pool.get_connection('localhost', 6379))
关键点:
- 连接池复用:不要每次操作都创建新连接池,应该全局共享一个
- 连接释放:使用完连接后要显式释放回连接池
- 连接池配置:合理设置max_connections,避免连接数过多
更推荐的做法是使用上下文管理器:
from contextlib import contextmanager
@contextmanager
def get_redis_connection():
conn = pool.get_connection('localhost', 6379)
try:
yield conn
finally:
pool.release(conn)
# 使用方式
with get_redis_connection() as conn:
r = redis.Redis(connection=conn)
result = r.get('key')
如果已经出现CLOSE_WAIT,可以用ss -tan或netstat命令查看状态,然后重启应用强制释放连接。
总结:确保连接池单例且正确释放连接。
redis-py 真是想各种吐槽
- 连接池不能负载均衡
- 连接池不能读写分离
- zadd 不支持 nx 等参数
- zadd 那个坑死无数新人的参数顺序。
你们用都不看源码的么 那个链接池简陋得连心跳都没 你们也直接用
#3 源码看了 确实简陋 有别的选择吗 基本都在用这个库的吧
#2 确实 有更好的库可以选择吗
当然自己重新封装 自己写心跳啊
如果发现已经有 Pull Request,+1 求合并就好了,求合并的人多了,自然受重视
如果只是默默吐槽,那就不怪别人了
没用的 对比下 kombu 的代码 就知道了 这玩意就是个基本接口根本没打算做全功能
就算是 kombu openstack 还再封装过一遍

