[redis 源码走读] - sentinel 哨兵 - 故障转移

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

前面几章已经讲了:redis 集群各个角色之间的通信,主客观下线,投票选举;在选举中胜出的哨兵 leader,由它来完成 redis 集群的故障转移: redis 实例的角色转换 。


哨兵故障转移主体流程:

master 主观下线 -> master 客观下线 -> 选举 -> leader 筛选原 master 的最优 slave -> 晋升最优 slave 为新 master -> 通知原 master 的其它 slave 链接新 master -> 结束故障转移 -> 更新新 master 的存储结构关系 -> 旧 master 重新上线被降级为 slave。



1. 故障转移

故障转移由许多环节组成,集群中每个 sentinel 都有机会实行,但是只有在选举过程中赢得选票的人,才可以完整完成整个故障转移流程。

1.1. 流程

sentinel 节点故障转移流程的几个环节:

 
    /* 初始状态。*/
    #define SENTINEL_FAILOVER_STATE_NONE 0               /* No failover in progress. */
    /* 开始进入选举投票状态。*/
    #define SENTINEL_FAILOVER_STATE_WAIT_START 1         /* Wait for failover_start_time*/
    /* 选出最优 slave。 */
    #define SENTINEL_FAILOVER_STATE_SELECT_SLAVE 2       /* Select slave to promote */
    /* 提升最优 slave 为新master。 */
    #define SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE 3 /* Slave -> Master */
    /* 等待最优 slave 成功晋升:info 回复 role:master。 */
    #define SENTINEL_FAILOVER_STATE_WAIT_PROMOTION 4     /* Wait slave to change role */
    /* slaves 连接新 master。 */
    #define SENTINEL_FAILOVER_STATE_RECONF_SLAVES 5      /* SLAVEOF newmaster */
    /* slave 成功晋升 master 后,更新 master <--> slave 的数据结构关系。 */
    #define SENTINEL_FAILOVER_STATE_UPDATE_CONFIG 6      /* Monitor promoted slave. */
    
    /* 进入故障转移流程。*/
    void sentinelFailoverStateMachine(sentinelRedisInstance *ri) {
        serverAssert(ri->flags & SRI_MASTER);
    
        /* 确保当前没有故障转移正在执行。*/
        if (!(ri->flags & SRI_FAILOVER_IN_PROGRESS)) return;
    
        switch (ri->failover_state) {
            case SENTINEL_FAILOVER_STATE_WAIT_START:
                sentinelFailoverWaitStart(ri);
                break;
            case SENTINEL_FAILOVER_STATE_SELECT_SLAVE:
                sentinelFailoverSelectSlave(ri);
                break;
            case SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE:
                sentinelFailoverSendSlaveOfNoOne(ri);
                break;
            case SENTINEL_FAILOVER_STATE_WAIT_PROMOTION:
                sentinelFailoverWaitPromotion(ri);
                break;
            case SENTINEL_FAILOVER_STATE_RECONF_SLAVES:
                sentinelFailoverReconfNextSlave(ri);
                break;
        }
    }

1.2. 测试

3 个 sentinel,3 个 redis 实例,一主两从。关闭主服务,再重新启动主服务,通过 sentinel 日志看看故障转移情况。

  • 测试节点。
