`

Redis集群之复制、故障转移及消息实现

阅读更多
        在Redis集群实现原理一节,我们介绍了 Redis 集群的实现细节,以及所使用的主要数据结构,本节将对集群节点的复制方法,检测节点是否下线的方法,以及对下线主节点进行故障转移的方法一一进行探讨。
        Redis 集群中的节点分为主节点(master)和从节点(slave),其中主节点用于处理槽,而从节点则用于复制某个主节点,并在被复制的主节点下线时,代替下线主节点继续处理命令请求。

        设置从节点
        向一个节点发送“CLUSTER REPLICATE <node_id>”命令,可以让接收命令的节点成为 node_id 所指定节点的从节点,并开始复制主节点:
        * 接收到该命令的节点首先会将自己的 clusterState.myself.slaveof 指针指向 clusterState.nodes 字典中 node_id 所对应节点的 clusterNode 结构,以此记录这个节点正在复制的主节点。
        * 然后节点会修改自己在 clusterState.myself.flags 中的属性,关闭原本的 REDIS_NODE_MASTER 标识(如果设置),并打开 REDIS_NODE_SLAVE 标识,表示这个节点已经由原来的主节点变成了从节点。
        * 最后,节点会根据 slaveof 指向的 clusterNode 结构中的 IP 和端口,调用复制代码对主节点进行复制。因为节点的复制功能和单机 Redis 服务器的复制功能(见数据库复制一节)使用了相同的代码,所以让从节点复制主节点相当于向从节点发送命令“SLAVEOF <master_ip> <master_port>”。
        一个节点成为从节点,并开始复制某个主节点这一信息会通过消息发送给集群中的其他节点。集群中的所有节点都会在代表主节点的 clusterNode 结构的 slaves 和 numslaves 属性中记录正在复制这个主节点的从节点名单。

        故障检测和故障转移
        集群中的每个节点都会定期地向其他节点发送 PING 消息,以此来检测对方是否在线。如果接收 PING 消息的节点没有在规定的时间内返回 PONG 消息,则发送 PING 消息的节点就会将其标记为疑似下线(probable fail,PFAIL),具体为在自己的 clusterState.nodes 字典中找到对方的 clusterNode 结构,然后打开其中 flags 属性中的 REDIS_NODE_PFAIL 标识,以表示该节点进入了疑似下线状态。
        集群中的各个节点会通过互相发送消息的方式来交换集群中各个节点的状态信息。当一个主节点 A 通过消息得知主节点 B 认为主节点 C 进入了疑似下线状态时,主节点 A 会在自己的 clusterState.nodes 字典中找到 C 所对应的 clusterNode 结构,并将主节点 B 的下线报告添加到其中的 fail_reports 链表里面。每个下线报告由一个 clusterNodeFailReport 结构表示。
typedef struct clusterNodeFailReport {
    struct clusterNode *node;     // 报告目标节点已经下线的节点
    // 最后一次从 node 节点收到下线报告的时间
    // 程序使用这个时间戳来检查下线报告是否过期(与当前时间相差太久的会被删除)
    mstime_t time;
}clusterNodeFailReport;

        如果在一个集群里面,半数以上负责处理槽的主节点都将某个主节点 X 报告为疑似下线,则该主节点 X 将被标记为已下线(FAIL),将主节点 X 标记为以下线的节点会向集群广播一条关于主节点 X 的 FAIL 消息,所有收到这条消息的节点(包括从节点)都会立即将主节点 X 标记为已下线。
        当一个从节点发现自己正在复制的主节点进入了已下线状态时,从节点将开始对下线主节点进行故障转移,执行步骤如下:
        1)从下线主节点的所有从节点里面选举一个来执行“SLAVEOF no noe”命令,成为新的主节点。
        2)新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽全部指派给自己。
        3)新的主节点向集群广播一条 PONG 消息,以告知集群中的其他节点,自己已经由从节点变成了主节点,并且已经接管了原本由已下线主节点复杂处理的槽。
        4)新的主节点开始接收和自己负责处理的槽有关的命令请求,故障转移完成。

        消息
        集群中的各个节点通过发送和接收消息来进行通信,比如前面提到的 MEET、PING、PONG、FAIL 和 PUBLISH 等消息。一条消息由消息头和消息正文组成。
        消息头除了包含消息正文之外,还记录了消息发送者自身的一些信息。每个消息头都由一个 clusterMsg 结构表示:
typedef struct {
    uint32_t totlen;        // 消息的长度,包括消息头和消息正文
    uint16_t type;          // 消息的类型
    // 消息正文包含的节点信息数量,只在发送 MEET、PING、PONG 这三种 Gossip 协议消息时使用
    uint16_t count;

    uint64_t currentEpoch;  // 发送者所处的配置纪元

    // 如果发送者是一个主节点,则这里记录的是发送者的配置纪元
    // 如果发送者是一个从节点,则这里记录的是发送者正在复制的主节点的配置纪元
    uint64_t configEpoch;

    char sender[REDIS_CLUSTER_NAMELEN];    // 发送者的名字(ID)
    unsigned char myslots[REDIS_CLUSTER_SLOTS/8];  // 发送者的槽指派信息

    // 如果发送者是一个主节点,则这里记录的是 REDIS_NODE_NULL_NAME
    // 如果发送者是一个从节点,则这里记录的是发送者正在复制的主节点的名字
    char slaveof[REDIS_CLUSTER_NAMELEN];

    uint16_t port;         // 发送者的端口号
    uint16_t flags;        // 发送者的标识值
    unsigned char state;   // 发送者所处集群的状态

    union clusterMsgData data;    // 消息的正文
}clusterMsg;

union clusterMsgData{
    struct {
        clusterMsgDataGossip gossip[2];
    } ping;                // MEET、PING、PONG 消息的正文

    struct {
        clusterMsgDataFail about;
    } fail;                // FAIL 消息的正文

    struct {
        clusterMsgDataPublish msg;
    } publish;             // PUBLISH 消息的正文

    /* 其他消息的正文 */
};

typedef struct {
    char nodename[REDIS_CLUSTER_NAMELEN];    // 节点的名字
    uint32_t ping_sent;    // 最后一次向该节点发送 PING 消息的时间戳
    uint32_t pong_sent;    // 最后一次从该节点收到 PONG 消息的时间戳
    char ip[16];           // 节点的 IP
    uint16_t port;         // 节点的端口号
    uint16_t flags;        // 节点的标识值
} clusterMsgDataGossip;

typedef struct {
    char nodename[REDIS_CLUSTER_NAMELEN];   // 已下线节点的名字
} clusterMsgDataFail;

typedef struct {
    uint32_t channel_len;        // channel 参数的长度
    uint32_t message_len;        // message 参数的长度

    // 该字节数组保存了客户端通过 PUBLISH 命令发送的 channel 和 message 参数
    // 定义为 8 字节只是为了对齐其他消息结构
    // 实际的长度由保存的内容决定
    // channel 参数的内容是前 channel_len 字节
    // message 参数的内容则是 channel+message_len-1 字节
    unsigned char bulk_data[8];
} clusterMsgDataPublish;

        clusterMsg 结构的 currentEposh、sender、myslots 等属性记录了发送者自身的节点信息,接收者会根据这些消息,在自己的 clusterState.nodes 字典里找到发送者对应的 clusterNode 结构来更新相关信息。比如,通过对比接收者为发送者记录的槽指派信息和发送者在消息头的 myslots 属性记录的槽信息,接收者可以知道发送者的槽指派信息是否发生了变化。
        每次发送 MEET、PING 和 PONG 消息时,发送者都从自己的已知节点列表中随机选出两个节点(可以是主节点或者从节点),并将它们的信息分别保存到两个 clusterMsgDataGossip 结构里面。当接收者收到这三种消息时,它会访问消息正文中的两个 clusterMsgDataGossip 结构,并根据自己是否认识其中的节点来选择进行哪种操作:
        * 如果被选中的节点不存在于接收者的已知节点列表,则说明接收者是第一次接触到被选中节点,接收者将与之进行握手。
        * 如果被选中的节点已经存在于接收者的已知节点列表,则说明两者之前已经接触过,接收者将根据 clusterMsgDataGossip 结构记录的信息来更新被选中节点所对应的 clusterNode 结构。
        对于 FAIL 消息,在集群的节点数量比较大的情况下,单纯使用 Gossip 协议来传播节点的已下线信息会给节点的信息更新带来一定的延迟,因为 Gossip 协议消息通常需要一段时间才能传播至整个集群,而发送 FAIL 消息可以让集群里的所有节点立即知道某个主节点已下线,从而尽快判断是否需要将集群标记为下线,又或者对下线主节点进行故障转移。
        当客户端向集群中的某个节点发送命令“PUBLISH <channel> <message>”时,接收到 PUBLISH 命令的节点不仅会向 channel 频道发送消息 message,它还会向集群广播一条 PUBLISH 消息,所有接收到这条消息的节点都会向 channel 频道发送 message 消息(集群中之所以没有像在复制 PUBLISH 命令时采用广播 PUBLISH 命令的方式通知所有节点,主要是为了符合 Redis 集群的“各个节点通过发送和接收消息来进行通信”这一原则)。


参考书籍:
1、《Redis设计与实现》第17章——集群。
分享到:
评论

相关推荐

    Redis集群测试

    7. **测试策略**:测试Redis集群时,应包括性能测试(如并发读写测试)、压力测试(模拟大规模数据和高并发场景)、故障恢复测试(验证故障转移的正确性)以及数据一致性测试(检查数据在不同节点间的同步情况)。...

    spring + redis集群

    Redis集群是Redis的一个重要特性,它允许你分散数据到多个节点上,实现数据的高可用性和水平扩展。构建Redis集群时,需要注意以下几点: 1. **集群配置**:至少需要6个节点(3主3从)来确保数据冗余和故障转移。每个...

    Redis主从复制和集群配置

    ### Redis主从复制和集群配置详解 #### 一、Redis主从复制原理及配置 **1.1 概述** ...通过对主从复制的理解和合理配置,以及利用Sentinel的功能,可以有效地管理和监控Redis集群,确保系统的稳定运行。

    Redis集群配置文件

    Redis集群配置文件是实现Redis高可用性和数据分片的关键组件。在Redis集群中,数据被分散存储在多个节点上,每个节点负责一部分数据,从而提高了系统的扩展性和容错性。以下将详细介绍Redis集群配置文件的相关知识,...

    redis集群一键自动部署脚本.rar

    - **uninstall.sh**:可能是用来卸载Redis集群的脚本,清理已安装的Redis实例及相关配置。 - **main.sh**:主脚本,可能包含整个部署流程,包括解压Redis源码、编译安装、配置集群等步骤。 - **redis-5.0.0.tar....

    redis集群以及Spring-data-redis操作集群

    在Redis 3.0及以上版本,引入了集群功能,支持主从复制、槽分配以及故障转移等特性。 **集群搭建** Redis集群的搭建通常包括以下几个步骤: 1. **准备节点**:至少需要三个独立的Redis实例作为集群的初始节点。 2...

    redis集群 三主三从模式

    在这种三主三从的配置中,每个主节点都有一个对应的从节点,用于数据备份和故障转移。当主节点故障时,其对应的从节点可以自动提升为主节点,继续提供服务,确保服务的连续性。 接下来,我们来看如何设置这个集群。...

    shiro连接redis集群 根据org.crazycake.shiro包改造源码

    例如,原本的实现可能仅支持单个Redis实例,改造后可能实现了多节点的发现、读写操作的路由以及故障转移机制。 具体改造可能包括以下方面: 1. **RedisClient**:原有的Shiro Redis连接器可能使用了单一的Redis...

    Redis集群搭建与验证.pdf

    在Redis集群中,主节点负责处理读写请求,而从节点通常用于故障转移,当主节点故障时,一个从节点可以提升为主节点继续服务。 3. 环境准备与Redis版本选择 安装环境选择使用虚拟机模拟,文中提到的虚拟机操作系统...

    redis集群安装手册(终稿).docx

    Redis集群遵循主从复制的架构,至少需要3个主节点,每个主节点有一个副本,即形成三主三从的配置。这样设计的原因是为了避免单点故障,即使一个主节点发生故障,其对应的副本节点可以接管服务,确保服务的连续性。 ...

    redis集群redis集群

    Redis集群通过将数据分布在多个Redis节点上,并且提供故障转移和水平扩展的能力。本文档详细介绍了如何在CentOS 6.6环境下,使用VMware虚拟机安装Redis集群,并确保每个步骤都经过了亲自实践验证,证明是可行的。 ...

    redis集群详细操作1

    Sentinel系统能够监控Redis主从节点,当检测到主节点故障时,自动进行故障转移,保证服务的连续性。 在实际操作中,理解Redis的基本概念、应用场景、安装配置以及客户端的使用是构建高效、稳定的Redis服务的关键。...

    redis7.0.0集群相关安装包

    2. **复制与故障转移**:Redis 集群支持主从复制,每个节点可以有多个从节点。如果主节点失败,其从节点将自动晋升为主节点,确保服务不间断。这个过程称为故障转移(Failover)。 3. **槽迁移**:在节点添加或移除...

    linux redis集群部署

    - **Slave to Master 选举**:集群具备自动故障转移能力,能够在主节点(Master)故障时自动选取一个备节点(Slave)作为新的主节点。 - **Hot Re-sharding (在线分片)**:支持在线的数据重新分布,可以在不影响现有服务...

    CentOS7.5安装Redis集群.docx

    使用 Redis 集群可以提高系统的可扩展性、可靠性和性能,可以水平扩展、负载均衡、故障转移等。 八、集群注意事项 在创建集群时需要注意一些问题,例如节点的 IP 地址、端口号、密码等需要一致,否则可能导致集群...

    docker-compose redis主从哨兵 redis多节点高可用 redis集群高可用

    2. **Redis哨兵系统(Sentinel)**:哨兵是Redis的监控和故障转移组件,它可以监控主从节点的状态,当主节点故障时自动进行故障转移。在Docker Compose中,我们需要定义额外的哨兵节点,配置哨兵间的心跳检测和故障...

    大规模redis集群的服务治理之路

    ### 大规模Redis集群的服务治理之路 #### 一、Redis Cluster简介 Redis Cluster是一种用于构建大规模、高性能Redis集群的技术方案,旨在提供一种可扩展、高可用的分布式存储解决方案。其核心设计思想是通过去中心...

    redis集群工具包和配置

    Redis Cluster是Redis官方提供的原生集群解决方案,它通过数据分片(Sharding)来实现数据的分布式存储,并且具备故障转移功能,确保服务的高可用性。 在Windows环境下配置Redis集群,首先需要安装以下几个关键组件...

Global site tag (gtag.js) - Google Analytics