redis设计与实现学习---(三)多机数据库的实现

一 复制

1 旧版本复制的实现
redis slaveof命令分为同步和命令传播。
同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
命令传播操作则用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态出 现不一致时,让主从服务器的数据库重新回到一致状态。

2 同步
从服务器对主服务器的同步操作需要通过向主服务器发送SYNC命令来完成,以下是 SYNC命令的执行步骤:
1)从服务器向主服务器发送SYNC命令。
2)收到SYNC命令的主服务器执行BGSAVE命令,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令。
3)当主服务器的BGSAVE命令执行完毕时,主服务器会将BGSAVE命令生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态。
4)主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写 命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。

3 命令传播
在主服务器进行数据修改时,需要把具体的命令发送给从服务器,从服务器再次执行命令之后才能保持数据一致。

4 旧版复制功能的缺陷
初次复制:从服务器以前没有复制过任何主服务器,或者从服务器当前要复制的主服务 器和上一次复制的主服务器不同。
断线后重复制:处于命令传播阶段的主从服务器因为网络原因而中断了复制,但从服务 器通过自动重连接重新连上了主服务器,并继续复制主服务器。
对于初次复制来说,旧版复制功能能够很好地完成任务,但对于断线后重复制来说,旧 版复制功能虽然也能让主从服务器重新回到一致状态,但效率却非常低,因为需要完全在同步一份RDB文件会占用大量的带宽以及IO操作,而且在从服务载入RDB的期间无法进行对外操作。

5 新版本复制功能的实现
使用PSYNC命令代替SYNC命令来执行复制时的同步操作。
对于初次复制来讲,必须复制完整的RDB文件。
对于断线复制,可以采用部分同步:
① 主服务器的复制偏移量(replication offset)和从服务器的复制偏移量。
② 主服务器的复制积压缓冲区(replication backlog)。
③ 服务器的运行ID(run ID)。

6 复制偏移量
主服务器每次向从服务器传播N个字节的数据时就将自己的复制偏移量的值加上N。
从服务器每次收到主服务器传播来的N个字节的数据时,就将自己的复制偏移量的值加上N。
如果主从服务器处于一致状态,那么主从服务器两者的偏移量总是相同的。相反,如果主从服务器两者的偏移量并不相同,那么说明主从服务器并未处于一致状态,则需要从复制积压缓冲区中查找应该同步的偏移量数据。

7 复制积压缓冲区
复制积压缓冲区是由主服务器维护的一个固定长度(fixed-size)先进先出(FIFO)队列,默认大小为1MB,由偏移量以及每个偏移量对应的字节值组成。
和普通先进先出队列随着元素的增加和减少而动态调整长度不同,固定长度先进先出队列的长度是固定的,当入队元素的数量大于队列长度时,最先入队的元素会被弹出,而新元素会被放入队列。
因此当主从不同步时,主服务器根据从服务器的偏移量在复制积压缓冲区中找到对应的偏移量之后的数据进行同步,如果在复制积压缓冲区中未找到对应的偏移量则表示由于太长时间未同步数据所以需要进行全量同步。

8 服务器运行ID
每个Redis服务器,不论主服务器还是从服务,都会有自己的运行ID。运行ID在服务器启动时自动生成,由40个随机的十六进制字符组成,主从服务器进行初次同步时会把自己的ID上报给主服务器,下次断线重连之后会根据ID判断是否进行完全同步
例如 53b9b28df8042fdc9ab5e3fcbbbabff1d5dce2b3。

9 PSYNC的实现
在这里插入图片描述

10 复制的具体步骤
① 设置主服务器的端口
SLAVEOF 127.0.0.1 6379
② 建立套接字连接
③ 发送ping命令
如果超时未收到回复或者收到了一个错误恢复则从服务器主动断开并重新创建套接字连接,如果收到pong命令则表示连接正常
④ 身份验证
在这里插入图片描述

⑤ 发送端口信息
REPLCONF listening-port
⑥ 同步
⑦ 命令传播

