Redis集群节点通信过程/原理流程分析

目录
  • 简介
  • 通信流程
  • Gossip消息
    • 消息流程
    • 消息格式
  • 节点选择
    • 1.选择发送消息的节点数量
    • 2.消息数据量
  • 其他网址

简介

本文介绍Redis的Cluster(集群)的节点通信的流程。

通信流程

在分布式存储中需要提供维护节点元数据信息的机制, 所谓元数据是指: 节点负责哪些数据, 是否出现故障等状态信息。 常见的元数据维护方式分为: 集中式和P2P方式。 Redis集群采用P2P的Gossip(流言) 协议,Gossip协议工作原理就是节点彼此不断通信交换信息, 一段时间后所有的节点都会知道集群完整的信息, 这种方式类似流言传播, 如下所示

通信过程说明:

  • 集群中的每个节点都会单独开辟一个TCP通道, 用于节点之间彼此通信, 通信端口号在基础端口上加10000。
  • 每个节点在固定周期内通过特定规则选择几个节点发送ping消息。接收到ping消息的节点用pong消息作为响应。
  • 集群中每个节点通过一定规则挑选要通信的节点, 每个节点可能知道全部节点, 也可能仅知道部分节点, 只要这些节点彼此可以正常通信, 最终它们会达到一致的状态。 当节点出故障、 新节点加入、 主从角色变化、 槽信息变更等事件发生时, 通过不断的ping/pong消息通信, 经过一段时间后所有的节点都会知道整个集群全部节点的最新状态, 从而达到集群状态同步的目的。

Gossip消息

消息流程

Gossip协议的主要职责就是信息交换。 信息交换的载体就是节点彼此发送的Gossip消息, 了解这些消息有助于我们理解集群如何完成信息交换。

常用的Gossip消息可分为: ping消息、 pong消息、 meet消息、 fail消息等, 它们的通信模式如下图所示:

  • meet消息: 用于通知新节点加入。

消息发送者通知接收者加入到当前集群, meet消息通信正常完成后, 接收节点会加入到集群中并进行周期性的ping、 pong消息交换。

  • ping消息: 集群内交换最频繁的消息

集群内每个节点每秒向多个其他节点发送ping消息, 用于检测节点是否在线和交换彼此状态信息。 ping消息发送封装了自身节点和部分其他节点的状态数据。

  • pong消息: 当接收到ping、 meet消息时, 作为响应消息回复给发送方确认消息正常通信。

pong消息内部封装了自身状态数据。 节点也可以向集群内广播自身的pong消息来通知整个集群对自身状态进行更新。
fail消息: 当节点判定集群内另一个节点下线时, 会向集群内广播一个fail消息, 其他节点接收到fail消息之后把对应节点更新为下线状态。 具体细节将在后面“故障转移”中说明。

消息格式

所有的消息格式划分为: 消息头和消息体。 消息头包含发送节点自身状态数据, 接收节点根据消息头就可以获取到发送节点的相关数据, 结构如下:

typedef struct {
    char sig[4]; /* 信号标示 */
    uint32_t totlen; /* 消息总长度 */
    uint16_t ver; /* 协议版本*/
    uint16_t type; /* 消息类型,用于区分meet,ping,pong等消息 */
    uint16_t count; /* 消息体包含的节点数量, 仅用于meet,ping,ping消息类型*/
    uint64_t currentEpoch; /* 当前发送节点的配置纪元 */
    uint64_t configEpoch; /* 主节点/从节点的主节点配置纪元 */
    uint64_t offset; /* 复制偏移量 */
    char sender[CLUSTER_NAMELEN]; /* 发送节点的nodeId */
    unsigned char myslots[CLUSTER_SLOTS/8]; /* 发送节点负责的槽信息 */
    char slaveof[CLUSTER_NAMELEN]; /* 如果发送节点是从节点, 记录对应主节点的nodeId */
    uint16_t port; /* 端口号 */
    uint16_t flags; /* 发送节点标识,区分主从角色, 是否下线等 */
    unsigned char state; /* 发送节点所处的集群状态 */
    unsigned char mflags[3]; /* 消息标识 */
    union clusterMsgData data /* 消息正文 */;
} clusterMsg;

