前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis Cluster 节点间交互

Redis Cluster 节点间交互

作者头像
一个架构师
发布2022-06-20 19:56:00
3620
发布2022-06-20 19:56:00
举报
文章被收录于专栏:从码农的全世界路过

集群的原生创建中,我们知道只需要在一个节点上执行cluster meet命令就可以做到节点间的相互发现.今天我们就看下节点的发现过程以及节点间通信协议是什么样的.

一. gossip协议

Redis Cluster 集群的各节点间是采用gossip协议进行节点发现和通信.

gossip协议简单点说就是,我得到的信息是其他节点告诉我的,同时我也将我的信息和我知道的其他节点信息告诉别人,使整个集群达到最终一致.

二. MEET

看下cluster meet命令执行过程

1.首先调用clusterStartHandshake()方法,准备节点间握手.

2.判断当前是否已经在执行握手,已经在执行则不继续操作.

3.创建节点信息(clusterNode)并存储在server.cluster->nodes中.

4.这时该节点信息中并没有相关的link信息;节点标识状态node->flags 设置为CLUSTER_NODE_HANDSHAKE|CLUSTER_NODE_MEET,该节点并不是一个可用状态.

这个流程中只保存了节点信息, 节点间通信流程是通过定时任务clusterCron()完成,通信报文可以参考PING&PONG部分.

三. 定时任务

Redis设计了一套定时任务进行节点间通信.

1. 集群中节点通信是使用每秒执行10次的定时任务clusterCron()完成.

2. 定时任务会根据link和flags信息向其他节点间发送两种信息: MEET和PING

3. PING与MEET会随机选择其他节点信息作为流言信息(gossip)发送出去.

4. 节点消息体的封装和发送都会由clusterSendPing()方法进行执行;

5. 用于接收消息的端口并不是提供服务的6379端口,而是RCmb (Redis Cluster message bus)端口,默认是在服务端口上加10000的16379集群端口.

6. 对方节点通过clusterReadHandler()方法收到消息后,更新自己的server.cluster->nodes相关信息,同时会返回一个同样数据结构的PONG信息.

下文会详细说明下交互报文,也就清楚每次交互发送了哪些信息,收到哪些信息.

四. 报文协议

报文体分为两部分:报文头和报文体

报文头是自身节点信息;

报文体会有4种,后文会逐一说明.

(1) PING, MEET 和PONG

(2) FAIL

(3) PUBLISH

(4) UPDATE

报文头

主要包含自身节点的信息:port,cport,配置版本号,hash槽信息等.

代码语言:javascript
复制
typedef struct {
    char sig[4];        /* Siganture "RCmb" (Redis Cluster message bus). */
    uint32_t totlen;    /* Total length of this message */
    uint16_t ver;       /* Protocol version, currently set to 1. */
    uint16_t port;      /* TCP base port number. */
    uint16_t type;      /* Message type */
    uint16_t count;     /* Only used for some kind of messages. */
    uint64_t currentEpoch;  /* The epoch accordingly to the sending node. */
    uint64_t configEpoch;   /* The config epoch if it's a master, or the last
                               epoch advertised by its master if it is a
                               slave. */
    uint64_t offset;    /* Master replication offset if node is a master or
                           processed replication offset if node is a slave. */
    char sender[CLUSTER_NAMELEN]; /* Name of the sender node */
    unsigned char myslots[CLUSTER_SLOTS/8];
    char slaveof[CLUSTER_NAMELEN];
    char myip[NET_IP_STR_LEN];    /* Sender IP, if not all zeroed. */
    char notused1[34];  /* 34 bytes reserved for future usage. */
    uint16_t cport;      /* Sender TCP cluster bus port */
    uint16_t flags;      /* Sender node flags */
    unsigned char state; /* Cluster state from the POV of the sender */
    unsigned char mflags[3]; /* Message flags: CLUSTERMSG_FLAG[012]_... */
    union clusterMsgData data;
} clusterMsg;

报文体

报文体是使用共用体(union)定义,会根据发送消息的不同消息格式也不相同.

