最近在读的 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)

为甚么连接池没有资源了呢,原因非常多,首先检查下客户端:

  1. 高并发下连接池设置过小。
  2. 没有正确释放连接池。
  3. 存在慢查询时,该 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

造成该异常的原因也有以下几种:

  1. 连接超时设置得过短,
  2. Redis发生阻塞,造成tcp-backlog已满,造成新的连接失败。
  3. 客户端与服务端网络不正常。

客户端缓冲区异常

Jedis 在调用 Redis 时,如果出现客户端数据流异常,会出现下面的异常:

redis.clients.jedis.exceptions.JedisConnectionException: Unexpected end of stream.

造成这个异常的原因可能有如下几种:

  1. 输出缓冲区满。例如将普通客户端的输出缓冲区设置为 1M 1M 60config set client-output-buffer-limit "normal 1048576 1048576 60 slave 268435456 67108864 60 pubsub 33554432 8388608 60。如果使用get命令获取一个bigkey(例如3M),就会出现这个异常。
  2. 长时间闲置连接被服务端主动断开。
  3. 不正常并发读写: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