深入解析redis cluster gossip机制

news/2024/6/29 12:50:52
社区版redis cluster是一个P2P无中心节点的集群架构,依靠gossip协议传播协同自动化修复集群的状态。本文将深入redis cluster gossip协议的细节,剖析redis cluster gossip协议机制如何运转。

协议解析

cluster gossip协议定义在在ClusterMsg这个结构中,源码如下:
typedef struct {char sig[4];        /* Signature "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 lastepoch advertised by its master if it is aslave. */uint64_t offset;    /* Master replication offset if node is a master orprocessed 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;
可以对此结构将消息分为三部分:
1、sender的基本信息:
sender: node name
configEpoch:每个master节点都有一个唯一的configEpoch做标志,如果和其他master节点冲突,会强制自增使本节点在集群中唯一
slaveof:master信息,假如本节点是slave节点的话,协议带有master信息
offset:主从复制的偏移
flags:本节点当前的状态,比如 CLUSTER_NODE_HANDSHAKE、CLUSTER_NODE_MEET
mflags:本条消息的类型,目前只有两类:CLUSTERMSG_FLAG0_PAUSED、CLUSTERMSG_FLAG0_FORCEACK
myslots:本节点负责的slots信息
port:
cport:
ip:
2、集群视图的基本信息:
currentEpoch:表示本节点当前记录的整个集群的统一的epoch,用来决策选举投票等,与configEpoch不同的是:configEpoch表示的是master节点的唯一标志,currentEpoch是集群的唯一标志。
3、具体的消息,对应clsuterMsgData结构中的数据: 
ping、pong、meet:clusterMsgDataGossip,这个协议将sender节点中保存的集群所有节点的信息都发送给对端,节点个数在clusterMsg的字段count中定义,这个协议包含其他节点的信息的字段有:
  • nodename:
  • ping_sent:最近一次sender节点给该节点发送ping的时间点。收到pong回复后ping_sent会被赋值为0
这里作者用了一个技巧去减少gossip通信带宽。
如果receiver节点上关于该节点的ping_sent=0 并且没有任何节点正在failover&该节点没有fail&receiver节点上关于该节点的pong_received<sender上的pong_received并且sender的pong_received大于receiver节点内核时间的500ms内,则将receiver节点关于该节点的pong_received时间设置为和sender节点一致,复用sender节点的pong_received。那么received节点则会减少对该节点发送ping。参考issue:https://github.com/antirez/redis/issues/3929
  • pong_received:最近一次sender节点收到该节点发送pong的时间点
  • ip:
  • port:
  • cport:
  • flags:对应clusterMsg的flags,只不过存储的其他节点的
fail:clusterMsgDataFail,只有一个表示fail节点的nodename字段, 统计超过一半以上节点任务node pfail后发送fail msg
publish:clusterMsgDataPublish,集群间同步publish信息,以支持客户端在任一节点发送pub/sub
update:clusterMsgDataUpdate,当receiver节点发现sender节点的configepoch低于本节点的时候,会给sender节点发送一个update消息通知sender节点更新状态,包含:
  • configEpoch:receiver节点中保存的sender节点的configepoch
  • nodename:receiver节点中保存的sender节点的nodename
  • slots:receiver节点中保存的sender节点的slots列表

运转机制

通过gossip协议,cluster可以提供集群间状态同步更新、选举自助failover等重要的集群功能。

握手联结

客户端给节点X发送cluster meet 节点Y的请求后,节点X之后就会尝试主从和节点Y建立连接。此时在节点X中保存节点Y的状态是:
  • CLUSTER_NODE_HANDSHAKE:表示节点Y正处于握手状态,只有收到来自节点Y的ping、pong、meet其中一种消息后该状态才会被清除
  • CLUSTER_NODE_MEET:表示还未给节点Y发送meet消息,一旦发送该状态清除,不管是否成功
以下是meet过程:
(0)节点X通过getRandomHexChars这个函数给节点Y随机生成nodename
(1)节点X 在clusterCron运转时会从cluster->nodes列表中获取未建立tcp连接,如未发送过meet,发送CLUSTERMSG_TYPE_MEET,节点Y收到meet消息后:
(2)查看节点X还未建立握手成功,比较sender发送过来的消息,更新本地关于节点X的信息
(3)查看节点X在nodes不存在,添加X进nodes,随机给X取nodename。状态设置为CLUSTER_NODE_HANDSHAKE
(4)进入gossip处理这个gossip消息携带的集群其他节点的信息,给集群其他节点建立握手。
(5)给节点X发送CLUSTERMSG_TYPE_PONG,节点Y处理结束(注意此时节点Y的clusterReadHandler函数link->node为NULL)。
(6)节点X收到pong后,发现和节点Y正处在握手阶段,更新节点Y的地址和nodename,清除CLUSTER_NODE_HANDSHAKE状态。
(7)节点X在cron()函数中将给未建立连接的节点Y发送ping
(8)节点Y收到ping后给节点X发送pong
(9)节点X将保存的节点Y的状态CLUSTER_NODE_HANDSHAKE清除,更新一下nodename和地址,至此握手完成,两个节点都保存相同的nodename和信息。
68692e492336e8052a5a0e87e20460c59959caca
看完整个握手过程后,我们尝试思考两个问题:
1、如果发送meet失败后,节点X的状态CLUSTER_NODE_MEET状态又被清除了,cluster会如何处理呢?
这时候节点Y在下一个clusterCron()函数中会直接给节点Y发送ping,但是不会将节点X存入cluster->nodes,导致节点X认为已经建立连接,然而节点Y并没有承认。在后面节点传播中,如果有其他节点持有节点X的信息并给节点Y发送ping,也会触发节点Y主动再去给节点X发送meet建立连接。
2、如果节点Y已经有存储节点X,但还是收到了节点X的meet请求,如何处理?
  • nodename相同:
(1)节点Y发送pong给节点X
(2)如果正处于握手节点,会直接删除节点,这里会导致节点Y丢失了节点X的消息。相当于问题1。
(3)非握手阶段往下走正常的ping流程
  • nodename不同:
(1)节点Y重新创建一个随机nodename放入nodes中并设置为握手阶段,此时有两个nodename存在。
(2)节点Y发送pong给节点X
(3)节点Y如果已经创建过和节点X的连接,节点Y会在本地更新节点X的nodename,删除第一个nodename存储的node,更新握手状态,此时只剩下第二个正确的nodename。
(4)节点Y如果没创建过和节点X的链接,会在clustercron()中再次给节点X发送ping请求,两个nodename会先后各发送一次。
(5)第一个nodename发送ping后,在收到节点X回复的pong中,更新节点X的nodename
(6)第二个nodename发送ping后,在收到节点X回复的pong中,发送节点X的nodename已经存在,第二个nodename处于握手状态,这时候直接删除了第二个nodename。
结论:只有nodename相同并且两个节点都在握手阶段,会导致其中一个节点丢掉另外一个节点。

健康检测及failover

详情见文章:https://yq.aliyun.com/articles/638627?utm_content=m_1000016044

状态更新及冲突解决

假如出现两个master的时候gossip协议是如何处理冲突的呢?
首先要理解两个重要的变量:
  • configEpoch: 每个分片有唯一的epoch值,主备epoch应该一致
  • currentEpoch:集群当前的epoch,=集群中最大分片的epoch
在ping包中会自带sender节点的slots信息和currentEpoch, configEpoch。
master节点收到来自slave节点后的处理流程:
(1)receiver比较sender的角色,
  • 如果sender认为自己是master,但是在receiver被标记为slave,则receiver节点在集群视图中将sender标记为master。
  • 如果sender认为自己是slave,但是在receiver被标记为master, 则在receiver的集群视图中将sender标记为slave, 加入到sender标记的master中,并且删除sender在reciver集群视图中的slots信息。
(2)比较sender自带的slot信息和receiver集群视图中的slots是否冲突,有冲突则进行下一步比较
(3)比较sender的configEpoch 是否 > receiver集群视图中的slots拥有者的configepoch,如是在clusterUpdateSlotsConfigWith函数中重新设置slots拥有者为sender,并且将旧slots拥有者设置为sender的slave,再比较本节点是有脏slot, 有则清除掉。
(4)比较sender自身的slots信息 < receiver集群视图中的slots拥有者的configepoch,发送update信息,通知sender更新,sender节点也会执行clusterUpdateSlotsConfigWith函数。
8abfc607e1649060b2e14dabec47a6ecd57c791b
如果两个节点的configEpoch, currentEpoch,角色都是master, 这时候如何处理呢?
receiver的currentEpoch自增并且赋值给configEpoch,也就是强制自增来解决冲突。这时候因为configEpoch大,又可以走回上文的流程。
所以可能存在双master同时存在的情况,但是最终会挑选出新的master。

结束语

云数据库Redis版(ApsaraDB for Redis)是一种稳定可靠、性能卓越、可弹性伸缩的数据库服务。基于飞天分布式系统和全SSD盘高性能存储,支持主备版和集群版两套高可用架构。提供了全套的容灾切换、故障迁移、在线扩容、性能优化的数据库解决方案。欢迎各位购买使用:云数据库 Redis 版

http://lihuaxi.xjx100.cn/news/236604.html

相关文章

老年手机英文改中文_这些手游大作你都玩了吗?手机游戏推荐

全 世 界 只 有 1 % 的 人 关 注 郭 叔 说你 真 是 个 特 别 的 人目前100000人 已关注 郭叔说郭叔说做一个有趣的人&#xff0c;从认识我开始。关注攻略交流群请添加微信&#xff1a;GLT962464 备注老规矩&#xff1a;游戏名(无备注不通过&#xff01;&#xff01;&#xf…

openPGP加密解密

首先请大家一定要搞清楚加密解密概念&#xff1a; 下面这是百度出来的。 如果只是单方面采用非对称性加密算法,其实有两种方式,用于不同用处. 第一种是签名,使用私钥加密,公钥解密,用于让所有公钥所有者验证私钥所有者的身份并且用来防止私钥所有者发布的内容被篡改.但是不用来…

MakeCode图形化编程语言学习笔记:micro:bit编程练习题[图]

2019独角兽企业重金招聘Python工程师标准>>> MakeCode图形化编程语言学习笔记&#xff1a;micro:bit编程练习题[图]&#xff1a; 基础训练题&#xff1a; Q1&#xff1a;摇晃micro:bit编程板&#xff0c;随机出现7个小动物图标中的一个&#xff0c;并且前后相邻两次…

011:视图函数介绍

视图&#xff1a; 视图一般都写在 app 的 views.py 中。并且视图的第一个参数永远都是 request &#xff08;一个HttpRequest&#xff09;对象。这个对象存储了请求过来的所有信息&#xff0c;包括携带的参数以及一些头部信息等。在视图中&#xff0c;一般是完成逻辑相关的操作…

java设计一个bank类实现银行_SAP银企直连之平安银行(ECC版)

关于讲解SAP中国本地化银企直连系统功能&#xff0c;它通过ECC和S4 HANA 1909两个不同版本的演示来讲解银企直连付款相关功能实施和应用&#xff0c;有兴趣的可以联系微信号&#xff1a;timijia进行付费获取。以下资料仅供大家参考&#xff1a;说明&#xff1a;因为平安银行较S…

传承乡邦文化,展示国学之美,联墨香飘远,文明花放红;

2019独角兽企业重金招聘Python工程师标准>>> 12月16日上午&#xff0c;阳光普照&#xff0c;翰墨飘香。由揭阳市文联指导、揭阳市楹联学会主办、榕城区图书馆协办的“我们的美好生活”原创联墨作品展在榕城区图书馆隆重开幕。 此次活动意在传承乡邦文化&#xff0c;…

Windows和Linux的编译理解

Windows一般编译出来的x86的软件&#xff0c;就是只能在x86的系统上才能运行&#xff0c;同理&#xff0c;在x64系统上也是一样的道理。 Linux利用gcc编译器编译&#xff0c;可以在Linux上面运行&#xff0c;但是想要在嵌入式系统上运行的话&#xff0c;需要在Linux上安装相应的…

定义一个属性_Python property属性

1. 什么是property属性一种用起来像是使用的实例属性一样的特殊属性&#xff0c;可以对应于某个方法# ############### 定义 ###############class Foo: def func(self): pass # 定义property属性 property def prop(self): pass# ############### 调用 ###############foo_obj…