11 心跳
在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:
REPLCONF ACK < replication_offset >
发送REPLCONF ACK命令对于主从服务器有三个作用:
检测主从服务器的网络连接状态。
辅助实现min-slaves选项。
检测命令丢失。

12 min-slaves配置
min-slaves-to-write 3
min-slaves-max-lag 10
表示在从服务器的数量少于3个,或者三个从服务器的延迟(lag)值都大于或等于10秒时,主服务器将拒绝执行写命令

二 Sentinel

1 作用
Sentinel(哨岗、哨兵)是Redis的高可用性(high availability)解决方案:由一个或多个 Sentinel实例(instance)组成的Sentinel系统(system)可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。
操作主从切换的过程是由多个Sentinel选出一个临时leader Sentinel来执行的,选举算法采用的是raft选举协议。

2 启动方式
redis-sentinel /path/to/your/sentinel.conf
或者redis-server /path/to/your/sentinel.conf –sentinel
当一个Sentinel启动时,它需要执行以下步骤:
1)初始化服务器(此时不会载入RDB/AOF,不载入数据库相关的操作命令,保留发布订阅命令以及事件处理器)。
2)将普通Redis服务器使用的代码替换成Sentinel专用代码。
3)初始化Sentinel状态。Sentinel状态中的masters字典记录了所有被Sentinel监视的主服务器的相关信息,字典的键是被监视主服务器的名字。 而字典的值则是被监视主服务器对应的sentinel.c/sentinelRedisInstance结构。每个sentinelRedisInstance结构代表一个被Sentinel监视的Redis服务器实例(instance),这个实例可以是主服务器、从服务器,或者另外一个Sentinel。
在这里插入图片描述

4)根据给定的配置文件,初始化Sentinel的监视主服务器列表。
5)创建连向主服务器的网络连接。
对于每个被Sentinel监视的主服务器来说,Sentinel会创建两个连向主服务器的异步网络连接(从服务器也会建立连接):
一个是命令连接,这个连接专门用于向主服务器发送命令,并接收命令回复,主要是每十秒一次INFO命令,来获取实例信息。
另一个是订阅连接,这个连接专门用于订阅主服务器的__sentinel__:hello频道。
6) 创建向其他Sentinel的命令连接。这里不需要订阅链接是因为Sentinel需要 通过接收主服务器或者从服务器发来的频道信息来发现未知的新Sentinel,所以才需要建立订阅连接,而相互已知的Sentinel只要使用命令连接来进行通信就足够了。

3 检测主观下线状态
在默认情况下,Sentinel会以每秒一次的频率向所有与它创建了命令连接的实例(包括主 服务器、从服务器、其他Sentinel在内)发送PING命令,并通过实例返回的PING命令回复来 判断实例是否在线。
实例对PING命令的回复可以分为以下两种情况:
有效回复:实例返回+PONG、-LOADING、-MASTERDOWN三种回复的其中一种。 ·
无效回复:实例返回除+PONG、-LOADING、-MASTERDOWN三种回复之外的其他回复,或者在指定时限内没有返回任何回复。
Sentinel配置文件中的down-after-milliseconds选项指定了Sentinel判断实例进入主观下线 所需的时间长度:如果一个实例在down-after-milliseconds毫秒内,连续向Sentinel返回无效回 复,那么Sentinel会修改这个实例所对应的实例结构,在结构的flags属性中打开 SRI_S_DOWN标识,以此来表示这个实例已经进入主观下线状态。
注意:
down-after-milliseconds选项另一个需要注意的地方是,对于监视同一个主服务器的多个Sentinel来说,这些Sentinel所设置的down-after-milliseconds选项的值也可能不同, 因此,当一个Sentinel将主服务器判断为主观下线时,其他Sentinel可能仍然会认为主服务器处于在线状态。因此当Sentinel将一个主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线了,它会向同样监视这一主服务器的其他Sentinel进行询问,看它们是否也认为主服务器已经 进入了下线状态(可以是主观下线或者客观下线)。当Sentinel从其他Sentinel那里接收到足够数量的已下线判断之后,Sentinel就会将从服务器判定为客观下线,并对主服务器执行故障转移操作。

