最近在读的 Redis开发与运维,很好地总结了客户端的常见异常。这篇博客权且作为读书笔记。
无法从连接池获取到连接
JedisPool 中的 Jedis 对象个数默认是 8 个。如果有 8 个 Jedis 对象被占用,并且没有归还,此时调用者还要从 JedisPool 中借用 Jedis,就需要进行等待(例如设置了 maxWaitMillis > 0
),如果在 maxWaitMillis
时间内仍然无法获取到 Jedis 对象就会抛出如下异常:
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource
from the pool
…
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.
java:449)
另外一种情况,是设置了 blockWhenExhausted = false
。调用者不会等待,直接抛出异常。
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource
from the pool
…
Caused by: java.util.NoSuchElementException: Pool exhausted
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.
java:464)
为甚么连接池没有资源了呢,原因非常多,首先检查下客户端:
- 高并发下连接池设置过小。
- 没有正确释放连接池。
- 存在慢查询时,该 Jedis 对象归还速度会很慢,导致池子满了。
如果客户端正常,服务端的某些原因可能导致用户命令的阻塞,也会使客户端抛出这种异常。
客户端读写超时
Jedis 在调用 Redis 时,如果出现了读写超时后,会出现下面的异常:
redis.clients.jedis.exceptions.JedisConnectionException:
java.net.SocketTimeoutException: Read timed out
造成该异常的原因也有以下几种:
- 读写超时间设置得过短。
- 命令本身就比较慢。
- 客户端与服务端网络不正常。
- Redis自身发生阻塞。
客户端连接超时
Jedis 在调用 Redis 时,如果出现了连接超时后,会出现下面的异常:
redis.clients.jedis.exceptions.JedisConnectionException:
java.net.SocketTimeoutException: connect timed out
造成该异常的原因也有以下几种:
- 连接超时设置得过短,
- Redis发生阻塞,造成tcp-backlog已满,造成新的连接失败。
- 客户端与服务端网络不正常。
客户端缓冲区异常
Jedis 在调用 Redis 时,如果出现客户端数据流异常,会出现下面的异常:
redis.clients.jedis.exceptions.JedisConnectionException: Unexpected end of stream.
造成这个异常的原因可能有如下几种:
- 输出缓冲区满。例如将普通客户端的输出缓冲区设置为
1M 1M 60
:config set client-output-buffer-limit "normal 1048576 1048576 60 slave 268435456 67108864 60 pubsub 33554432 8388608 60
。如果使用get命令获取一个bigkey(例如3M),就会出现这个异常。 - 长时间闲置连接被服务端主动断开。
- 不正常并发读写:Jedis对象同时被多个线程并发操作,可能会出现上述异常。
Redis 正在加载持久化文件
Jedis 调用 Redis 时,如果 Redis 正在加载持久化文件,那么会收到下面的异常:
redis.clients.jedis.exceptions.JedisDataException: LOADING Redis is loading the dataset in memory
Redis 使用的内存超过 maxmemory
配置
Jedis 执行写操作时,如果 Redis 的使用内存大于 maxmemory
的设置,会收到下面的异常,此时应该调整 maxmemory
并找到造成内存增长的原因:
redis.clients.jedis.exceptions.JedisDataException: OOM command not allowed when used memory > 'maxmemory'.
客户端连接数过大
如果客户端连接数超过了maxclients,新申请的连接就会出现如下异常:
redis.clients.jedis.exceptions.JedisDataException: ERR max number of clients reached
此时新的客户端连接执行任何命令,返回结果都是如下:
127.0.0.1:6379> get hello
(error) ERR max number of clients reached