根本原因是连接未归还、连不通或配置错层三类问题叠加;jedis实例必须显式close或用try-with-resources归还,否则永久滞留“已借出”状态,且spring boot 3.x需用spring.data.redis.jedis.pool.*前缀,否则按默认maxtotal=8启动致耗尽。

连接池耗尽不是配置小了就完事,而是“借没还”“连不通”“配错层”三类问题叠加的结果。
为什么jedisPool.getResource()调用后总卡住或抛JedisExhaustedPoolException
根本原因不是并发高,而是连接没归还。JedisPool里每个Jedis实例必须显式归还,否则它就永远滞留在“已借出”状态。常见错误包括:
- 用完
jedis后漏掉jedis.close(),尤其在异常分支里; - 把
jedis传给其他方法后,在别处关了,但原调用方又关一次(double close)导致连接实际未归还; - 用了
try-with-resources却没让Jedis实现AutoCloseable——老版本Jedis(close()不等价于returnResource(),必须用jedisPool.returnResource(jedis)或升级到Jedis 4.x(close()已重写为归还逻辑)。
JedisPoolConfig里maxTotal设多大才合理
不能只看QPS,得结合单次Redis操作平均耗时和线程模型算。比如:
- 接口平均RT为20ms,线程池核心线程数是50 → 理论最大并发连接需求 ≈ 50 × (20 / 1000) = 1个连接(远低于默认8);
- 但若大量使用
pipeline或Lua脚本,单次操作耗时升至150ms → 同样50线程下需约7.5个连接; - 生产建议从
maxTotal=64起步,压测时观察JedisPool的getNumActive()和getNumIdle(),确保活跃数稳定在maxTotal × 0.7以内; -
minIdle别设太高(如>32),空闲连接长期不被使用,可能被Redis服务端timeout主动断开,下次借用时才发现是死连接。
Spring Boot 3.x里JedisPool不生效的隐藏陷阱
配置项前缀写错是最隐蔽的耗尽诱因:Spring Boot 3.x起,所有Redis连接池参数必须用spring.data.redis.jedis.pool.*,而不是spring.redis.jedis.pool.*。写错后配置被完全忽略,池子按默认值maxTotal=8启动,一压就满。
- 验证方式:启动日志搜
JedisPoolConfig,确认打印出的maxTotal是你配的值; - 同时检查是否意外引入了
redis.clients:jedis独立依赖——它会干扰spring-boot-starter-data-redis的自动配置,导致JedisConnectionFactory初始化失败; - 若用Redis 5.x或阿里云旧版实例,记得加
spring.data.redis.jedis.client-config.protocol-version=RESP2,否则Lettuce/Jedis混用时协议协商失败,连接反复创建又丢弃。
真正难排查的是“半泄漏”:连接看似归还了,但因Redis服务端主动断连、客户端未做testOnBorrow检测,导致下一次借用时才暴露失败,此时连接池已悄悄少掉一个可用资源。所以testOnBorrow=true和定期evictor扫描不能省。