4 领头Sentinel的选举(参考raft选举协议)
当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个Sentinel会进行协 商,选举出一个领头Sentinel,并由领头Sentinel对下线主服务器执行故障转移操作。
① 所有在线的Sentinel都有被选为领头Sentinel的资格,换句话说,监视同一个主服务器的 多个在线Sentinel中的任意一个都有可能成为领头Sentinel。
② 每次进行领头Sentinel选举之后,不论选举是否成功,所有Sentinel的配置纪元 (configuration epoch)的值都会自增一次。配置纪元实际上就是一个计数器,并没有什么特别的。
③ 在一个配置纪元里面,所有Sentinel都有一次将某个Sentinel设置为局部领头Sentinel的机 会,并且局部领头一旦设置,在这个配置纪元里面就不能再更改。 ·每个发现主服务器进入客观下线的Sentinel都会要求其他Sentinel将自己设置为局部领头 Sentinel。
④ 当一个Sentinel(源Sentinel)向另一个Sentinel(目标Sentinel)发送SENTINEL ismaster-down-by-addr命令,并且命令中的runid参数不是*符号而是源Sentinel的运行ID时,这 表示源Sentinel要求目标Sentinel将前者设置为后者的局部领头Sentinel。
⑤ Sentinel设置局部领头Sentinel的规则是先到先得:最先向目标Sentinel发送设置要求的源 Sentinel将成为目标Sentinel的局部领头Sentinel,而之后接收到的所有设置要求都会被目标 Sentinel拒绝。
⑥ 目标Sentinel在接收到SENTINEL is-master-down-by-addr命令之后,将向源Sentinel返回 一条命令回复,回复中的leader_runid参数和leader_epoch参数分别记录了目标Sentinel的局部 领头Sentinel的运行ID和配置纪元。
⑦ 源Sentinel在接收到目标Sentinel返回的命令回复之后,会检查回复中leader_epoch参数 的值和自己的配置纪元是否相同,如果相同的话,那么源Sentinel继续取出回复中的 leader_runid参数,如果leader_runid参数的值和源Sentinel的运行ID一致,那么表示目标 Sentinel将源Sentinel设置成了局部领头Sentinel。
⑧ 如果有某个Sentinel被半数以上的Sentinel设置成了局部领头Sentinel,那么这个Sentinel成 为领头Sentinel。举个例子,在一个由10个Sentinel组成的Sentinel系统里面,只要有大于等于 10/2+1=6个Sentinel将某个Sentinel设置为局部领头Sentinel,那么被设置的那个Sentinel就会成 为领头Sentinel。
⑨ 因为领头Sentinel的产生需要半数以上Sentinel的支持,并且每个Sentinel在每个配置纪元 里面只能设置一次局部领头Sentinel,所以在一个配置纪元里面,只会出现一个领头 Sentinel。
⑩ 如果在给定时限内,没有一个Sentinel被选举为领头Sentinel,那么各个Sentinel将在一段时间之后再次进行选举,直到选出领头Sentinel为止。

5 故障转移
在选举产生出领头Sentinel之后,领头Sentinel将对已下线的主服务器执行故障转移操 作,该操作包含以下三个步骤:
1)在已下线主服务器属下的所有从服务器里面,挑选出一个从服务器,并将其转换为 主服务器。
2)让已下线主服务器属下的所有从服务器改为复制新的主服务器。
3)将已下线主服务器设置为新的主服务器的从服务器,当这个旧的主服务器重新上线 时,它就会成为新的主服务器的从服务器。
4) 修改其他从服务器的复制目标
5) 如果旧的主服务器重新上线,则会被当成新的从服务器来对待

