今天线上生产环境Redis报错: No reachable node in cluster
Redis使用的客户端: jedis:3.0.0
首先看一下报错位置,位于redis.clients.jedis.JedisSlotBasedConnectionHandler#getConnection()
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
public Jedis getConnection() {
List<JedisPool> pools = cache.getShuffledNodesPool();
for (JedisPool pool : pools) {
Jedis jedis = null;
try {
jedis = pool.getResource();
if (jedis == null) {
continue;
}
String result = jedis.ping();
if (result.equalsIgnoreCase("pong")) return jedis;
jedis.close();
} catch (JedisException ex) {
if (jedis != null) {
jedis.close();
}
}
}
throw new JedisNoReachableClusterNodeException("No reachable node in cluster");
}
大致这段代码的意思是找到Redis集群中的所有Master结点,并对redis结点发起一次ping请求,如果返回pong就代表该结点是可用的,如果没有任何一个redis结点可用,就会报No reachable node in cluster
异常
这里还有一个条件是jedis==null的时候continue,但是pool.getResource()代码如下:
java
- 01
- 02
- 03
- 04
- 05
- 06
public Jedis getResource() { Jedis jedis = super.getResource(); jedis.setDataSource(this); return jedis; }
明显jedis为空的时候就会报空指针异常,所以可以忽略这个条件
因此先检查一下pod的状态
kubectl get pods | grep redis
发现结点都是1/1的状态,那就可以进redis ping 一下试试
- 01
127.0.0.1:6379 > ping
(error) ERR max number of clients reached
这里的报错大致意思是redis的客户端连接数到达了上线,因此拒绝了更多的请求。redis默认的配置最大客户端数是10000,可以通过maxclients修改。
但显然仅仅增加最大连接数是治标不治本,如果redis可用,我们还可以通过info clients
查看当前连接以及通过client list
查看连接列表,这里我们只能通过linux的网络连接来看了
netstat -na | grep current_ip:6379 | awk '{print $5}' | awk -F ':' '{count[$1]++;} END {for(i in count) {print i,count[i]}}'
通过上面这个命令,可以打印出哪个ip与当前客户端建立了多少个请求,结果就发现有一个ip,建立了9k多个请求,立马就确定是当前这个服务出现了异常。
由于这个服务与业务无关,因此先暂时停止该服务,过一段时间后,redis连接恢复,业务正常执行。
那到底是为啥这个服务建立了9k多个请求呢。
看了一下,里面有四五个定时任务,比如判断redis是否存活,响应时间等等,每个定时任务做判断的时候都会去new一个Jedis客户端。
逆天,jedis不是有自带的JedisPool不用。。。虽然每处代码都close了,但如果由于网络原因close不及时或出现问题(这里还用的是IOUtils.closeQuitely,报错都不会显示)Redis连接数久而久之就占满了。
以上。