Redis 主从集群
为了避免 Redis 的单点故障问题,我们可以搭建一个 Redis 集群,将数据备份到集群中的其它节点上。
Redis 的主从集群是一个“一主多从”的读写分离集群。对于数据库集群,写操作压力一般都较小,压力大多数来自于读操作请求,所以集群中的 Master 节点负责处理客户端的读写请求,而 Slave 节点仅能处理客户端的读请求。
主从集群搭建
伪集群搭建与配置
在采用单线程 IO 模型时,为了提高处理器的利用率,一般会在一个主机中安装多台 Redis, 构建一个 Redis 主从伪集群。
- 复制 redis.conf,用于设置每个 Redis 节点的公共属性。修改:
- masterauth
如果需要设置置密码验证属性 requirepass,每个主机的密码都要设置为相同的。且要设置两个值完全相同的属性:requirepass 与 masterauth。其中 requirepass 用于指定当前主机的访问密码,而 masterauth 用于指定当前 slave 访问 master 时向 master 提交的访问密码,用于让 master 验证自己身份是否合法。
- repl-disable-tcp-nodelay
该属性用于设置是否禁用 TCP 特性 tcp-nodelay。设为 yes 则禁用 tcp-nodelay,此时 master 与 slave 间的通信会产生延迟,但使用的 TCP 包数量会较少,占用的网络带宽会较小。设置为 no,则网络延迟会变小,但使用的 TCP 包数量会较多,相应占用的网络带宽会大。
tcp-nodelay:为了充分复用网络带宽,TCP 总是希望发送尽可能大的数据块。为了达到该目的,TCP 中使用了名为 Nagle 的算法。
Nagle 算法的工作原理:网络在接收到要发送的数据后,并不直接发送,而是等待着数据量足够大(由 TCP 网络特性决定)时再一次性发送出去。这样,网络上传输的有效数据比例就得到了大大提升,无效数据传递量极大减少,于是就节省了网络带宽,缓解了网络压力。
tcp-nodelay 则是 TCP 协议中 Nagle 算法的开头。
- 创建 slave 的配置文件:
1 | include redis.conf |
另外两个文件类似,不在赘述
启动 redis
设置主从关系:
- slaveof
查看状态信息:
- info replication
分级管理
Redis 主从集群中的 Slave 较多时,它们的数据同步过程会对 Master 形成较大的性能压力。此时可以对这些 Slave 进行分级管理。
只需要让低级别 Slave 指定其 slaveof 的主机为其上一级 Slave 即可。上一级 Slave 的状态仍为 Slave,只不过其是更上一级的 Slave。
当然,此时 Master 的 Slave 只有 6381 一个主机。
容灾冷处理
在 Master/Slave 的 Redis 集群中,若 Master 出现宕机,有两种处理方式,一种是通过手工角色调整,使 Slave 晋升为 Master 的冷处理;一种是使用哨兵模式,实现 Redis 集群的高可用 HA,即热处理。
无论 Master 是否宕机,Slave 都可通过 slaveof no one 将自己由 Slave 晋升为 Master。如果其原本有下一级的 Slave,那么其就直接变为了这些 Slave 的 Master 了。而原来的 Master 也会失去这个原来的 Slave。
主从复制原理
主从复制过程
当一个 slave 节点接收到类似 slaveof 127.0.0.1 6380 的指令后直至其可以从 master 持续复制数据,大体经历了如下几个过程:
- 保存 master 地址
- 建立连接
slave 中维护着一个定时任务,该定时任务会尝试着与该 master 建立 socket 连接。如果连接无法建立,则其会不断定时重试,直到连接成功或接收到 slaveof no one 指令。
- slave 发送 ping 命令
连接建立成功后,slave 会发送 ping 命令进行首次通信。如果 slave 没有收到 master 的 回复,则 slave 会主动断开连接,下次的定时任务会重新尝试连接。
- 对 slave 身份验证
master 收到了 slave 的 ping 命令,并不会立即回复,而是先进行身份验证。如果验证失败,则会发送消息拒绝连接;如果验证成功,则向 slave 发送连接成功响应。
- master 持久化
首次通信成功后,slave 会向 master 发送数据同步请求。当 master 接收到请求后,会 fork 出一个子进程,让子进程以异步方式立即进行持久化。
- 数据发送
持久化完毕后 master 会再 fork 出一个子进程,让该子进程以异步方式将数据发送给 slave。slave 会将接收到的数据不断写入到本地的持久化文件中。
在 slave 数据同步过程中,master 的主进程仍在不断地接受着客户端的写操作,且不仅将新的数据写入到了 master 内存,同时也写入到了同步缓存。当 master 的持久化文件中的数据发送完毕后,master 会再将同步缓存中新的数据发送给 slave,由 slave 将其写入到本地持久化文件中。数据同步完成。
- slave 恢复内存数据
当 slave 与 master 的数据同步完成后,slave 就会读取本地的持久化文件,将其恢复到本地内存,然后就可以对外提供读服务了。
- 持续增量复制
在 slave 对外提供服务过程中,master 会持续不断的将新的数据以增量方式发送给 slave,以保证主从数据的一致性。
数据同步演变过程
sync 同步
Redis 2.8 版本之前,首次通信成功后,slave 会向 master 发送 sync 数据同步请求。然后 master 就会将其所有数据全部发送给 slave,由 slave 保存到其本地的持久化文件中。这个过程称为全量复制。
由于全量复制过程非常耗时,期间出现网络抖动的概率很高。而中断后的从头开始不仅需要消耗大量的系统资源、网络带宽,而且可能会出现长时间无法完成全量复制的情况。
psync 同步
Redis 2.8 版本之后,全量复制采用了 psync(Partial Sync,不完全同步)同步策略。当全量复制过程出现由于网络抖动而导致复制过程中断时,当重新连接成功后,复制过程可以“断点续传”。
为了实现 psync,整个系统做了三个大的变化:
- 复制偏移量
系统为每个要传送数据进行了编号,该编号从 0 开始,每个字节一个编号。该编号称为复制偏移量。参与复制的主从节点都会维护该复制偏移量。
master 每发送过一个字节数据后就会进行累计。统计信息通过 info replication 的 master_repl_offset 可查看到。同时,slave 会定时向 master 上报其自身已完成的复制偏移量给 master,所以 master 也会保存 slave 的复制偏移量 offset。
slave在接收到master的数据后,也会累计接收到的偏移量。统计信息通过info replication 的 slave_repl_offset 可查看到。
- 主节点复制 ID
当 master 启动后就会动态生成一个长度为 40 位的 16 进制字符串作为当前 master 的复制 ID,该 ID 是在进行数据同步时 slave 识别 master 使用的。通过 info replication 的 master_replid 属性可查看到该 ID。
- 复制积压缓冲区
当 master 有连接的 slave 时,在 master 中就会创建并维护一个队列 backlog,默认大小为 1MB,该队列称为复制积压缓冲区。master 接收到了写操作数据不仅会写入到 master 主 存,写入到 master 中为每个 slave 配置的发送缓存,而且还会写入到复制积压缓冲区。其作用就是用于保存最近操作的数据,以备“断点续传”时做数据补偿,防止数据丢失。
psync 同步过程
psync 是一个由 slave 提交的命令,其格式为 psync <master_replid> <repl_offset>,表示当前 slave 要从指定的 master 中的 repl_offset+1 处开始复制。repl_offset 表示当前 slave 已经 完成复制的数据的 offset。该命令保证了“断点续传”的实现。
在第一次开始复制时,slave 并不知道 master 的动态 ID,并且一定是从头开始复制,所以其提交的 psync 命令为 PSYNC ? -1。
此时 master 可能有两种响应:
- FULLRESYNC <master_replid> <repl_offset>:告知 slave 当前 master 的动态 ID 及可以开始全量复制了,这里的 repl_offset 一般为 0
- ERR:告知 slave,当前 master 的版本低于 Redis 2.8,不支持 psyn,你可以开始全量复制了
如果复制过程中断后 slave 与 master 成功连接,则 slave 再次提交 psyn 命令。此时的 psyn 命令的 repl_offset 参数为其前面已经完成复制的数据的偏移量。
master 相应:CONTINUE;告知 slave 可以按照你提交的 repl_offset 后面位置开始“续传”了
psync 存在的问题
- 在 psync 数据同步过程中,若 slave 重启,在 slave 内存中保存的 master 的动态 ID 与续传 offset 都会消失,“断点续传”将无法进行,从而只能进行全量复制,导致资源浪费。
- 在 psync 数据同步过程中,master 宕机后 slave 会发生“易主”,从而导致 slave 需要从新 master 进行全量复制,形成资源浪费。
psync 同步的改进
Redis 4.0 对 psync 进行了改进,提出了“同源增量同步”策略。
- 解决 slave 重启问题
针对“slave 重启时 master 动态 ID 丢失问题”,改进后的 psync 将 master 的动态 ID 直接写入到了 slave 的持久化文件中。
slave 重启后直接从本地持久化文件中读取 master 的动态 ID,然后向 master 提交获取复制偏移量的请求。master 会根据提交请求的 slave 地址,查找到保存在 master 中的复制偏移量
- 解决 slave 易主问题
如果 slave 发送 PSYNC <原 master_replid> <repl_offset> 命令,新master能够识别出该slave要从原master复制数据,而自己的数据也都是从该master复制来的。那么新 master 就会明白,其与该 slave“师出同门”,应该接收其“断点续传”同步请求。
无盘操作
Redis 6.0 对同步过程又进行了改进,提出了“无盘全量同步”与“无盘加载”策略,避免了耗时的 IO 操作。
- 无盘全量同步:master 的主进程 fork 出的子进程直接将内存中的数据发送给 slave,无需经过磁盘。
- 无盘加载:slave 在接收到 master 发送来的数据后不需要将其写入到磁盘文件,而是直接写入到内存,这样 slave 就可快速完成数据恢复。
共享复制积压缓冲区
Redis 7.0 版本对复制积压缓冲区进行了改进,让各个 slave 的发送缓冲区共享复制积压缓冲区。这使得复制积压缓冲区的作用,除了可以保障数据的安全性外,还作为所有 slave 的发送缓冲区,充分利用了复制积压缓冲区。
哨兵机制
对于 Master 宕机后的冷处理方式是无法实现高可用的。Redis 从 2.6 版本开始提供了高可用的解决方案—— Sentinel 哨兵机制。在集群中再引入一个节点,该节点充当 Sentinel 哨兵,用于监视 Master 的运行状态,并在 Master 宕机后自动指定一个 Slave 作为新的 Master。 整个过程无需人工参与,完全由哨兵自动完成。
为了解决 Sentinel 的单点问题,又要为 Sentinel 创建一个集群,即 Sentinel 哨兵集群。
Sentinel 哨兵工作原理:
每个 Sentinel 都会定时会向 Master 发送心跳,如果 Master 在有效时间内向它们都进行了响应,则说明 Master 是“活着的”。如果 Sentinel 中有 quorum 个哨兵没有收到响应,那么就认为 Master 已经宕机,然后会有一个 Sentinel 做 Failover 故障转移。即将原来的某一个 Slave 晋升为 Master。
哨兵机制实现
- 复制 sentinel.conf
- 修改 sentinel.conf
- sentinel monitor
该配置用于指定 Sentinel 要监控的 master,为 master 起了一个名字。同时指定 Sentinel 集群中决定该master“客观下线状态”判断的法定 sentinel 数量<quorum>。<quorum>的另一个用途与sentinel 的 Leader 选举有关。要求中至少要有 max(quorum, sentinelNum/2+1)个 sentinel 参与,选举才能进行。
这里将该配置注释掉,因为要在后面的其它配置文件中设置,如果不注释就会出现配置冲突。
- sentinel auth-pass
如果 Redis 主从集群中的主机设置了访问密码,那么该属性就需要指定 master 的主机名与访问密码。以方便 sentinel 监控 master。
- 新建sentinel配置文件
1 | include sentinel.conf |
另外两个文件类似,不再赘述
Redis 高可用集群的启动
- 启动并关联 Redis 集群
- 启动 Sentinel 集群
在/usr/local/bin 目录下有一个命令 redis-sentinel 用于启动 Sentinel。
redis-sentinel 命令是 redis-server 命令的软链接
方式一:使用 redis-sentinel 命令:redis-sentinel sentinel26380.conf
方式二,使用 redis-server 命令:redis-server sentinel26380.conf –sentinel
- 查看 Sentinel 信息
运行中的 Sentinel 就是一个特殊 Redis,其也可以通过客户端连接,然后通过 info sentinel 来查看当前连接的 Sentinel 的信息。
- 查看 sentinel 配置文件
打开任意 sentinel 的配置文件,发现其配置内容中新增加了很多配置。
Sentinel 优化配置
在公共的 sentinel.conf 文件中,还可以通过修改一些其它属性的值来达到对 Sentinel 的配置优化。
- sentinel down-after-milliseconds
每个 Sentinel 会通过定期发送 ping 命令来判断 master、slave 及其它 Sentinel 是否存活。如果 Sentinel 在该属性指定的时间内没有收到它们的响应,那么该 Sentinel 就会主观认为该主机宕机。默认为 30 秒。
- sentinel parallel-syncs
该属性用于指定在故障转移期间,即老的 master 出现问题,新的 master 刚晋升后,允许多少个 slave 同时从新 master 进行数据同步。默认值为 1 表示所有 slave 逐个从新 master 进行数据同步。
- sentinel failover-timeout
指定故障转移的超时时间,默认时间为 3 分钟。该超时时间的用途:
- 第一次故障转移失败,在同一个 master 上进行第二次故障转移尝试的时间为该 failover-timeout 的两倍
- 新 master 晋升完毕,slave 从老 master 强制转到新 master 进行数据同步的时间阈值。(当超时了就不会再逐个同步)
- 取消正在进行的故障转换所需的时间阈值。
- 新 master 晋升完毕,所有 replicas 的配置文件更新为新 master 的时间阈值。
- sentinel deny-scripts-reconfig
指定是否可以通过命令 sentinel set 动态修改 notification-script 与 client-reconfig-script 两个脚本。默认是不能的。这两个脚本如果允许动态修改,可能会引发安全问题。
- 动态修改配置
通过 redis-cli 连接上 Sentinel 后,通过 sentinel set 命令可动态修改配置信息。
sentinel set 命令支持的参数:
哨兵机制原理
三个定时任务
Sentinel 维护着三个定时任务以监测 Redis 节点及其它 Sentinel 节点的状态。
- info 任务
每个 Sentinel 节点每 10 秒就会向 Redis 集群中的每个节点发送 info 命令,以获得最新的 Redis 拓扑结构。
- 心跳任务
每个Sentinel节点每1秒就会向所有Redis节点及其它Sentinel节点发送一条ping命令,以检测这些节点的存活状态。该任务是判断节点在线状态的重要依据。
- 发布/订阅任务
每个 Sentinel 节点在启动时都会向所有 Redis 节点订阅_ _sentinel_ _:hello 主题的信息, 当 Redis 节点中该主题的信息发生了变化,就会立即通知到所有订阅者。
Sentinel 节点每 2 秒就会向每个 Redis 节点发布一条_ _sentinel_ _:hello 主题的信息,该信息是当前 Sentinel 对每个 Redis 节点在线状态的判断结果及当前 Sentinel 节点信息。
当 Sentinel 节点接收到_ _sentinel_ _:hello 主题信息后,就会读取并解析这些信息,然后主要完成以下三项工作:
- 如果发现有新的 Sentinel 节点加入,则记录下新加入 Sentinel 节点信息,并与其建立连接。
- 如果发现有 Sentinel Leader 选举的选票信息,则执行 Leader 选举过程。
- 汇总其它 Sentinel 节点对当前 Redis 节点在线状态的判断结果,作为 Redis 节点客观下线的判断依据。
Redis 节点下线判断
- 主观下线
每个 Sentinel 节点每秒会向每个 Redis 节点发送 ping 心跳检测,如果 Sentinel 在 down-after-milliseconds 时间内没有收到某 Redis 节点的回复,则 Sentinel 节点就会对该 Redis 节点做出“下线状态”的判断
- 客观下线
当 Sentinel 主观下线的节点是 master 时,该 Sentinel 节点会向每个其它 Sentinel 节点发送 sentinel is-master-down-by-addr 命令,以询问其对 master 在线状态的判断结果。这些 Sentinel 节点在收到命令后会向这个发问 Sentinel 节点响应 0(在线)或 1(下线)。当 Sentinel 收到超过 quorum 个下线判断后,就会对 master 做出客观下线判断。
Sentinel Leader 选举
当 Sentinel 节点对 master 做出客观下线判断后会由 Sentinel Leader 来完成后续的故障转移。Sentinel 集群的 Leader 选举是通过 Raft 算法实现的。
大致思路:
每个选举参与者都具有当选 Leader 的资格,当其完成了“客观下线”判断后,就会立即推选自己做 Leader,然后将自己的提案发送给所有参与者。其它参与者在收到提案后,只要自己手中的选票没有投出去,其就会立即通过该提案并将同意结果反馈给提案者,后续再过来的提案会由于该参与者没有了选票而被拒绝。当提案者收到了同意反馈数量大于等于 max(quorum,sentinelNum/2+1)时,该提案者当选 Leader。
说明:Sentinel Leader 选举会在次故障转移发生之前进行。在网络没有问题的前提下,谁先做出了“客观下线”的判断,谁就更容易当选Leader。故障转移结束后 Leader 就不再存在。
master 选择算法
在进行故障转移时,Sentinel Leader 需要从所有 Redis 的 Slave 节点中选择出新的 Master。
- 过滤掉所有主观下线的,或心跳没有响应 Sentinel 的,或 replica-priority 值为 0 的 Redis 节点
- 在剩余 Redis 节点中选择出 replica-priority 最小的的节点列表。如果只有一个节点,则直接返回
- 从优先级相同的节点列表中选择复制偏移量最大的节点。如果只有一个节点,则直接返回
- 从复制偏移值量相同的节点列表中选择动态 ID 最小的节点返回
故障转移过程
Sentinel Leader 负责整个故障转移过程:
- 根据 master 选择算法选择出一个 slave 节点作为新的 master
- 向新 master 节点发送 slaveof no one 指令,使其晋升为 master
- 向新 master 发送 info replication 指令,获取到 master 的动态 ID
- 向其余 Redis 节点发送消息,以告知它们新 master 的动态 ID
- 向其余 Redis 节点发送 slaveof 指令,使它们成为新 master 的 slave
- 从所有 slave 节点中每次选择出 parallel-syncs 个 slave 从新 master 同步数 据,直至所有 slave 全部同步完毕
- 故障转移完毕
节点上线
- 原 Redis 节点上线
只要是原 Redis 集群中的节点上线,只需启动 Redis 即可。因为每个 Sentinel 中都保存有原来其监控的所有 Redis 节点列表, Sentinel 会定时查看这些 Redis 节点是否恢复。如果查看到其已经恢复,则会命其从当前 master 进行数据同步。如果是原 master 上线,在新 master 晋升后 Sentinel Leader 会立即先将原 master 节点更新为 slave,然后才会定时查看其是否恢复。
- 新 Redis 节点上线
如果需要在 Redis 集群中添加一个新的节点,则上线操作只能手工完成。即添加者在添加之前必须知道当前 master 是谁,然后在新节点启动后运行 slaveof 命令加入集群。
- Sentinel 节点上线
添加 Sentinel 节点需要手工完成。即在添加之前必须知道当前 master 是谁,然后在配置文件中修改 sentinel monitor 属性,指定要监控的 master。
CAP定理
CAP 定理的内容是:对于分布式系统,网络环境相对是不可控的,出现网络分区是不可避免的,因此系统必须具备分区容错性。但系统不能同时保证一致性与可用性。即要么 CP,要么 AP。
- 一致性(C):
分布式系统中多个主机之间是否能够保持数据一致的特性。即,当系统数 据发生更新操作后,各个主机中的数据仍然处于一致的状态。
- 可用性(A):
系统提供的服务必须一直处于可用的状态,即对于用户的每一个请求,系统总是可以在有限的时间内对用户做出响应。
- 分区容错性(P):
分布式系统在遇到任何网络分区故障时,仍能够保证对外提供满足一致性和可用性的服务。
分布式系统中,节点之间必然会有不同,比如网络、服务器等等,所以在分布式系统中分区容错性必然存在
BASE 理论
BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent(最终一致性)三个短语的简写,BASE 是对 CAP 中一致性和可用性权衡的结果
BASE 理论的核心思想是:即使无法做到强一致性,但每个系统都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。
- 基本可用
基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。
- 软状态
软状态,是指允许系统数据存在的中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统主机间进行数据同步的过程存在一定延时。
- 最终一致性
最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。
CAP 应用:
- Zookeeper
Zookeeper 遵循的是 CP 模式,当 Leader 节点中的数据发生了变化后,在 Follower 还没有同步完成之前,整个 Zookeeper集群是不对外提供服务的。
- Consul
Consul 遵循的是 CP 模式
- Redis
Redis 遵循的是 AP 模式
- Eureka
Eureka 遵循的是 AP 模式
- Nacos
Nacos 在做注册中心时,默认是 AP 的。但其也支持 CP 模式,但需要用户提交请求进行转换。
Raft 算法
Raft 算法是一种通过对日志复制管理来达到集群节点一致性的算法。这个日志复制管理发生在集群节点中的 Leader 与 Followers 之间。Raft 通过选举出的 Leader 节点负责管理日志复制过程,以实现各个节点间数据的一致性。
在 Raft 中,节点有三种角色:
- Leader:唯一负责处理客户端写请求的节点;同时负责日志复制工作
- Candidate:Leader 选举的候选人,其可能会成为 Leader。是一个选举中的过程角色
- Follower:可以处理客户端读请求;负责同步来自于 Leader 的日志;当接收到其它 Cadidate 的投票请求后可以进行投票;当发现 Leader 挂了,其会转变为 Candidate 发起 Leader 选举
leader 选举
- 选举
若 follower 在心跳超时范围内没有接收到来自于 leader 的心跳,则认为 leader 挂了。此时其首先本地 term 增一。然后 follower 会完成以下步骤:
- 若接收到了其它 candidate 的投票请求,则会将选票投出
- 由 follower 转变为 candidate
- 若之前尚未投票,则向自己投一票
- 向其它节点发出投票请求,然后等待响应
- 投票
follower 在接收到投票请求后,其会根据以下情况来判断是否投票:
- 发来投票请求的 candidate 的 term 不能小于我的 term
- 在当前 term 内,我的选票还没有投出去
- 若接收到多个 candidate 的请求,采取 first-come-first-served 方式投票
- 等待响应
当一个 Candidate 发出投票请求后会等待其它节点的响应结果。
- 收到过半选票,成为新的 leader。然后会将消息广播给所有其它节点,消息中包含 term 值
- 接收到别的 candidate 发来的新 leader 通知,比较新 leader 的 term 并不比自己的 term 小,则转变为 follower
- 一段时间内没有收到过半选票,也没有收到新 leader 通知,则重新发出选举
- 选举时机
可能会出现较多 candidate 票数相同的情况,即无法选举出 Leader。
为了防止这种情况的发生,Raft 算法采用了 randomized election timeouts 策略。其会为这些 Follower 随机分配一个选举发起时间 election timeout,这个 timeout 在 150-300ms 范围内。只有到达了 election timeout 时间的 Follower 才能转变为 candidate, 否则等待。
数据同步
正常运行期间, Leader 通过日志复制管理实现集群中各节点数据的同步。
Raft 算法一致性的实现,是基于日志复制状态机的。状态机的最大特征是,不同 Server 中的状态机若当前状态相同,然后接受了相同的输入,则一定会得到相同的输出。
处理流程
当 leader 接收到 client 的写操作请求后,大体会经历以下流程:
- leader 在接收到 client 的写操作请求后,leader 会将数据与 term 封装为一个 box,并随着下一次心跳发送给所有 followers,以征求大家对该 box 的意见。同时在本地将数据封 装为日志
- follower 在接收到来自 leader 的 box 后首先会比较该 box 的 term 与本地记录的曾接受过的 box 的最大 term,只要不比自己的小就接受该 box,并向 leader 回复同意。同时会将 该 box 中的数据封装为日志。
- 当 leader 接收到过半同意响应后,会将日志 commit 到自己的状态机,状态机会输出一个结果,同时日志状态变为了 committed
- 同时 leader 还会通知所有 follower 将日志 commit 到它们本地的状态机,日志状态变为了 committed
- 在 commit 通知发出的同时,leader 也会向 client 发出成功处理的响应
脑裂
在多机房部署中,由于网络连接问题,很容易形成多个分区。而多分区的形成,很容易产生脑裂,从而导致数据不一致。
三机房部署的容灾能力最强,下面以三机房部署为例进行分析
1.
B 机房中的主机感知不到 Leader 的存在,所以 B 机房中的主机会发起新一轮的 Leader 选举。由于 B 机房与 C 机房是相连的,虽然 C 机房中的 Follower 能够感 知到 A 机房中的 Leader,但由于其接收到了更大 term 的投票请求,所以 C 机房的 Follower 也就放弃了 A 机房中的 Leader,参与了新 Leader 的选举。
若新 Leader 出现在 B 机房,A 机房感知不到新 Leader 的诞生,不会转为follower,形成脑裂。此时 A 机房 Leader 处理的写操作请求无法获取到过半响应,所以无法完成写操作。若新 Leader 出现在 C 机房,A 机房中的 Leader 会自动下线。
2.
不会形成脑裂
3.
B 无法选举出新的 Leader,无法提供任何服务
4.
对于集群的运作不产生影响
- A、B、C 全部断开
A 机房无法处理写操作请求,但可以对外提供读服务。B、C 无法提供服务
Leader 宕机处理
- 请求到达前宕机
对集群数据的一致性没有任何影响。
- 未开始同步数据前宕机
接受到的数据丢失
- 同步完部分后宕机
client 发送写操作请求给 Leader,Leader 接收完数据后向所有 Follower 发送数据。在部分 Follower 接收到数据后 Leader 挂了。
- 若 Leader 产生于已完成数据接收的 Follower,其会继续将前面接收到的写操作请求转换为日志,并写入到本地状态机,并向所有 Flollower 发出询问。在获取过半同意响应后会向所有 Followers 发送 commit 指令,同时向 client 进行响应。
- 若 Leader 产生于尚未完成数据接收的 Follower,那么原来已完成接收的 Follower 则会放弃曾接收到的数据。