社区版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和信息。

看完整个握手过程后,我们尝试思考两个问题:
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函数。
如果两个节点的configEpoch, currentEpoch,角色都是master, 这时候如何处理呢?
receiver的currentEpoch自增并且赋值给configEpoch,也就是强制自增来解决冲突。这时候因为configEpoch大,又可以走回上文的流程。
所以可能存在双master同时存在的情况,但是最终会挑选出新的master。

结束语

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

深入解析redis cluster gossip机制相关推荐

  1. Redis Cluster Gossip 协议详解

    Redis Cluster Gossip 协议 大家好,我是历小冰,今天来讲一下 Reids Cluster 的 Gossip 协议和集群操作,文章的思维导图如下所示. 集群模式和 Gossip 简介 ...

  2. 算法高级(18)-Redis Cluster选举机制

    Redis集群是一个distribute.fault-tolerant的Redis实现,主要设计目标是达到线性可扩展性.可用性.数据一致性. 一.一些特性 线性拓展 官方推荐最大的节点数量为1000, ...

  3. 一万字详解 Redis Cluster Gossip 协议

    大家好,我是历小冰,今天来讲一下 Reids Cluster 的 Gossip 协议和集群操作,文章的思维导图如下所示. 集群模式和 Gossip 简介 对于数据存储领域,当数据量或者请求流量大到一定 ...

  4. Redis Cluster集群知识学习总结

    Redis集群解决方案有两个: 1)  Twemproxy: 这是Twitter推出的解决方案,简单的说就是上层加个代理负责分发,属于client端集群方案,目前很多应用者都在采用的解决方案.Twem ...

  5. 算法高级(19)-不得不懂的Redis Cluster数据分片机制

    亲爱的同学们,你是否使用过Redis集群呢?那Redis集群的原理又是什么呢?记住下面两句话: Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master,继续 ...

  6. Java中高级核心知识全面解析——Redis(集群【概述{主从复制、哨兵、集群化}、数据分区方案、节点通信机制、数据结构简析】)5

    目录 一.[集群]入门实践教程 1.Redis 集群概述 1)Redis 主从复制 2)Redis 哨兵 3)Redis 集群化 2.主从复制 1)主从复制主要的作用 2)快速体验 ①.第一步:本地启 ...

  7. 全面剖析Redis Cluster原理和应用 (good)

    redis redis cluster注意的问题 : 1.'cluster-require-full-coverage'参数的设置.该参数是redis配置文件中cluster模式的一个参数,从字面上基 ...

  8. 如何开发一个高性能的redis cluster proxy

    背景 redis cluster简介 Redis cluster是redis官方提供集群方案,设计上采用非中心化的架构,节点之间通过gossip协议交换互相的状态,redis cluster使用数据分 ...

  9. 开源|如何开发一个高性能的redis cluster proxy?

    文|曹佳俊 网易云信资深服务端开发工程师 背    景  redis cluster简介  Redis cluster是redis官方提供集群方案,设计上采用非中心化的架构,节点之间通过gossip协 ...

最新文章

  1. Leetcode 199.二叉树的右视图 (每日一题 20210628 同类型题)
  2. Rainmeter 天气
  3. c#服务器后台搭建_【环境搭建】Docker简明安装教程
  4. 关于用iframe大框架覆盖小框架的问题
  5. 教你摆脱低级程序猿 项目中cocopads的安装使用
  6. C++并发与多线程(二) 创建多个线程、数据共享问题分析、案例代码
  7. gp3688写频线制作_摩托罗拉GP3688对讲机写频软件(摩托罗拉对讲机写频工具) 官方版...
  8. python 画图十大工具_python实现画图工具
  9. 显示风场的某一局部区域,实现多分辨率
  10. IDEA 不检查语法错误问题
  11. 用linux安装包装ftp,Linux 安装vsftpd和ftp客户端
  12. WBS(Work Breakdown Structure)
  13. 基于物理的渲染技术(PBR)系列一
  14. 几个好玩有趣的Python入门实例
  15. 关于应用安全可控信息技术加强银行业网络安全和信息化建设的指导意见
  16. delete 后加 limit
  17. 【转】用天文方法计算二十四节气(上)
  18. 【翻译】Real Shading in Unreal Engine 4
  19. easymock 图片_用easymock来mock数据
  20. ORACLE存储过程使用数组

热门文章

  1. CUDA Samples: green ball
  2. 设计模式之单例模式(Singleton)摘录
  3. window7系统中64位安装matalbR2009b后出现乱码的解决方案
  4. 华为鸿蒙手机官网价格表,曝下半年华为将推出两款鸿蒙手机:国内独享,价格良心...
  5. layui如何存在多个弹窗_layui常见弹窗使用方法
  6. 计算机应用 含升学方向,对口升学《计算机应用基础》复习资料总汇(含答案))讲述.doc...
  7. kudu接受kafka消息_Kafka 在车好多
  8. python解压_python解压缩
  9. r语言手动算两个C指数p值,如何用R语言进行Pvalue显著性标记?
  10. linux shell for 循环变量,shell for循环总结