Redis生产实战-Redis集群故障探测以及降级方案设计

Redis 集群故障探测

在生产环境中,如果 Redis 集群崩溃了,那么会导致大量的请求打到数据库中,会导致整个系统都崩溃,所以系统需要可以识别缓存故障,限流保护数据库,并且启动接口的降级机制

降级方案设计

我们在系统中操作 Redis 一般都是通过工具类来进行操作的,假设工具类有两个 RedisCacheRedisLock,那么通过 AOP 对这两个工具类的所有方法做一个切面,如果在这两个类中执行 Redis 操作时,Redis 挂掉了,就会抛出异常(Redis 连接失败),那么我们在切面的处理方法上捕捉异常,再记录下来,判断是 Redis 集群挂了还是展示网络波动

判断是集群挂掉还是网络波动的话,我们可以配置规则,比如 30 秒内出现了 3 次 Redis 连接失败,就认为 Redis 挂掉了(可以使用 Hotkey 配置规则),那么如何自动恢复呢?可以设置 hotkey 中的缓存过期时间,设置为 60 秒,那么缓存过期之后,会再次尝试去操作 Redis,如果 Redis 恢复了就可以正常使用了,如果还没有恢复,会继续向 hotkey 中 set 数据,切面中记录 Redis 故障代码如下:

java 复制代码
@Around("redisCachePointcut() || redisLockPointcut()")
public Object around(ProceedingJoinPoint point) {
    // 签名信息
    Signature signature = point.getSignature();
    // 强转为方法信息
    MethodSignature methodSignature = (MethodSignature) signature;
    // 参数名称
    String[] parameterNames = methodSignature.getParameterNames();
    //执行的对象
    Object target = point.getTarget();

    log.debug("处理方法:{}.{}", target.getClass().getName() , methodSignature.getMethod().getName());
    Object[] parameterValues = point.getArgs();

    //查看入参
    log.debug("参数名:{},参数值:{}", JSONObject.toJSONString(parameterNames), JSONObject.toJSONString(parameterValues));

    Class returnType = methodSignature.getReturnType();

    // 返回类型是否布尔类型
    boolean booleanType = boolean.class.equals(returnType) || Boolean.class.equals(returnType);
    try {
        if (Objects.nonNull(JdHotKeyStore.get("redis_connection_failed"))) {
            // 值不为空表示redis连接失败,这里就不再继续请求redis了,直接返回false或者null
            log.error("获取缓存失败,redis连接失败,直接返回 false 或者 null");
            if (booleanType) {
                return false;
            }
            return null;
        }
        return point.proceed();
    } catch (Throwable throwable) {
        log.error("执行方法:{}失败,异常信息:{}", methodSignature.getMethod().getName(), throwable);
        /*
         * redis连接失败,不抛异常,返回空值,
         * 继续用数据库提供服务,避免整个服务异常
         * 一分钟之内或者30秒之内出现了几次redis连接失败
         * 此时可以设置一个key,告诉hotkey,redis连接不上了,指定1分钟左右的过期时间
         * 下次获取缓存的时候,先根据hotkey来判断,redis是否异常了
         * hotkey在1分钟之后,会删除key,下次再有redis请求过来,重新去看redis能否连接
         * 这样可以简单的实现redis挂掉之后直接走数据库的降级
         */
        if (JdHotKeyStore.isHotKey("redis_connection_failed")) {
            JdHotKeyStore.smartSet("redis_connection_failed", "{}");
        }

        // 让后续操作继续,判断返回类型是Boolean则返回false,其他类型返回null
        log.error("缓存操作失败,直接返回 false 或者 null");
        if (booleanType) {
            return false;
        }
        return null;
    }
}

如果 Redis 故障的话,通过 key=redis_connection_failed 就已经记录下来了,那么降级操作的话,就从本地缓存 caffeine 中取数据,如果取不到,再查询数据库,降级流程如下:

这里如果本地缓存中没有数据的话,需要查询数据库之后,再将数据库中的数据放入本地缓存中,这里还是需要加锁的,那么我们就加本地锁即可 ReentrantLock

相关推荐
极限实验室1 小时前
APM(一):Skywalking 与 Easyearch 集成
数据库·云原生
饕餮争锋1 小时前
SQL条件中WHERE 1=1 的功能
数据库·sql
玄斎2 小时前
MySQL 单表操作通关指南:建库 / 建表 / 插入 / 增删改查
运维·服务器·数据库·学习·程序人生·mysql·oracle
编织幻境的妖2 小时前
SQL查询连续登录用户方法详解
java·数据库·sql
编程小Y3 小时前
MySQL 与 MCP 集成全解析(核心原理 + 实战步骤 + 应用场景)
数据库·mysql·adb
零度@3 小时前
SQL 调优全解:从 20 秒到 200 ms 的 6 步实战笔记(附脚本)
数据库·笔记·sql
Miss_Chenzr4 小时前
Springboot优卖电商系统s7zmj(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
lvbinemail4 小时前
Grafana模板自动复制图表
数据库·mysql·zabbix·grafana·监控
Miss_Chenzr4 小时前
Springboot旅游景区管理系统9fu3n(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·旅游
小虾米vivian4 小时前
dmetl5 运行失败,提示违反协议?
数据库·达梦数据库