问题描述
在使用Azure Redis时,遇见Read Timed out异常, Redis的客户端使用的时jedis。问题发生时,执行redis部分指令出错,大部分get指令,set指令能正常执行。 但程序间段性还是出现Read Timed out错误。
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool at redis.clients.util.Pool.getResource(Pool.java:53) at redis.clients.jedis.JedisPool.getResource(JedisPool.java:226) at redis.clients.jedis.JedisPool.getResource(JedisPool.java:16) at io.terminus.session.redis.JedisPoolExecutor.execute(JedisPoolExecutor.java:56) at io.terminus.session.redis.SessionRedisSource.findSessionById(SessionRedisSource.java:61) ... 58 common frames omitted Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:202) at redis.clients.util.RedisInputStream.readByte(RedisInputStream.java:40) at redis.clients.jedis.Protocol.process(Protocol.java:151) at redis.clients.jedis.Protocol.read(Protocol.java:215) at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340) at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:239) at redis.clients.jedis.BinaryJedis.auth(BinaryJedis.java:2139) at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:108) at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:868) at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:435) at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363) at redis.clients.util.Pool.getResource(Pool.java:49) ... 62 common frames omitted Caused by: java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:170) at java.net.SocketInputStream.read(SocketInputStream.java:141) at java.net.SocketInputStream.read(SocketInputStream.java:127) at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:196) ... 73 common frames omitted
异常分析
从异常分析,当前客户端与Redis服务器的连接已经建立成功,但是在执行某些指令时,出现超时情况,而根据Jedis默认对JedisPool中设置的超时时间2秒作为判断标准,需要在Redis服务器中查看是否时执行某些命令时间超过了2秒。可以通过showlog指令显示出日志记录。
If you get
java.net.SocketTimeoutException: Read timed out
exceptionTry setting own
timeout
value when constructingJedisPool
using the following constructor:
JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout)
where
timeout
is given as milliseconds.Default
timeout
value is 2 seconds.
在Redis的日志中,查看到执行KEYS命令时,超过了2秒
解决办法
在知道异常的根源是由于执行KEYS,超过了2秒的超时时间。解决办法有两点,
- 替换KEYS命令,因为KEYS命令回全Redis键值扫描,非常消耗资源。而在Redis的官方推荐中也建议使用SCAN来替代它。
- 增加timeout时间,把默认的超时时间2秒,增加到5秒
参考文档
If you get java.net.SocketTimeoutException: Read timed out
exception:https://github.com/xetorthio/jedis/wiki/FAQ#if-you-get-javanetsockettimeoutexception-read-timed-out-exception
KEYS: https://redis.io/commands/keys
SCAN: https://redis.io/commands/scan