代码语言:javascript
复制
union clusterMsgData {
    /* PING, MEET and PONG */
    struct {
        /* Array of N clusterMsgDataGossip structures */
        clusterMsgDataGossip gossip[1];
    } ping;
    /* FAIL */
    struct {
        clusterMsgDataFail about;
    } fail;
    /* PUBLISH */
    struct {
        clusterMsgDataPublish msg;
    } publish;
    /* UPDATE */
    struct {
        clusterMsgDataUpdate nodecfg;
    } update;
};

五. 节点间交互信息

5.1 PING & PONG

上文已经阐述了节点间会不停的互相发送PING&PONG心跳包,交互各节点间的状态.

具体报文体是一个最大长度为2的clusterMsgDataGossip[]数组;

如果有PFAIL状态的节点信息,也会追加到消息后面,一同发出去.

结构体内容为当前服务节点缓存的其他节点的信息

代码语言:javascript
复制
typedef struct {
    char nodename[CLUSTER_NAMELEN];
    uint32_t ping_sent;
    uint32_t pong_received;
    char ip[NET_IP_STR_LEN];  /* IP address last time it was seen */
    uint16_t port;              /* base port last time it was seen */
    uint16_t cport;             /* cluster port last time it was seen */
    uint16_t flags;             /* node->flags copy */
    uint32_t notused1;
} clusterMsgDataGossip

5.2 PFAIL & FAIL

与sentinel模式相似PFAIL和FAIL 分别表示一个节点服务的主观宕机和客观宕机.它们是根据各节点间的PING,PONG信息进行传递交互的,具体流程如下:

1. 集群中当一个节点向另一个节点发送PING命令,但是目标节点未在给定的时限(node timeout)内返回PONG时,那么发送命令的节点会将目标节点标记为PFAIL(possibly failing).

2. 为了保证链接有效,在超过(timeout/2)的时间内还没收到回复时,会重新建立链接,再次发送PING信息.

3. 当节点接收到其它节点发送来的信息时,它会记下哪些被其它节点标记为失效的节点,这称之为失效报告(failure report);

4. 如果当前节点已经将某个节点标记为PFAIL,并且根据所收到的失效报告显示,集群中的大部分其它主节点也认为该节点进入了PFAIL状态,那么节点将会把哪个节点标记为失效状态FAIL;

5.一旦某个节点被标记为FAIL,关于这个节点已失效的信息就会通过clusterSendFail()方法广播到整个集群中,所有接收到这条信息的节点都会将失效节点标记为FAIL;

此时发送的报文头clusterMsg->type值为:CLUSTERMSG_TYPE_FAIL,

报文体是struct clusterMsgDataFail结构.

代码语言:javascript
复制
typedef struct {
    char nodename[CLUSTER_NAMELEN];
} clusterMsgDataFail;

5.3 PUB/SUB

在cluster模式下进行pub/sub时,是将pub/sub channel和pub/sub内容信息发送到一个节点后,由该节点组装报文对集群中其他节点进行广播,将pub/sub信息转发出去.

报文头clusterMsg->type值为CLUSTERMSG_TYPE_PUBLISH

报文体部分的结构是clusterMsgDataPublish

代码语言:javascript
复制
typedef struct {
    uint32_t channel_len;
    uint32_t message_len;
    /* We can't reclare bulk_data as bulk_data[] since this structure is
     * nested. The 8 bytes are removed from the count during the message
     * length computation. */
    unsigned char bulk_data[8];
} clusterMsgDataPublish;

如执行命令: publish topic msg

数据格式:

5.4 配置版本变更

当节点发现接收到的报文头中的configepoch低于自己的时候,会通过clusterSendUpdate()方法,将自己的hash槽信息组装成报文发送回sender节点,进行hash槽信息同步.

代码语言:javascript
复制
typedef struct {
    uint64_t configEpoch; /* Config epoch of the specified instance. */
    char nodename[CLUSTER_NAMELEN]; /* Name of the slots owner. */
    unsigned char slots[CLUSTER_SLOTS/8]; /* Slots bitmap. */
} clusterMsgDataUpdate;

综上,我们了解了节点间的信息通信与交互.

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 从码农的全世界路过 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档