文章目录
Jedis连接问题
一、现状
- 项目实施中生产环境获取redis缓存报错。
Unexpected end of stream.
二、复现 - Unexpected end of stream
- 环境版本信息
应用 | 版本 | 数据来源 |
---|---|---|
jdk | 1.8.0_231 | – |
redis | 2.8.19 | ./redis-cli info server | grep redis_version |
jedis | 2.7.3 | – |
ss-redis | 1.2.6.1 | – |
-
设置redis服务端超时时间或者在redis.conf修改
./redis-cli -p 7379 config set timeout 30
-
客户端验证超时(伪代码)
/** 重要参数 MinIdle=2 MaxIdle = 2 TestOnBorrow = false TestOnReturn = false; MaxTotal = -1; MaxWaitMillis = 100L; TestWhileIdle = false; **/ initPool(); //初始化连接池 Thread.sleep(1000*40); //线程阻塞40s(大于服务端超时时间) Jedis jedis = getResource(); //从连接池获取连接 jedis.set(k, v); //报错 Unexpected end of stream
-
模拟报错结果如下
三、分析 - Unexpected end of stream
-
设置服务端超时30s,每隔2秒采集redis client连接情况
while true ;do ./redis-cli -p 7379 info Clients | grep connected_clients && sleep 2; done
-
连接数监测结果
- 如下图中可以看出,在redis服务端30s超时之后,服务端断开连接,连接数变成7。当Jedis客户端再次操作的时候就会报错_Unexpected end of stream_
- 如下图中可以看出,在redis服务端30s超时之后,服务端断开连接,连接数变成7。当Jedis客户端再次操作的时候就会报错_Unexpected end of stream_
-
对初始及剩下的7个连接分析结果
- 6个连接是sentinel与redis-server建立的连接
- 1个是当前执行采集脚本时候,与redis-server建立的连接
-
四、方案 - Unexpected end of stream
方案一:设置服务端不超时 timeout=0
-
修改redis-server配置
./redis-cli -p 7379 config set timeout 0
-
结果验证
服务端连接一直保持,不断开。客户端操作正常。
方案二:设置TestOnBorrow = true,服务端超时30s
-
修改Jedis连接池配置
setTestOnBorrow(true)
-
修改redis-server配置
./redis-cli -p 7379 config set timeout 30
-
结果验证
服务端连接超时断开,客户端重新建立连接获取数据。见下图
-
源码分析
- redis pool将连接对象保存在队列里面,每次获取连接时从队列中取 pollFirst,拿到连接对象执行ping操作。如果正常返回则使用该连接。如果报错则重建连接。
- testOnBorrow=true保证了连接的可用性。
public boolean validateObject(PooledObject