Connection timed out 和 Could not get a resource from the pool 是两回事:前者是TCP握手失败,问题在服务端监听、网络或防火墙;后者是客户端连接池耗尽,请求根本未发出。

Connection timed out 和 Could not get a resource from the pool 是两回事
看到超时日志第一反应别急着调大 timeout 或重启 Redis。先看堆栈末尾的 Caused by:如果是 java.net.ConnectException: Connection timed out,说明 TCP 握手失败,问题在服务端监听、网络通路或防火墙;如果是 Could not get a resource from the pool,说明客户端连接池已空,根本没发出去请求——这时候调服务端配置毫无意义。
检查本地连接池是否耗尽(最常被跳过的一步)
很多“Redis 超时”其实是应用自己卡死在等连接。关键看三件事:
- 用
netstat -an | grep :6379 | grep ESTAB | wc -l查本机到 Redis 的ESTABLISHED连接数,如果接近maxTotal(Jedis 默认 8,Lettuce 默认 18),就是池子撑不住了 - 确认代码里每次
jedis.get()后是否都执行了jedis.close();用try-with-resources最稳妥,否则连接永不归还 - 检查
maxWaitMillis是否设得太小(比如 100ms),高并发下等不及就直接抛异常,而不是真没资源
验证 Redis 服务端是否在 silently drop 新连接
服务端连接数打满或内核队列溢出时,不会返回 Connection refused,而是静默丢弃 SYN 包,客户端就只能干等 connectTimeout 耗尽。要确认这点:
- 执行
redis-cli info clients,看connected_clients是否等于maxclients(默认 10000) - 执行
netstat -s | grep -i "listen overflows"或ss -s | grep -i "orphan",有 overflow 就说明tcp_backlog(Redis 配置项,默认 511)不够用了 - 执行
redis-cli client list | awk '{print $2,$10}' | grep -v "idle=0" | sort -k2 -nr | head -5,看有没有大量 idle 超过服务端timeout值(如 3600)的连接——这些连接可能已被服务端关闭,但客户端还在复用
区分 read timeout 是卡在 Redis 还是卡在网络或客户端
Read timed out 表示连接已建好,命令也发过去了,但没等到响应。这时得盯住 Redis 主线程是否被拖住:
- 执行
redis-cli --latency看基础延迟,如果 >10ms 就值得怀疑链路或 Redis 自身 - 执行
redis-cli slowlog get 10,重点看执行时间 >10ms 的命令,尤其是HGETALL、LRANGE 0 -1、KEYS *这类 - 执行
redis-cli --bigkeys扫描是否存在 >1MB 的 String 或 >10k 成员的 Hash/List/Set——读写这类 key 会阻塞主线程,下游所有请求跟着一起 hang - 注意
socketTimeout设置是否合理:设太小(如 100ms)会让正常慢操作也被判为超时;设太大(如 30s)又掩盖真实阻塞问题
真正难排查的不是报错本身,而是同一句 JedisConnectionException 可能对应 TCP 握手失败、连接池枯竭、Redis 主线程卡死、甚至客户端线程被自己业务逻辑锁住——必须靠 Caused by 定位到最底层异常,再按链路逐层反推,漏一层就白查。


















