美文网首页
redis集群 第一节 节点

redis集群 第一节 节点

作者: c84f3109853b | 来源:发表于2017-04-10 00:15 被阅读0次

    一个Redis集群通常由多个节点组成,在刚开始的时候,每个节点都是相互独立的,它们都处于一个只包含自己的集群当中,要组件一个真正可工作的集群,我们必须将各个独立的节点连接起来,构成一个包含多个节点的集群。
    连接各个节点的工作可以使用CLUSTER MEET命令来完成,该命令的格式如下:

    CLUSTER MEET <ip> <port>

    向一个节点node发送CLUSTER MEET命令,可以让node节点与ip和port所指定的节点进行握手(handshake),当握手成功时,node节点就会将ip和port所指定的节点添加到当前所在的集群中。

    1.1 启动节点

    一个节点就是一个运行在集群模式下的Redis服务器,Redis服务器在启动时会根据cluster-enabled配置选项是否为yes来决定是否开启服务器的集群模式。
    节点(运行在集群模式下的Redis服务器)会继续使用所有在单机模式中使用的服务器组件,比如说:

    • 节点会继续使用文件事件处理器来处理命令请求和返回命令回复。
    • 节点会继续使用时间事件处理器来执行serverCron函数,而serverCron函数又会调用集群模式特有的clusterCron函数。clusterCron函数负责执行在集群模式下需要执行的常规操作,例如向集群中的其他节点发送Gossip消息,检查节点是否断线,或者检查是否需要对下线节点进行自动故障转移等。
    • 节点会继续使用数据库来保存键值对数据,键值对依然会是各种不同类型的对象。
    • 节点会继续使用RDB持久化模块和AOF持久化模块来执行持久化工作。
    • 节点会继续使用发布与订阅模块来执行PUBLISH、SUBSCRIBE等命令。
    • 节点会继续使用复制模块来进行节点的复制工作。
    • 节点会继续使用Lua脚本环境来执行客户端输入的Lua脚本。
    • 节点会继续使用redisServer结构来保存服务器的状态,使用redisClient结构来保存客户端的状态,至于那些只有在集群模式下才会用到的数据,节点将它们保存到了cluster.h/clusterNode结构、cluster.h/clusterLink结构,以及cluster.h/clusterState结构里面。

    1.2 集群数据结构

    clusterNode结构保存了一个节点的当前状态,比如节点的创建时间、节点的名字、节点当前的配置纪元、节点的IP地址和端口号等等。
    每个节点斗湖使用一个clusterNode结构来记录自己的状态,并为集群中的所有其他节点(包括主节点和从节点)都创建一个相应的clusterNode结构,以此来记录其他节点的状态。

    struct clusterNode {
    // 创建节点的时间
    mstime_t ctime;
    // 节点的名字,由40个十六进制字符组成
    // 例如例如 68eef66df23420a5862208ef5b1a7005b806f2ff
    char name[REDIS_CLUSTER_NAMELEN];
    // 节点标识
    // 使用各种不同的标识值记录节点的角色(比如主节点或者从节点),
    // 以及节点目前所处的状态(比如在线或下线)。
    int flags;
    // 节点当前的配置纪元,用于实现故障转移
    uint64_t configEpoch;
    // 节点的IP地址
    char ip[REDIS_IP_STR_LEN];
    // 节点的端口号
    int port;
    // 保存连接节点所需的有关信息
    clusterLink *link;
    // ...
    };

    clusterNode结构的link属性是一个clusterLink结构,该结构保存了连接节点所需的有关信息,比如套接字描述符,输入缓冲区和输出缓存区:

    typedef struct clusterLink {
    // 连接的创建时间
    mstime_t ctime;
    // 套接字描述符
    int fd;
    // 输出缓冲区,保存着等待发送给其他节点的消息(message)。
    sds sndbuf;
    // 输入缓冲区,保存着从其他节点接收到的消息。
    sds rcvbuf;
    // 与这个连接相关联的其他节点,如果没有的话就为NULL
    struct clusterNode *node;
    } clusterLink;

    redisClient结构和clusterLink结构都有自己的套接字描述符和输入、输出缓冲区,这两个结构区别在于,redisClient结构中的套接字和缓冲区是用于连接客户端的,而clusterLink结构中的套接字和缓冲区则是用于连接节点的。
    最后,每个节点都保存着一个clusterState结构,这个结构记录了在当前节点的视角下,集群目前所处的状态,例如集群是在线还是下线,集群包含多少个节点,集群当前的配置纪元,诸如此类:

    typedef struct clusterState {
    // 指向当前节点的指针
    clusterNode *myself;
    // 集群当前的配置纪元,用于实现故障转移
    uint64_t currentEpoch;
    // 集群当前的状态:是在线还是下线
    int state;
    // 集群中至少处理着一个槽的节点的数量
    int size;
    // 集群节点名单(包括myself节点)
    // 字典的键为节点的名字,字典的值为节点对应的clusterNode结构
    dit *nodes;
    } clusterState;

    1.3 CLUSTER MEET命令的实现

    通过向节点A发送CLUSTER MEET命令,客户端可以让接收命令的节点A将另一个节点B添加到节点A当前所在的集群里面:

    CLUSTER MEET <ip> <port>

    收到命令的节点A将与节点B进行握手(handshake),以此来确认彼此的存在,并为将来的进一步通信打好基础:

    • 节点A会为节点B创建一个clusterNode结构,并将该结构添加到自己的clusterState.nodes字典里面
    • 之后,节点A将根据CLUSTER MEET命令给定的IP地址和端口号,向节点B发送一条MEET消息(message)
    • 如果一切顺利,节点B将接收到节点A发送的MEET消息,节点B会为节点A创建一个clusterNode结构,并将该结构添加到自己的clusterState.nodes字典里面
    • 之后,节点B将向节点A返回一条PONG消息
    • 如果一切顺利,节点A将接收到节点B返回的PONG消息,通过这条PONG消息节点A可以知道节点B已经成地接收了自己发送的MEET消息
    • 之后,节点A将向节点B返回一条PING消息
    • 如果一切顺利,节点B将接收到节点A返回的PING消息,通过这条PING消息节点B可以知道节点A已经成功地接收到了自己返回的PONG消息,握手完成。
    • 之后,节点A会将节点B的信息通过Gossip协议传播给集群中的其他节点,让其他节点也与节点B进行握手,最终,经过一段时间之后,节点B会被集群中的所有节点认识。

    相关文章

      网友评论

          本文标题:redis集群 第一节 节点

          本文链接:https://www.haomeiwen.com/subject/qzbjattx.html