连接池耗尽是配置失效、连接泄漏或参数错配的综合结果;需通过日志异常、netstat验证真实连接数、redis-cli info clients比对maxclients、Actuator指标及Spring Boot版本对应配置路径(2.x用spring.redis.lettuce.pool,3.x用spring.data.redis.lettuce.pool)精准定位,并排查Jedis未close、RedisTemplate绕过使用、异步线程未释放等泄漏点。

连接池耗尽不是配置没加,而是配置失效、连接泄漏或参数错配的综合结果。 直接看日志里有没有 Cannot get Jedis connection 或 RedisConnectionFailureException,再查 netstat -an | grep :6379 —— 如果 ESTABLISHED 连接数远超 max-active 值,基本可断定是泄漏或保活机制没起作用。
确认连接池是否真的被占满
别只信监控面板数字。真实连接数得从操作系统层面验证:
- 执行
netstat -an | grep :6379 | grep ESTABLISHED | wc -l,对比spring.data.redis.lettuce.pool.max-active值;如果前者显著更大,说明连接没归还或物理连接未回收 - 用
redis-cli info clients查connected_clients,若该值持续接近 Redis 服务端maxclients上限,说明服务端也快扛不住了 - Spring Boot Actuator 的
/actuator/metrics/redis.clients.used指标(需启用 micrometer)比日志更及时,但前提是应用没卡死在连接获取阶段
检查 Spring Boot 版本对应的配置路径是否正确
Spring Boot 2.x 和 3.x 的 Redis 连接池配置路径完全不同,旧配置会静默失效:
- Spring Boot 2.x 使用
spring.redis.lettuce.pool.max-active - Spring Boot 3.x 必须写成
spring.data.redis.lettuce.pool.max-active(注意多了data) - 如果配置路径错,Lettuce 会回退到默认值
max-active=8,高并发下几秒就打满 - 用
spring-boot:run启动时加--debug参数,搜索日志里是否有Bound to property 'spring.data.redis.lettuce.pool'类似行,确认配置是否被加载
排查连接泄漏的三个关键代码点
即使配置合理,手动操作连接仍极易泄漏:
- 用
Jedis时没在finally块调用jedis.close(),或用了 try-with-resources 却没实现AutoCloseable接口(老版本 JedisPool 不支持) - 用
RedisTemplate却绕过它直接调factory.getConnection(),之后没调connection.close() - 在异步线程(如
@Async方法)里操作 Redis,但没确保连接在该线程结束前释放 —— Lettuce 的连接绑定线程局部变量,跨线程不自动归还
验证空闲连接是否被有效驱逐
Lettuce 默认不检测空闲连接有效性,网络抖动后大量半死连接滞留池中:
- 必须显式开启保活:
spring.data.redis.lettuce.pool.test-while-idle=true - 搭配
time-between-eviction-runs=30000(每30秒扫描)和min-evictable-idle-time-millis=60000(空闲超60秒才驱逐) - 注意:若 Redis 禁用了
PING命令(如安全策略限制),test-while-idle会失效,此时要靠connect-timeout和timeout双重兜底 - 观察日志里是否频繁出现
Connection closed或RedisCommandTimeoutException,这是驱逐机制生效的信号,也是泄漏正在被清理的迹象
真正难处理的不是连接池配多大,而是连接什么时候该释放、由谁释放、释放后是否真被回收 —— 这些细节藏在 Netty 底层和线程模型里,稍不留神就会堆积成堆外内存溢出或 TIME_WAIT 泛滥。


















