今天线上生产环境Redis报错: No reachable node in cluster
Redis使用的客户端: jedis:3.0.0
首先看一下报错位置,位于redis.clients.jedis.JedisSlotBasedConnectionHandler#getConnection()
@Override
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()代码如下:
@Override public Jedis getResource() { Jedis jedis = super.getResource(); jedis.setDataSource(this); return jedis; }明显jedis为空的时候就会报空指针异常,所以可以忽略这个条件
因此先检查一下pod的状态
kubectl get pods | grep redis发现结点都是1/1的状态,那就可以进redis ping 一下试试
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连接数久而久之就占满了。
以上。
评论