背景

  • 线上服务报大量的Redis,相关依赖这个服务的其他产品线服务也报出同样的日志。
         "Could not get a resource from the pool  org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool" 和 "Connect timed out” 
  • 截图线上日志

image

为什么要写这篇文章

  • 在我的上篇文章中 《记录Redis事故影响API性能-上篇》 由于时间的问题遗留了一个问题没有解释清楚
  • 我们在解决线上问题时如何能快速的定位问题和如何根据相关日志思考问题是如何发生的-通过我的理解尝试解释一下这个问题

因为我个人的能力和精力有限,如果有任何不对或者需要完善的地方,请帮忙指出!

分析

《记录Redis事故影响API性能-上篇》 这篇文章中解决方法中第一个想到的是和运维确认redis 问题和抛出了如果我们哨兵模式当中如果一个节点挂掉会不会出现 获取不到连接池和超时呢?
  • 我们先来分析一下节点挂掉会不会出现问题,我通过分析jedis 源码 答案是 即使挂掉一个节点不会出现连接池获取不到和超时,下面我们一步一步来分析:

    • 第一步:我们的redis 环境是基于哨兵模式,所以我们只看JedisSentinelPool 这个类文件就可以了,先看连接哨兵的初始化逻辑。

      image

    • 第二步:我们从源码中可以看到在初始化哨兵节点启了一个线程来做监听的,下面我们看看这块的源码

      • 我缩了一下代码,整体看一下这个内部类 MasterListener 源码image
      • 在看一下run 方法 具体实现

        image

      • 好,大家仔细看一下我们第二步的两个截图,我们通过假设论证的方法来论证我们的假设是否成立。

        1. 假设我的三个哨兵节点,其中有一个节点挂掉了,会影响服务并且报timeout 和 获取不到连接池资源,但通过我们查看源码 这个假设一眼就看的出来 抛出的Exception 和我们的假设步一致,如果是某一个节点挂掉了会报 下面Excetpion 中的一种,所以假设不成立

          if (running.get()) {
            log.log(Level.SEVERE, "Lost connection to Sentinel at " + host + ":" + port
       try {
         Thread.sleep(subscribeRetryWaitTimeMillis);
       } catch (InterruptedException e1) {
         log.log(Level.SEVERE, "Sleep interrupted: ", e1);
       }
     } else {
       log.fine("Unsubscribing from Sentinel at " + host + ":" + port);
     }
     ```

  2. 我们在找运维的时候,运维也不确定Redis 是否有问题,就重启了一个哨兵节点,应用报了一个错误 然后瞬间就好了,好的当时截图留了一个证据,现在分析来看 这个错误日志能给我很大的启示但是我们错过了,如果你对jedis 有深入的了解的话。![image](https://upload-images.jianshu.io/upload_images/20672231-2cb3b1f43b3b2f30.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


总结:

1. 通过上面的分析我们可以得出 哨兵模式 即使某一个哨兵节点挂掉了不会报出 一下问题

             "Could not get a resource from the pool  org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool"
             "Could not get a resource from the pool  org.springframework.data.redis.RedisConnectionFailureException: Connect timed out; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Connect timed out"

2. 我们在这次的故障中,处理问题的时候想法太单一,在加上线上服务问题心态上有些变化,着急了,没有通过事物的本质去思考问题,从现在总结来看,这个问题当时细心一点就应该得出是什么问题导致的。

3 . 多复盘多总结 ,考虑事情需要从事物的本质去思考问题。一份耕耘,一份收获,不留恋过去,不惧未来。

  • 对于如何定位线上问题和能准确并快速确定问题的根因的方法论和原则

    • 基于服务

      • 服务故障都需要第一时间恢复,无论能不能找到根因。【基于用户为中心指导原则】
      • 如果你的架构是基于微服务,一定要搭建基于微服务的服务治理系统。
      • 所有线上服务运行的日志一定要保留,方便后期找根因。
      • 搭建服务的监控系统。
    • 基于人

      • 在处理线上服务,沉稳冷静, 不放过任何有用的信息
      • 大胆假设,逻辑清晰,小心求证。
      • 时刻保持谦卑的心,终身学习。

关联文章

《记录Redis事故影响API性能-上篇》

作者:易企秀工程师 henry_chen


易企秀工程师
91 声望10 粉丝