集群内所有的消息都采用相同的消息头结构clusterMsg, 它包含了发送节点关键信息, 如节点id、 槽映射、 节点标识(主从角色, 是否下线) 等。消息体在Redis内部采用clusterMsgData结构声明, 结构如下:

union clusterMsgData {
    /* ping,meet,pong消息体*/
    struct {
        /* gossip消息结构数组 */
        clusterMsgDataGossip gossip[1];
    } ping;

    /* FAIL 消息体 */
    struct {
        clusterMsgDataFail about;
    } fail;
    // ...
};

消息体clusterMsgData定义发送消息的数据, 其中ping、 meet、 pong都采用cluster MsgDataGossip数组作为消息体数据, 实际消息类型使用消息头的type属性区分。 每个消息体包含该节点的多个clusterMsgDataGossip结构数据, 用于信息交换, 结构如下:

typedef struct {
    char nodename[CLUSTER_NAMELEN]; /* 节点的nodeId */
    uint32_t ping_sent; /* 最后一次向该节点发送ping消息时间 */
    uint32_t pong_received; /* 最后一次接收该节点pong消息时间 */
    char ip[NET_IP_STR_LEN]; /* IP */
    uint16_t port; /* port*/
    uint16_t flags; /* 该节点标识, */
} clusterMsgDataGossip;

当接收到ping、 meet消息时, 接收节点会解析消息内容并根据自身的识别情况做出相应处理, 对应流程如下图所示:

接收节点收到ping/meet消息时, 执行解析消息头和消息体流程:

  • 解析消息头过程:

消息头包含了发送节点的信息, 如果发送节点是新节点且消息是meet类型, 则加入到本地节点列表; 如果是已知节点, 则尝试更新发送节点的状态, 如槽映射关系、 主从角色等状态。

  • 解析消息体过程:

如果消息体的clusterMsgDataGossip数组包含的节点是新节点, 则尝试发起与新节点的meet握手流程; 如果是已知节点, 则根据cluster MsgDataGossip中的flags字段判断该节点是否下线, 用于故障转移。
消息处理完后回复pong消息, 内容同样包含消息头和消息体, 发送节点接收到回复的pong消息后, 采用类似的流程解析处理消息并更新与接收节点最后通信时间, 完成一次消息通信。

节点选择

虽然Gossip协议的信息交换机制具有天然的分布式特性, 但它是有成本的。 由于内部需要频繁地进行节点信息交换, 而ping/pong消息会携带当前节点和部分其他节点的状态数据, 势必会加重带宽和计算的负担。 Redis集群内节点通信采用固定频率(定时任务每秒执行10次) 。 因此节点每次选择需要通信的节点列表变得非常重要。 通信节点选择过多虽然可以做到信息及时交换但成本过高。 节点选择过少会降低集群内所有节点彼此信息交换频率,从而影响故障判定、 新节点发现等需求的速度。 因此Redis集群的Gossip协议需要兼顾信息交换实时性和成本开销, 通信节点选择的规则如下图所示

根据通信节点选择的流程可以看出消息交换的成本主要体现在单位时间选择发送消息的节点数量和每个消息携带的数据量。

1.选择发送消息的节点数量

集群内每个节点维护定时任务默认每秒执行10次, 每秒会随机选取5个节点找出最久没有通信的节点发送ping消息, 用于保证Gossip信息交换的随机性。 每100毫秒都会扫描本地节点列表, 如果发现节点最近一次接受pong消息的时间大于cluster_node_timeout/2, 则立刻发送ping消息, 防止该节点信息太长时间未更新。 根据以上规则得出每个节点每秒需要发送ping消息的数
量=1+10*num(node.pong_received>cluster_node_timeout/2) , 因此cluster_node_timeout参数对消息发送的节点数量影响非常大。 当我们的带宽资源紧张时, 可以适当调大这个参数, 如从默认15秒改为30秒来降低带宽占用率。 过度调大cluster_node_timeout会影响消息交换的频率从而影响故障转移、 槽信息更新、 新节点发现的速度。 因此需要根据业务容忍度和资源消耗进行平衡。 同时整个集群消息总交换量也跟节点数成正比。

2.消息数据量

每个ping消息的数据量体现在消息头和消息体中, 其中消息头主要占用空间的字段是myslots[CLUSTER_SLOTS/8], 占用2KB, 这块空间占用相对固定。 消息体会携带一定数量的其他节点信息用于信息交换。 具体数量见以下伪代码:

