Redis连接数打满,客户端泄漏
Redis 连接数被打满时,服务端会拒绝新的连接请求,客户端报 ERR max number of clients reached,整个业务链路随之变慢甚至不可用。
这类问题最常见的原因有两个:客户端获取连接后没有正确释放,以及服务端 timeout 参数配置不当。
下面按真实故障排查顺序,从确认现状到修复调优逐步操作,手把手带你解决问题。
先确认连接数到底卡在哪一步
登录 Redis 服务器,执行 redis-cli 进入命令行,先看当前连接状态:
redis-cli INFO clients
重点关注 connected_clients 和 blocked_clients。
如果 connected_clients 已经接近或等于配置上限,说明连接池确实被占用完。
再查看最大连接数限制:
redis-cli CONFIG GET maxclients
确认是连接数真的打满后,下一步要弄清楚这些连接是从哪里来的。
如果你的 Redis 没有设置密码,建议先加一层保护,否则外部扫描器很容易通过暴力连接占满连接数。
检查方式:
redis-cli CLIENT LIST
观察输出中的 addr 字段,也就是客户端 IP 和端口。
如果大量连接来自同一个内网应用服务器,那基本可以判定是该应用内存有连接泄漏;
如果来自公网陌生 IP,则要考虑安全策略问题。
定位并修复客户端连接泄漏
客户端连接泄漏通常发生在连接池使用不当的场景。
以 Java 的 Jedis 和 Lettuce 为例,常见错误是每次请求都新建连接,却没有在 finally 块中归还或关闭连接;
或者连接池的 maxTotal 设置过小,高峰时所有连接被借出后等待归还,造成连接积压。
先检查你的连接池配置。
以 JedisPool 为例,核心参数如下:
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(50);
config.setMaxIdle(20);
config.setMinIdle(5);
config.setMaxWaitMillis(3000);
如果应用代码在获取 Jedis 实例后没有放入 try-finally 中归还,连接就会一直被占用。
正确写法:
try (Jedis jedis = pool.getResource()) {
jedis.set("key", "value");
}
使用 try-with-resources 后,无论正常执行还是抛异常,连接都会自动归还到池中。
如果你用的框架是 Spring Boot 默认的 Lettuce,同样要注意连接池配置,在 application.yml 中开启连接池:
spring:
redis:
lettuce:
pool:
max-active: 50
max-idle: 20
min-idle: 5
max-wait: 3000ms
排查时还可以借助 CLIENT LIST 输出里的 age 和 idle 字段。
如果大量连接 age 很大且 idle 也很长,说明这些连接被创建后一直没被复用,基本可以判断为泄漏或池配置不合理。
调整 Redis timeout 参数释放空闲连接
当确认代码层面没有明显泄漏后,
仍然可能因为 timeout 参数设置过大,
导致大量空闲连接长期占用服务端资源。timeout 表示客户端空闲多少秒后,
服务端主动断开连接,
默认值通常是 0,
也就是永不断开。
登录 redis-cli 查看当前值:
redis-cli CONFIG GET timeout
建议将 timeout 设置为 300 秒,同时配合 tcp-keepalive 让服务端主动检测死连接:
redis-cli CONFIG SET timeout 300
redis-cli CONFIG SET tcp-keepalive 60
但注意,CONFIG SET 只对当前实例生效,重启后就会丢失。
要想永久生效,需要修改 redis.conf 文件,找到这两行:
timeout 300
tcp-keepalive 60
如果没有 tcp-keepalive 配置项,直接补充到文件末尾即可。
修改后重启 Redis 服务:
systemctl restart redis
这里有一个容易踩坑的点:timeout 设置过小会导致短连接应用频繁断线,比如某些连接池 idel 检测周期较长,连接被服务端回收后客户端仍在使用,反而引发报错。
所以建议先从 300 开始观察,如果业务允许再逐渐缩短到 120 或 60。
客户端侧的超时配置同样重要,比如 Jedis 的 connectionTimeout 和 soTimeout 不要设置过大,否则应用会长时间阻塞等待 Redis 响应。
修改后的验证与日常监控
调优完成后,需要确认连接数是否回归到合理范围。
继续在 redis-cli 中执行:
redis-cli INFO clients
观察 connected_clients 是否明显下降。
想要更直观地观察动态变化,可以开启 Redis 慢查询日志和状态监控:这里推荐使用 redis-cli --stat 实时刷新关键指标:
redis-cli --stat
这个命令会每秒钟输出一次连接数、内存和命中率等数据,非常适合运维排查时观察。
日常监控层面,建议在应用服务器上配置脚本,定期采集 Redis 连接数,当 connected_clients 超过 80% 的 maxclients 时触发告警。
两个容易被忽略的细节
排查过程中还有两个细节经常被忽略。
一是 Redis 的 maxclients 默认值只有 10000(部分发行版可能更小),如果业务并发高,即使没有泄漏也很容易打满,可以根据实际内存和文件句柄数适当调大,比如设置为 20000。
改完后同样要同步到 redis.conf。
二是如果应用和 Redis 之间有负载均衡或代理(如 Twemproxy、Codis),连接打满的根因可能不直接来自业务代码,而是代理层没有正确释放后端连接。
这种情况需要查看代理的日志和连接池配置,不要只盯着 Redis 服务端调参。
遇到 Redis 连接数持续上涨、偶发连接超时报错时,按照本文的排查顺序,先看 CLIENT LIST 定位连接来源,再整改客户端连接池,最后调整服务端 timeout 和 tcp-keepalive,大多数问题都能在半小时内解决。
如果调优后依然异常,建议抓取应用栈信息,确认是否有长时间阻塞的 Redis 调用,再做进一步优化。