6 从服务器晋升主服务器的依据
领头Sentinel会将已下线主服务器的所有从服务器保存到一个列表里面,然后按照以 下规则,一项一项地对列表进行过滤:
1)删除列表中所有处于下线或者断线状态的从服务器,这可以保证列表中剩余的 从服务器都是正常在线的。
2)删除列表中所有最近五秒内没有回复过领头Sentinel的INFO命令的从服务器,这 可以保证列表中剩余的从服务器都是最近成功进行过通信的。
3)删除所有与已下线主服务器连接断开超过down-after-milliseconds10毫秒的从服 务器:down-after-milliseconds选项指定了判断主服务器下线所需的时间,而删除断开时 长超过down-after-milliseconds10毫秒的从服务器,则可以保证列表中剩余的从服务器 都没有过早地与主服务器断开连接,换句话说,列表中剩余的从服务器保存的数据都是比较新的。
4)之后,领头Sentinel将根据从服务器的优先级,对列表中剩余的从服务器进行排序, 并选出其中优先级最高的从服务器。
5) 如果有多个具有相同最高优先级的从服务器,那么领头Sentinel将按照从服务器的复制偏移量,对具有相同最高优先级的所有从服务器进行排序,并选出其中偏移量最大的 从服务器(复制偏移量最大的从服务器就是保存着最新数据的从服务器)。
6) 最后,如果有多个优先级最高、复制偏移量最大的从服务器,那么领头Sentinel将按照运行ID对这些从服务器进行排序,并选出其中运行ID最小的从服务器。

三 集群

1 作用
Redis集群是Redis提供的分布式数据库方案,集群通过分片(sharding)来进行数据共 享,并提供复制和故障转移功能,需要在配置文件中开启cluster-enabled yes。分片数据的复制以及故障转移与sentinel类似,集群之间的其他发现以及同步操作采用的是gossip算法传播。

2 集群数据结构
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

4 槽指派
CLUSTER ADDSLOTS [slot …]
在这里插入图片描述

如果节点只使用clusterNode.slots数组来记录槽的指派信息,那么为了知道槽i是否已经被指派,或者槽i被指派给了哪个节点,程序需要遍历clusterState.nodes字典中的所有clusterNode结构,检查这些结构的slots数组,直到找到负责处理槽i的节点为止,这个过程的 复杂度为O(N),其中N为clusterState.nodes字典保存的clusterNode结构的数量。而通过将所有槽的指派信息保存在clusterState.slots数组里面,程序要检查槽i是否已经被 指派,又或者取得负责处理槽i的节点,只需要访问clusterState.slots[i]的值即可,这个操作的 复杂度仅为O(1)。

虽然clusterState.slots数组记录了集群中所有槽的指派信息,但使用 clusterNode结构的slots数组来记录单个节点的槽指派信息仍然是有必要的: 因为当程序需要将某个节点的槽指派信息通过消息发送给其他节点时,程序只需要将相应节点的clusterNode.slots数组整个发送出去就可以了。 另一方面,如果Redis不使用clusterNode.slots数组,而单独使用clusterState.slots数组的话,那么每次要将节点A的槽指派信息传播给其他节点时,程序必须先遍历整个 clusterState.slots数组,记录节点A负责处理哪些槽,然后才能发送节点A的槽指派信息,这比直接发送clusterNode.slots数组要麻烦和低效得多。

5 在集群中对命令的处理
节点使用以下算法来计算给定键key属于哪个槽
def slot_number(key):
return CRC16(key) & 16383
在这里插入图片描述

6 节点数据库的实现
节点数据库实现与单机数据库实现大致相同,其中一个区别是节点数据库只能使用0号数据库,还有重要的一点是,单机数据库中,除了redisDb.dict以及expires会记录数据库使用到的键之外,再节点数据库的clusterState中还有一个slots_to_keys跳跃表来保存槽和键之间的关系。
例如:键"book"所在跳跃表节点的分值为1337.0,这表示键"book"所在的槽为1337
在这里插入图片描述

命令CLUSTER GETKEYSINSLOT 命令可以返回最多count个属于槽slot的数据库键,而这个命令就是通过遍历 slots_to_key s跳跃表来实现的。

7 重新分片
重新分片操作可以在线(online)进行,在重新分片的过程中,集群不需要下线,并且 源节点和目标节点都可以继续处理命令请求。
在这里插入图片描述

8 重新分片过程中的ASK错误
ASK与MOVE作用类似,都是告知客户端向另一个节点重新发起请求,区别在于MOVE是永久的,ASK是临时一次性的。
在这里插入图片描述