def get_wanted():
    int total_size = size(cluster.nodes)

    # 默认包含节点总量的1/10
    594int wanted = floor(total_size/10);
    if wanted < 3:
    # 至少携带3个其他节点信息
    wanted = 3;
    if wanted > total_size -2 :
    # 最多包含total_size - 2个
    wanted = total_size - 2;
    return wanted;

根据伪代码可以看出消息体携带数据量跟集群的节点数息息相关, 更大的集群每次消息通信的成本也就更高, 因此对于Redis集群来说并不是大而全的集群更好, 对于集群规模控制的建议见之后“集群运维”。

其他网址

《Redis开发与运维》=> 第10章 集群=> 10.3 节点通信

到此这篇关于Redis集群节点通信过程/原理的文章就介绍到这了,更多相关Redis集群节点通信内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 深入浅析Redis 集群伸缩原理

    Redis 节点分别维护自己负责的槽和对应的数据.伸缩原理:Redis 槽和对应数据在不同节点之间移动 环境:CentOS7 搭建 Redis 集群 一.集群扩容 1. 手动扩容 (1) 准备节点 9007,并加入集群 192.168.11.40:9001> cluster meet 192.168.11.40 9007 [注意]若 cluster meet 加入已存在于其它集群的节点,会导致集群合并,造成数据错乱!.建议使用 redis-cli 的 add-node: # 若节点已加入其它集群

  • Redis集群新增、删除节点以及动态增加内存的方法

    目录 一.新增服务节点到集群中 1.创建配置文件 2.启动新的端口 3.将新增的两个端口增加到现有集群中 4.设置从节点 5.设置主节点master 二.删除节点 1.删除从节点 2.删除主节点 三.动态扩容内存 1.动态将7002端口内存从5G提升至10G 一.新增服务节点到集群中 1.创建配置文件 在主机127.0.0.5上创建新端口的配置文件,如之前有端口直接复制之前的配置文件即可.复制完然后修改下配置文件里的端口.内存大小.pid的路径等. cp redis7001.conf redis

  • Redis cluster集群模式的原理解析

    redis cluster redis cluster是Redis的分布式解决方案,在3.0版本推出后有效地解决了redis分布式方面的需求 自动将数据进行分片,每个master上放一部分数据 提供内置的高可用支持,部分master不可用时,还是可以继续工作的 支撑N个redis master node,每个master node都可以挂载多个slave node 高可用,因为每个master都有salve节点,那么如果mater挂掉,redis cluster这套机制,就会自动将某个slave

  • Redis Cluster集群收缩主从节点详细教程

    目录 1.Cluster集群收缩概念 2.将6390主节点从集群中收缩 2.1.计算需要分给每一个节点的槽位数 2.2.分配1365个槽位给192.168.81.210的6380节点 2.3.分配1365个槽位给192.168.81.220的6380节点 2.4.分配1365个槽位给192.168.81.230的6380节点 2.5.查看当前集群槽位分配 3.验证数据迁移过程是否导致数据异常 4.将下线的主节点从集群中删除 4.1.删除节点 4.2.调整主从交叉复制 4.3.当节点存在数据无法删

  • Redis Cluster集群数据分片机制原理

    Redis Cluster数据分片机制 Redis 集群简介 Redis Cluster 是 Redis 的分布式解决方案,在 3.0 版本正式推出,有效地解决了 Redis 分布式方面的需求. Redis Cluster 一般由多个节点组成,节点数量至少为 6 个才能保证组成完整高可用的集群,其中三个为主节点,三个为从节点.三个主节点会分配槽,处理客户端的命令请求,而从节点可用在主节点故障后,顶替主节点. 如上图所示,该集群中包含 6 个 Redis 节点,3主3从,分别为M1,M2,M3,S

  • Redis集群节点通信过程/原理流程分析

    目录 简介 通信流程 Gossip消息 消息流程 消息格式 节点选择 1.选择发送消息的节点数量 2.消息数据量 其他网址 简介 本文介绍Redis的Cluster(集群)的节点通信的流程. 通信流程 在分布式存储中需要提供维护节点元数据信息的机制, 所谓元数据是指: 节点负责哪些数据, 是否出现故障等状态信息. 常见的元数据维护方式分为: 集中式和P2P方式. Redis集群采用P2P的Gossip(流言) 协议,Gossip协议工作原理就是节点彼此不断通信交换信息, 一段时间后所有的节点都会

  • 比较几种Redis集群方案

    目录 一.概述 二.Redis高可用集群搭建 三.Redis集群节点间的通信机制 3.1.集中式 3.2.gossip 四.网络抖动 五.Redis集群选举原理分析 5.1.集群是否完整才能对外提供服务 5.2.Redis集群为什么至少需要三个master节点,并且推荐节点数为奇数? 5.3.哨兵leader选举流程 六.新增/删除节点 一.概述 在Redis3.0以前的集群一般是借助哨兵sentinel工具来监控主节点的状态,如果主节点异常,则会做主从切换,将某一台slave作为master.

  • 在K8s上部署Redis集群的方法步骤

    一.前言 架构原理:每个Master都可以拥有多个Slave.当Master下线后,Redis集群会从多个Slave中选举出一个新的Master作为替代,而旧Master重新上线后变成新Master的Slave. 二.准备操作 本次部署主要基于该项目:https://github.com/zuxqoj/kubernetes-redis-cluster 其包含了两种部署Redis集群的方式: StatefulSet Service&Deployment 两种方式各有优劣,对于像Redis.Mong

  • Redis集群的离线安装步骤及原理详析

    前言 本文主要是记录一下Redis集群在linux系统下离线的安装步骤,毕竟在生产环境下一般都是无法联网的,Redis的集群的Ruby环境安装过程还是很麻烦的,涉及到很多的依赖的安装,所以写了一个文章来进行记录.本文分为两部分,第一部分先通过原生命令的安装来实现redis集群的部署,通过原生命令的安装对于了解redis集群的实现原理有很大的帮助,第二部分通过官方工具Ruby来进行Redis集群的安装,通过Ruby安装Redis集群的时候主要是搭建好Ruby环境,真正Redis集群的安装配置通过R

  • Redis集群水平扩展、集群中添加以及删除节点的操作

    在Redis集群搭建中,我们搭建了下图所示的Redis集群,接下来我们就来看看如何为我们的Redis集群进行水平扩容. [root@localhost redis-5.0.3]# src/redis-server redis-cluster/8001/redis.conf [root@localhost redis-5.0.3]# src/redis-server redis-cluster/8004/redis.conf [root@localhost redis-5.0.3]# src/re

  • redis集群搭建过程(非常详细,适合新手)

    目录 redis集群搭建 一.Redis Cluster(Redis集群)简介 二.集群搭建需要的环境 三.集群搭建具体步骤如下(注意要关闭防火墙) 四.结语 redis集群搭建 在开始redis集群搭建之前,我们先简单回顾一下redis单机版的搭建过程 下载redis压缩包,然后解压压缩文件: 进入到解压缩后的redis文件目录(此时可以看到Makefile文件),编译redis源文件: 把编译好的redis源文件安装到/usr/local/redis目录下,如果/local目录下没有redi

  • Redis自动化安装及集群实现搭建过程

    Redis实例安装 安装说明:自动解压缩安装包,按照指定路径编译安装,复制配置文件模板到Redis实例路的数据径下,根据端口号修改 配置文件模板 配置文件,当前shell脚本,安装包 参数1:basedir,redis安装包路径 参数2:安装实例路径 参数3:安装包名称 参数4:安装实例的端口号 #!/bin/bash set -e if [ $# -lt 4 ]; then echo "$(basename $0): Missing script argument" echo &qu

  • Redis集群增加节点与删除节点的方法详解

    前言 本文主要是承接上一篇文章Redis集群的离线安装成功以后,我们如何进行给集群增加新的主从节点(集群扩容)以及如何从集群中删除节点(集群缩容),也就是集群的伸缩,集群伸缩的原理是控制虚拟槽和数据在节点之间进行移动,通过实际操作来整理一下集群的伸缩. 上篇文章中搭建好的集群为三主三从,端口号为7000.7001.7002.7003.7004.7005. 查看集群启动情况:ps -ef | grep redis 查看集群的slots分配情况以及节点之间的主从关系: 首先登陆节点7000:redi

随机推荐