Posts Tagged ‘Read timed out’

Redis异常JedisConnectionException:Read timed out解决笔记

星期三, 六月 25th, 2014 21,506 views

笔记①

异常如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
    at redis.clients.jedis.Protocol.process(Protocol.java:131)
    at redis.clients.jedis.Protocol.read(Protocol.java:187)
    at redis.clients.jedis.Connection.getIntegerReply(Connection.java:200)
    at redis.clients.jedis.BinaryJedis.incrBy(BinaryJedis.java:633)
    at java.util.TimerThread.mainLoop(Unknown Source)
    at java.util.TimerThread.run(Unknown Source)
Caused by: java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(Unknown Source)
    at java.net.SocketInputStream.read(Unknown Source)
    at java.net.SocketInputStream.read(Unknown Source)
    at redis.clients.util.RedisInputStream.fill(RedisInputStream.java:109)
    at redis.clients.util.RedisInputStream.readByte(RedisInputStream.java:45)
    at redis.clients.jedis.Protocol.process(Protocol.java:116)
    ... 8 more

在服务器运行中突发异常,当时对Redis的操作并不频繁,大概一分钟一次的写数据,初步分析排除了资源竞争照成的Redis超时异常。
之后ping -t 远程Redis主机,发现当出现Read timed out异常时经常伴有ping超时情况,初步判定为网络不稳定照成。

临时解决办法是在new JedisPool(config, host, port, timeout) 初始化时,将timeout设置成更大的值(默认是2000)以便应对极端网络情况下的读取流异常情况。更进一步的分析还有待发掘,本篇未完待续。

笔记②
之前Read timed out的异常并未在修改了配置文件后有太大的改善,在外网环境下,当用户基数增长到一定量级时,再次出现Read timed out异常。

这种现象太容易让服务端程序将焦点集中在Redis的并发处理能力及连接池数量上,因此特意打印了Redis的慢查询日志,发现并无明显异常,之后观察了Redis的连接数,也不过几十个client而已,并未超过设置上限,在Jedis方面,按照网上其他朋友的建议修改了maxIdle、maxActive和maxWait的值,但问题依旧。

因此开始将排查重点放到了网络底层上,检查了与Redis主机的线路ping值,出现Read timed out的时候,并未出现延迟情况,网络ping值一直<1ms。

继续观察,这个时候注意到偶尔出现了带宽峰值突破30MB/s的情况,多亏了服务器上开启的流量监控浮动,否则很难捕捉到这一瞬间。

通过与机房确认,确定两台机器走的是外网IP,因此访问Redis时走的带宽为外网带宽,那么势必会受到机房防火墙的限制,因此出现了Jedis无法读取到后续数据流的问题。

找到根源之后,问题就很好解决了,在业务机与Redis服务器上各加了一块千兆网卡,通过内网进行直连。重新开机,导用户,测试,加大用户量,一切正常。同时实时流量显示最高峰值达到了100MB/s。

因为Redis是基于TCP连接的,而海量的数据反复交互相当于远程读写内存的操作,势必会造成带宽的使用紧张,那么在带宽吃紧的情况下,Redis客户端即Jedis拿不到连接或拿不到后续数据包也是很正常的了。

但考虑到峰值交互量有点高的可怕,针对这一问题,对并发交互数据的频率进行调整,对数据量进行精减才是解决这一问题的最佳方案。

关于redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out的这一问题我们暂且解决到这里,目前暂未再次出现。
大家如果遇到此类问题,在修改Jedis参数的情况下依旧无法解决,可以考虑一下是否是硬件及网络问题造成的。

本篇到此,欢迎交流讨论。谢谢。

Beitown
2015.04.07