9 重分片过程CLUSTER SETSLOT IMPORTING命令的实现
如果importing_slots_from[i]的值不为NULL,而是指向一个clusterNode结构,那么表示当前节点正在从clusterNode所代表的节点导入槽i。
在这里插入图片描述

10 重分片过程CLUSTER SETSLOT MIGRATING命令的实现
如果migrating_slots_to[i]的值不为NULL,而是指向一个clusterNode结构,那么表示当前节点正在将槽i迁移至clusterNode所代表的节点。
在这里插入图片描述

11 转移过程中MOVE以及ASK的处理
当客户端接收到ASK错误并转向至正在导入槽的节点时,客户端会先向节点发送一个 ASKING命令,然后才重新发送想要执行的命令,这是因为如果客户端不发送ASKING命令,而直接发送想要执行的命令的话,那么客户端发送的命令将被节点拒绝执行,并返回 MOVED错误。
在这里插入图片描述

12 故障转移
当一个从节点发现自己正在复制的主节点进入了已下线状态时,从节点将开始对下线主 节点进行故障转移,以下是故障转移的执行步骤:
1)复制下线主节点的所有从节点里面,会有一个从节点被选中。
2)被选中的从节点会执行SLAVEOF no one命令,成为新的主节点。
3)新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽全部指派给自己。
4)新的主节点向集群广播一条PONG消息,这条PONG消息可以让集群中的其他节点立 即知道这个节点已经由从节点变成了主节点,并且这个主节点已经接管了原本由已下线节点 负责处理的槽。
5)新的主节点开始接收和自己负责处理的槽有关的命令请求,故障转移完成。

13 选举新的主节点
与sentinel选举类似,之前是第一个设置节点主观下线的sentinel请求自己为领头sentinel,这里是第一个发现主节点断开的从节点向其他主节点发起请求投票。
1)集群的配置纪元是一个自增计数器,它的初始值为0。
2)当集群里的某个节点开始一次故障转移操作时,集群配置纪元的值会被增一。
3)对于每个配置纪元,集群里每个负责处理槽的主节点都有一次投票的机会,而第一 个向主节点要求投票的从节点将获得主节点的投票。
4)当从节点发现自己正在复制的主节点进入已下线状态时,从节点会向集群广播一条 CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST消息,要求所有收到这条消息、并且具 有投票权的主节点向这个从节点投票。
5)如果一个主节点具有投票权(它正在负责处理槽),并且这个主节点尚未投票给其 他从节点,那么主节点将向要求投票的从节点返回一条 CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,表示这个主节点支持从节点成为新的 主节点。
6)每个参与选举的从节点都会接收CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消 息,并根据自己收到了多少条这种消息来统计自己获得了多少主节点的支持。
7)如果集群里有N个具有投票权的主节点,那么当一个从节点收集到大于等于N/2+1张 支持票时,这个从节点就会当选为新的主节点。
8)因为在每一个配置纪元里面,每个具有投票权的主节点只能投一次票,所以如果有N 个主节点进行投票,那么具有大于等于N/2+1张支持票的从节点只会有一个,这确保了新的 主节点只会有一个。
9)如果在一个配置纪元里面没有从节点能收集到足够多的支持票,那么集群进入一个 新的配置纪元,并再次进行选举,直到选出新的主节点为止。