node ip port
sentinelA 127.0.0.1 26379
sentinelB 127.0.0.1 26377
sentinelC 127.0.0.1 26378
master 127.0.0.1 6379
slave 127.0.0.1 6378
slave2 127.0.0.1 6377

 
    #!/bin/sh
    ...
    # 关闭所有 redis 进程。
    kill_redis
    # 开启所有 sentinel 进程。
    start_sentinels
    # 打印 sentinel 进程信息。
    redis_info redis-sentinel
    # 开启所有 redis 进程。
    start_redis
    # 打印 redis 进程信息。
    redis_info redis-server
    # 将 6379 端口的 redis 设置为 master。
    remaster 6379
    # 向 redis 进程获取角色信息。
    redis_role
    # 向 sentinel 获取角色信息。
    get_master_info_from_sentinel 26379
    # 等待足够长时间,让 sentinel 发现所有节点,彼此建立通信。
    sleep 100
    # 关闭 6379 进程。
    shutdown_redis 6379
    # 等待 sentinel 故障转移成功(一般很快,根据需要设置时间。)
    echo 'failover wait for 30s......'
    sleep 30
    # 模拟将下线的 6379 master 重新上线。
    remaster_redis 6379
    sleep 5
    ...
    # 查看 sentinel 日志,观察工作流程。
  • sentinel-26379 故障转移日志,它在选举中赢得选票,执行完整的故障转移流程。
 
    32121:X 30 Sep 2023 15:06:54.145 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
    32121:X 30 Sep 2023 15:06:54.145 # Redis version=5.9.104, bits=64, commit=00000000, modified=0, pid=32121, just started
    32121:X 30 Sep 2023 15:06:54.145 # Configuration loaded
    # 当前 sentinel 端口为 26379
    32123:X 30 Sep 2023 15:06:54.147 * Running mode=sentinel, port=26379.
    # 当前 sentinel runnid: 0400c9**
    32123:X 30 Sep 2023 15:06:54.148 # Sentinel ID is 0400c9170654ecbaeaf98fedb1630486e5f8f5b6
    # 修改 sentinel 监控对象,监控端口为 6379 的 master。
    32123:X 30 Sep 2023 15:06:54.148 # +monitor master mymaster 127.0.0.1 6378 quorum 2
    32123:X 30 Sep 2023 15:07:00.211 # -monitor master mymaster 127.0.0.1 6378
    32123:X 30 Sep 2023 15:07:00.237 # +monitor master mymaster 127.0.0.1 6379 quorum 2
    # 设置故障转移有效时间段为 10 秒。
    32123:X 30 Sep 2023 15:07:00.254 # +set master mymaster 127.0.0.1 6379 failover-timeout 10000
    # 从 master 6379 中发现 slave 6378。
    32123:X 30 Sep 2023 15:07:00.291 * +slave slave 127.0.0.1:6378 127.0.0.1 6378 @ mymaster 127.0.0.1 6379
    # 当前 sentinel 通过 hello 频道的订阅信息,发现其它的 sentinel。
    32123:X 30 Sep 2023 15:07:02.271 * +sentinel sentinel 989f0e00789a0b41cff738704ce8b04bad306714 127.0.0.1 26378 @ mymaster 127.0.0.1 6379
    32123:X 30 Sep 2023 15:07:02.290 * +sentinel sentinel de0ffb0d63f77605db3fccb959f67b65b8fdb529 127.0.0.1 26377 @ mymaster 127.0.0.1 6379
    # 从 master 6379 中发现 slave 6377。
    32123:X 30 Sep 2023 15:07:10.359 * +slave slave 127.0.0.1:6377 127.0.0.1 6377 @ mymaster 127.0.0.1 6379
    ---
    # 发现 master 6379 主观下线。
    32123:X 30 Sep 2023 15:07:51.408 # +sdown master mymaster 127.0.0.1 6379
    # 确认 master 6379 客观下线。
    32123:X 30 Sep 2023 15:07:51.474 # +odown master mymaster 127.0.0.1 6379 #quorum 3/2
    # 开始进入选举环节,选举纪元(计数器) 29。(这个测试日志不是第一次,所以纪元有历史数据。)
    32123:X 30 Sep 2023 15:07:51.474 # +new-epoch 29
    # 尝试对 6379 开启故障转移流程,注意:这里还没正式开启,只有在选举中获胜的 sentinel 才会正式开启。
    32123:X 30 Sep 2023 15:07:51.474 # +try-failover master mymaster 127.0.0.1 6379
    # 当前 sentinel 没发现其它 sentinel 向它拉票,所以它把选票投给了自己。
    32123:X 30 Sep 2023 15:07:51.494 # +vote-for-leader 0400c9170654ecbaeaf98fedb1630486e5f8f5b6 29
    # 26378 把
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值