长连接卡在pool.getResource()不返回,大概率是连接池耗尽而非Redis宕机;需检查maxTotal配置、连接泄漏及testOnBorrow引发的延迟;redis-cli ping通不代表可用,应通过--latency、slowlog和blocked_clients等指标验证服务端真实状态。

长连接卡在 pool.getResource() 不返回?先看是不是连接池耗尽
这是最常见也最容易被误判为“Redis挂了”的场景:应用线程在调用 JedisPool.getResource() 时无限等待,堆栈停在 GenericObjectPool.borrowObject(),但 redis-cli ping 本地又通——说明 Redis 活着,只是你的连接池没资源可借了。
原因往往不是 Redis 拒绝连接,而是客户端侧连接池配置太激进或泄漏未回收:
-
maxWaitMillis设得过大(比如 5000ms 甚至 -1),导致线程傻等不报错 -
testOnBorrow开启但 Redis 响应慢,每次借连接都触发PING,放大延迟 - 业务代码忘了调用
jedis.close()或returnResource(),连接持续占用不释放 - 连接数配置不合理:
maxTotal=16却跑着 20 个并发线程,必然阻塞
实操建议:立刻查当前活跃连接数:redis-cli info clients | grep connected_clients,再对比你设的 maxclients 和连接池 maxTotal。如果前者远小于后者,问题大概率在客户端;如果两者接近,就要看 Redis 是否真被压垮了。
redis-cli ping 成功但业务请求超时?检查连接是否“假活”
能 ping 通只代表 TCP 连接建立成功、Redis 进程没死,不代表它还能处理命令。尤其在高负载、内存交换(swap)、CPU 抢占严重时,Redis 可能陷入“有心跳无响应”状态——收得到包,但命令排队太久或根本无法调度执行。
验证方式不是再 ping 一次,而是模拟真实路径:
- 用
redis-cli --latency -h $HOST -p $PORT看实际 RT,超过 50ms 就要警惕 - 执行
redis-cli slowlog get 5,确认是否有阻塞命令(如大 keyKEYS *、FLUSHALL)正在执行 - 查
redis-cli info stats | grep blocked_clients,非零值说明有客户端正被阻塞(如BLPOP等待) - 重点看 swap:
cat /proc/$(pgrep redis-server)/smaps | awk '/^Swap:/ {sum+=$2} END {print sum" KB"}',只要大于 4KB 就危险
这时重启连接池或重连毫无意义——问题在服务端资源层。必须降负载、关 swap、隔离 CPU,否则换多少次连接都是徒劳。
如何让长连接自动感知并脱离僵死状态?别只靠 timeout
单纯设 socketTimeout 或 connectionTimeout 只能防“建连失败”或“单次命令卡死”,对已建立但不再响应的连接(即僵死连接)无效。Jedis 默认不会主动探测连接是否还活着。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
真正起作用的是连接池的保活机制,但要注意参数含义差异:
-
testOnBorrow=true:每次借连接前发PING,最稳妥,但有性能开销 -
testWhileIdle=true+timeBetweenEvictionRunsMillis=30000:空闲连接每 30 秒被检测一次,适合低频应用 -
minEvictableIdleTimeMillis=60000:空闲超 60 秒的连接会被清理,防长期泄漏
示例配置(平衡健壮性与开销):config.setTestOnBorrow(true); config.setTestOnReturn(false); config.setTimeBetweenEvictionRunsMillis(30000); config.setMinEvictableIdleTimeMillis(60000);
注意:testOnBorrow 在 Redis 响应慢时会雪上加霜,若线上 RT 已不稳定,宁可关掉它,改用后台驱逐+业务层兜底重试。
连接池返回的 Jedis 实例执行命令卡住?别急着重连,先确认是否是命令级阻塞
有时现象是:连接池顺利返回了 Jedis 对象,但一执行 set("k","v") 就卡住不动。这未必是连接问题,很可能是命令本身被阻塞了。
典型场景包括:
- 使用了阻塞命令:
BLPOP、BZPOPMIN等,在没有数据时会一直挂起 - 执行了 O(n) 复杂度命令操作大 key,如
HGETALL一个百万字段的 hash - 开启了 AOF 且
appendfsync=always,磁盘写满或 IO 飙高导致同步阻塞
排查优先级:先 redis-cli client list 找出 cmd= 字段非 NULL 的客户端,再看其 idle 时间和 flags(如 b 表示阻塞中)。如果是阻塞命令,需从业务逻辑上规避,而非指望连接池解决。
真正容易被忽略的一点:Jedis 的 close() 并不等于断开 TCP,它只是归还到池里。如果这个连接之前执行过阻塞命令,归还后下一次借出仍可能残留状态——所以务必确保阻塞命令有超时参数(如 BLPOP key 5),而不是无期限等待。

