14 集群节点之间的消息
① MEET消息:当发送者接到客户端发送的CLUSTER MEET命令时,发送者会向接收者 发送MEET消息,请求接收者加入到发送者当前所处的集群里面。
② PING消息:集群里的每个节点默认每隔一秒钟就会从已知节点列表中随机选出五个节 点,然后对这五个节点中最长时间没有发送过PING消息的节点发送PING消息,以此来检测 被选中的节点是否在线。除此之外,如果节点A最后一次收到节点B发送的PONG消息的时 间,距离当前时间已经超过了节点A的cluster-node-timeout选项设置时长的一半,那么节点A 也会向节点B发送PING消息,这可以防止节点A因为长时间没有随机选中节点B作为PING消 息的发送对象而导致对节点B的信息更新滞后。
③ PONG消息:当接收者收到发送者发来的MEET消息或者PING消息时,为了向发送者 确认这条MEET消息或者PING消息已到达,接收者会向发送者返回一条PONG消息。另外, 一个节点也可以通过向集群广播自己的PONG消息来让集群中的其他节点立即刷新关于这个 节点的认识,例如当一次故障转移操作成功执行之后,新的主节点会向集群广播一条PONG 消息,以此来让集群中的其他节点立即知道这个节点已经变成了主节点,并且接管了已下线 节点负责的槽。
④ FAIL消息:当一个主节点A判断另一个主节点B已经进入FAIL状态时,节点A会向集群 广播一条关于节点B的FAIL消息,所有收到这条消息的节点都会立即将节点B标记为已下线。
⑤ PUBLISH消息:当节点接收到一个PUBLISH命令时,节点会执行这个命令,并向集群 广播一条PUBLISH消息,所有接收到这条PUBLISH消息的节点都会执行相同的PUBLISH命令。

15 redis集群消息格式
一条消息由消息头(header)和消息正文(data)组成
在这里插入图片描述
在这里插入图片描述

16 MEET、PING、PONG消息的实现
因为MEET、PING、PONG三种消息都使用相同的消息正文,所以节点通过消息头的 type属性来判断一条消息是MEET消息、PING消息还是PONG消息。
每次发送MEET、PING、PONG消息时,发送者都从自己的已知节点列表中随机选出两 个节点(可以是主节点或者从节点),并将这两个被选中节点的信息分别保存到两个 clusterMsgDataGossip结构里面。
clusterMsgDataGossip结构记录了被选中节点的名字,发送者与被选中节点最后一次发送 和接收PING消息和PONG消息的时间戳,被选中节点的IP地址和端口号,以及被选中节点的标识值。
当接收者收到MEET、PING、PONG消息时,接收者会访问消息正文中的两个 clusterMsgDataGossip结构,并根据自己是否认识clusterMsgDataGossip结构中记录的被选中 节点来选择进行哪种操作:
①如果被选中节点不存在于接收者的已知节点列表,那么说明接收者是第一次接触到被选 中节点,接收者将根据结构中记录的IP地址和端口号等信息,与被选中节点进行握手。
②如果被选中节点已经存在于接收者的已知节点列表,那么说明接收者之前已经与被选中 节点进行过接触,接收者将根据clusterMsgDataGossip结构记录的信息,对被选中节点所对应 的clusterNode结构进行更新。
在这里插入图片描述

17 FAIL消息的实现
当集群里的主节点A将主节点B标记为已下线(FAIL)时,主节点A将向集群广播一条关 于主节点B的FAIL消息,所有接收到这条FAIL消息的节点都会将主节点B标记为已下线。 在集群的节点数量比较大的情况下,单纯使用Gossip协议来传播节点的已下线信息会给 节点的信息更新带来一定延迟,因为Gossip协议消息通常需要一段时间才能传播至整个集群,而发送FAIL消息可以让集群里的所有节点立即知道某个主节点已下线,从而尽快判断是否需要将集群标记为下线,又或者对下线主节点进行故障转移。
在这里插入图片描述

举个例子,对于包含7000、7001、7002、7003四个主节点的集群来说: ·如果主节点7001发现主节点7000已下线,那么主节点7001将向主节点7002和主节点7003 发送FAIL消息,其中FAIL消息中包含的节点名字为主节点7000的名字,以此来表示主节点 7000已下线。 ·当主节点7002和主节点7003都接收到主节点7001发送的FAIL消息时,它们也会将主节 点7000标记为已下线。 ·因为这时集群已经有超过一半的主节点认为主节点7000已下线,所以集群剩下的几个主 节点可以判断是否需要将集群标记为下线,又或者开始对主节点7000进行故障转移。

18 PUBLISH消息的实现
当客户端向集群中的某个节点发送命令: PUBLISH 的时候,接收到PUBLISH命令的节点不仅会向channel频道发送消息message,它还会向集群广播一条PUBLISH消息,所有接收到这条PUBLISH消息的节点都会向channel频道发送 message消息。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值