数据一致性算法

在分布式系统中,数据存储有两种,一种是共用一个持久化数据库,这种自带一致性;一种是数据在内存中,需要自己用一定方案保证集群中多节点数据一致性。 下面讨论的针对的是内存中数据在集群中的同步。

1. CAP 理论

​ CAP定理主要关注的是分布式系统中的数据一致性、可用性和分区容错性,特别是在分布式集群内部的数据管理和通信。它不直接涉及客户端和服务端的交互,而是关于在分布式环境中的多个节点如何协同工作以提供服务。

​ 在分布式系统中,无法同时保证以下三个特性:

Consistency(一致性):在所有节点看到的数据是一致的,即读操作总是返回最近写入的值,无论读请求发送到哪个节点。

Availability(可用性):每个非故障节点对读写请求总是能做出响应,且不保证返回最新数据。

Partition Tolerance(分区容错性):系统能够容忍网络分区(部分节点间的通信中断)而继续运行。

​ 因为必须保证高可用,所以分区容错性P是必须要保证的,也就是必须做多节点部署。在网络分区的情况下,无法同时保证一致性与可用性。这是因为当网络分区发生时,节点之间无法通信,系统必须做出选择:

​ 如果优先保证一致性,那么在无法确认所有节点状态一致之前,系统可能会拒绝某些请求,以防止数据冲突,这样就牺牲了可用性。

​ 如果优先保证可用性,系统将继续接受和处理请求,但可能会返回旧的数据或者部分节点的数据,从而牺牲了一致性。

​ 因此,在设计分布式系统时,通常需要在CAP三者之间进行权衡,根据业务场景和需求选择合适的折衷方案。许多现代分布式系统倾向于牺牲一致性(或弱化一致性模型,如最终一致性)以保证可用性和分区容错性。

2. 一致性

1. 为什么需要一致性

  1. 数据不能存在单个节点(主机)上,否则可能出现单点故障。
  2. 多个节点(主机)需要保证具有相同的数据。

2. 分类

​ 强一致性: 保证系统改变提交以后立即改变集群的状态,模型:Paxos、Raft(muti-paxos)、ZAB(muti-paxos)。muti-paxos 是一种解决分布式一致性问题的基础算法,而 Multi-Paxos 则是用于处理多轮提案(propose)的 Paxos 实现,使得系统能够处理连续的、多阶段的决策过程。

​ 弱一致性: 也叫最终一致性,系统不保证改变提交以后立即改变集群的状态,但是随着时间的推移最终状态是一致的。模型:DNS系统、Gossip协议

从单主和多主的角度对协议进行分类。

  • 多主协议:即整个集群中不只存在一个主节点,从多个主节点出发传输数据,传输顺序具有随机性,因而数据的有序性无法得到保证,只保证最终数据的一致性。比如著名的gossip、pow 协议。

  • 单主协议:即整个分布式集群中只存在一个主节点,主节点发出数据,传输给其余从节点,能保证数据传输的有序性。采用这个思想的主要有2PC, Paxos, Raft等。

单主算法涉及两部分: 
第一:选主-如何选择主节点以及主节点挂掉后如何重新选举: 一般是主节点发心跳到其他节点, 未收到心跳证明主节点挂掉
第二:数据如何写入以及写入后如何同步?
(1). 方式一:只有主节点处理写入请求,主节点处理完同步给其他节点(半数节点以上写入成功认为写入成功),该方式适用于写入请求不多且不分片存储的的case,大部分都是读请求。读取请求可以从任何节点读取。 比如nacos 的实现raft。
主节点: 心跳、处理写入请求,然后同步给从节点,半数以上成功即认为写入成功。
从节点: 负责接收主节点心跳;被动同步主节点数据。(如果写入发到从节点,会转发给主节点)
(2). 方式二:  所有节点可以处理写入请求,收到请求后转发给其他应该处理的节点。 这种适用于分片存储、且分片逻辑是在服务端计算的情况,比如es。
主节点: 负责维护集群间分片信息以及节点心跳,然后同步给其他节点。处理读写请求。
从节点: 负责被动接收主节点的心跳以及集群分片信息。 处理读写请求。

3. 实例

  • Google的Chubby分布式锁服务,采用了Paxos算法
  • etcd分布式键值数据库,采用了Raft算法
  • ZooKeeper分布式应用协调服务,Chubby的开源实现,采用ZAB算法
  • Gossip: Redis Cluster,Apache Cassandra,Apache Mesos

3. 多主协议

​ 多主协议只保证最终一致性,允许多个节点并发写,能够显著提升系统性能。由于多主协议一般提供的都是最终一致性,所以常用在对数据一致性要求不高的场景中。

1. gossip

1. 简介

​ Gossip protocol 也叫 Epidemic Protocol (流行病协议)。原本用于分布式数据库中节点同步数据使用,后被广泛用于数据库复制、信息扩散、集群成员身份确认、故障探测等。

​ 简单的理解就是集群以扩散的方式传播消息,每个节点收到信息之后随机选择其他几个节点进行发送。

例子:

20 个集群的消息同步, 假设每次扩散四个节点:
1. 第一次:节点1收到消息
2. 第二次:节点1向其他四个节点发送消息,这一轮完成后有5个节点同步到
3. 第三次:5个节点每个都像四个节点发送消息,这时候肯定就全部同步到。
理论上经过3次就能全部覆盖,实际节点在传播消息的时候,是随机选择N个节点的,这样的话,就有可能某个节点会被选中2次甚至更多次。

​ Goosip 协议的信息传播和扩散通常需要由种子节点发起。整个传播过程可能需要一定的时间,由于不能保证某个时刻所有节点都收到消息,但是理论上最终所有节点都会收到消息,因此它是一个最终一致性协议。

​ Gossip协议是一个多主协议,所有写操作可以由不同节点发起,并且同步给其他副本。Gossip内组成的网络节点都是对等节点,是非结构化网络。

2. 消息传播和通信

Gossip 协议的消息传播方式有两种:

  • Anti-Entropy(反熵传播):是以固定的概率传播所有的数据。所有参与节点只有两种状态:Suspective(病原)、Infective(感染)。这种节点状态又叫做simple epidemics(SI model)。过程是种子节点会把所有的数据都跟其他节点共享,以便消除节点之间数据的任何不一致,它可以保证最终、完全的一致。缺点是消息数量非常庞大,且无限制;通常只用于新加入节点的数据初始化
  • Rumor-Mongering(谣言传播):是以固定的概率仅传播新到达的数据。所有参与节点有三种状态:Suspective(病原)、Infective(感染)、Removed(愈除)。这种节点状态又叫做complex epidemics(SIR model)。过程是消息只包含最新 update,谣言消息在某个时间点之后会被标记为 removed,并且不再被传播。缺点是系统有一定的概率会不一致,通常用于节点间数据增量同步

Gossip 协议最终目的是将数据分发到网络中的每一个节点。根据不同的具体应用场景,网络中两个节点之间存在三种通信方式:

  • Push: 节点 A 将数据 (key,value,version) 及对应的版本号推送给 B 节点,B 节点更新 A 中比自己新的数据
  • Pull:A 仅将数据 key, version 推送给 B,B 将本地比 A 新的数据(Key, value, version)推送给 A,A 更新本地
  • Push/Pull:与 Pull 类似,只是多了一步,A 再将本地比 B 新的数据推送给 B,B 则更新本地

​ 如果把两个节点数据同步一次定义为一个周期,则在一个周期内,Push 需通信 1 次,Pull 需 2 次,Push/Pull 则需 3 次。虽然消息数增加了,但从效果上来讲,Push/Pull 最好,理论上一个周期内可以使两个节点完全一致。直观上,Push/Pull 的收敛速度也是最快的。

3. 确保数据同步到所有节点以及处理重复接收消息的两个关键机制:

到达所有节点:

1. 随机选择和多播(Random Selection and Multicasting)
随机选择:每个节点周期性地随机选择几个邻居节点(通常是固定数量或者按照一定比例),并向这些节点发送自己的状态信息或更新。这种随机性有助于快速覆盖整个网络,减少传播延迟。
多播:通过向多个节点同时发送消息,增加信息传播的速度和可靠性。即使部分消息丢失,由于信息在多个路径上传播,其他节点仍然有机会接收到。
2. 指数退避与反熵(Exponential Backoff and Anti-Entropy)
指数退避:如果一个节点尝试向另一个节点发送信息但未得到确认,它会等待一段时间后再次尝试,这个等待时间通常按指数级增长,以避免在网络拥塞时加剧问题。
反熵(Anti-Entropy):为了确保数据的一致性,节点除了传播新状态外,还会定期与相邻节点进行全状态同步(Full State Synchronization)或增量同步(Incremental State Synchronization)。这可以视为一种健康检查,用来发现并修复因消息丢失导致的状态不一致。

重复接收:

1. 唯一标识符(Unique Message IDs):为每条消息分配一个全局唯一的ID,接收节点可以通过检查ID来判断是否已经接收过该消息,从而避免处理重复消息。
2. 版本控制或时间戳(Versioning/Timestamps):消息附带版本号或时间戳,当接收到具有相同标识但较旧版本的消息时,节点可以忽略它,只保留最新版本。
3. 去重缓存(Deduplication Cache):节点维护一个缓存,记录最近处理过的消息ID或关键信息,对于已知的重复消息直接丢弃。

4. 优劣

它具备以下优势:

  • 可扩展性:允许节点的任意增加和减少,新增节点的状态最终会与其他节点一致。
  • 容错性:任意节点的宕机和重启都不会影响 Gossip 消息的传播,具有天然的分布式系统容错特性。
  • 去中心化:无需中心节点,所有节点都是对等的,任意节点无需知道整个网络状况,只要网络连通,任意节点可把消息散播到全网。

同样也存在以下缺点:

  • 消息延迟:节点随机向少数几个节点发送消息,消息最终是通过多个轮次的散播而到达全网;不可避免的造成消息延迟。
  • 消息冗余:节点定期随机选择周围节点发送消息,而收到消息的节点也会重复该步骤;不可避免的引起同一节点消息多次接收,增加消息处理压力。
  • 拜占庭问题:如果有一个恶意传播消息的节点,Gossip协议的分布式系统就会出问题。

5. 适用场景

​ 适合于AP场景的数据一致性处理,常见应用有:P2P网络通信、Apache Cassandra、Redis Cluster、Consul。

2. pow

​ PoW(Proof of Work,工作量证明)协议是一种广泛应用于加密货币领域的共识机制,最初由比特币引入并普及。其核心目的是确保网络中的参与者就区块链的状态达成一致,同时防止恶意行为,如双重支付。

​ 实际就是基于算力来决定,有可能出现算力一致。

4. 单主协议

​ 一种常见的用于保证数据一致性的方式。在这种模式下,只有一个节点担任主节点的角色,负责处理所有的写操作,并同步这些更改到其他从节点。这种方式通常用于需要强一致性的场景,例如数据库复制或者分布式键值存储。常见的有:Paxos、Raft(muti-paxos)、ZAB(muti-paxos)

1. Paxos:

​ Paxos 是由 Leslie Lamport 提出的一种分布式一致性算法。它允许一组节点(称为接受者或服务器)在面临网络延迟和故障的情况下就提案达成一致。
​ Paxos 的核心思想是通过多轮提议和投票来确保只有一个提案被接受。它分为提议阶段、准备阶段和提交阶段,通过多数派原则保证决策的正确性。

角色:(一个进程可以充当多个角色)

proposer: 向集群提出议案,在发生冲突时候起到冲突调节作用

acceptor: 对提议投票 只有在达到多数派时提议才会被最终接受

leader: 提议接受者, 对集群一致性没什么影响,单纯的记录人员

proposal:proposer 提出的议案或建议, 编号n 或者内容value。

算法目标:每个proposer、acceptor、leadner 都认为同一个proposal 中的value 被选中

两大阶段:

  • prepare 阶段
  1. Prepare(N) 请求,proposer 提出一个proposal,编号为N(编号应该是递增的,大于等于之前所有已经提出的编号),向所有的Acceptor广播。(这里只有编号没有内容)
  2. promise(n,value): 如果N 大于该acceptor 此前接受的所有提案编号就接受(并承诺不在接受比N小的提议), 否则就拒绝。 如果该acceptor 已经存在相同的甜就返回这个提案的编号和内容(返回空值就表示接收)
  • accept 阶段
  1. Accept(N,value) 请求:proposer 收到多数派(多于一半的acceptor返回的promise), 如果存在编号大的议案就进行更新value, 范泽返回本次议案的value。(收到议案的n 与提出的编号N 无关)
  2. accepted(N)返回: 如果在此期间没有任何编号大于N的提案,就接收提案内容,否则拒绝
  3. 当proposer 收到超过半数的acceptor 的返回值后,达成共识

例子:

1. 三支蓝军,一支白军,如果两支以上蓝军同时进攻蓝军胜利,否则白军胜。
2. 因此蓝军需要同步他们的进攻时间,而只能通过步兵同步进攻时间。而有可能被白军俘虏从而将信息丢失。
3. 每支军队有1个参谋负责提议进攻时间,每支军队也有一个将军批准提出的进攻时间。 很明显需要至少2个将军的批准才有意义。

过程图如下:

解释:

1. 参谋1 发起prepare, 编号为1。此时将军1、2 都接受该编号;(编号是单调递增且唯一的,比如可以按时间戳等方式)
2. 参谋2 发起prepare, 编号为2. 将军2、3 都接收编号2;
3. 参谋1 继续发起accept 请求,编号为1、value为进攻时间1,此时将军1 接收; 将军2因为编号为2就拒绝并返回编号2
4. 参谋2 继续发起 accept 编号2、进攻时间2 的请求, 将军2、3 都接受
5. 参谋1 重新发起第二轮prepare, 编号为3,将军1返回(编号1,进攻时间1); 将军2 返回(编号2,进攻时间2)
6. 参谋1 选取编号大的编号2 作为依据,发起accept (编号3、进攻时间2),此时将军1、2 都接受, 因此进攻时间变为进攻时间2

存在的问题以及解决方案:

1. 活锁:
现象:当某一proposer 提交的proposal 编号被拒绝,可能是因为acceptor 返回了更大编号的proposal,因此proposer 提高编号继续提交。 如果2个proposer 一直出现这种情况,可能导致死循环,也被称为活锁。
解决方案:
后退策略(冲突后等待一段时间重试, 冲突次数增加等待的时间也相应增加), 也称为二进制指数退避法
2. 效率低:
现象:每个完整流程的提议都需要经过两大轮请求返回
解决方案:multi-paxos 先选出leader, 后续每次经过一轮, leader 强一致性。 比如raft
3. 实现困难: 当前共识算法普遍存在的问题

2. Raft协议

​ 思想: 集群有一个主节点,所有的写请求打到主节点。主节点然后同步阻塞将数据同步给其他节点,如果半数以上成功,就代表写入成功; 否则写入失败会抛出非法状态异常,可能就需要排查集群是否正常。也就是集群有一半的机器存活,集群就能正常工作。

核心逻辑:

  1. 领导选举:

(1). Raft 系统中的节点在任何时候都处于三种状态之一:领导者(Leader-处理操作请求,自己处理后同步其他follower 节点)、跟随者(Follower-请求的被动更新着,接收leader 的更新请求)或候选者(Candidate - follower 一定时间内没收到leader 的心跳认为leader 故障,会把自己升为候选者,随机时间到期后自己发起投票给自己投一票)。

(2). 当系统启动或领导者失效时,节点会转换为候选者状态并发起选举,通过请求投票(RequestVote) RPC 向其他节点寻求支持。

(3). 基于任期(Term)的概念,每个选举都有一个独一无二的任期号,确保过时的投票无效,防止选票分裂。

(4). 获得大多数节点支持的候选者将成为新的领导者,负责处理客户端请求和管理日志复制

简单理解:

  • 每个节点有一个随机等待时间,到达之后判断是否需要发起集群选主; 有一个term 数值,用于判断当前的选举版本。当集群暂未选出主节点或者没收到主节点心跳,把自己的角色设为CANDIDATE(只要是候选者在未选出主的情况下就会一直向其他节点拉票)、随机等待时间到期之后给自己投一票(term + 1),然后向兄弟节点收集投票结果,假设B先到期
  • 兄弟节点A收到B的投票请求后和自己的term 值(term = 0)比较,如果B小于等于A的值,那A投给A自己; 否则,A把自己的角色改为FOLLOWER 从节点,然后把自己的票数term 设为和B节点的一样、重置自己的等待时间. (这里A的voteFor为B,A同时把自己的term 也改为1; 同理,其他节点也一样,都是voteFor = B, term = 1)
  • B每次收集完结果之后,判断票数最多(根据voteFor 判断B最多)且超过半数(不包含自己的选举结果),那么就可以设为leader 主节点(将自己设为leader), 这是B已经知道自己是主节点
  • 主节点每次心跳会将自己的信息同步给兄弟节点(只有主节点会发心跳给其他节点,其他节点记录主节点等信息-com.alibaba.nacos.naming.consistency.persistent.raft.RaftCore.HeartBeat#sendBeat)。

总数: 票数是根据voteFor 汇总得到的,需要大于一半以上(n/2 + 1); 判断是否给其他节点投票是根据term 判断的(你大于我的term我投给你)

  1. 数据同步
    (1). 所有的写请求会到达leader 节点(如果请求打到非leader 节点,会转发给leader 节点)

    (2). leader 同步将数据发给其他兄弟节点,超过半数回复正常才会认为写入成功; 否则会抛出非法状态异常,这时候可能需要排查 集群状态

  2. 几个核心问题:

1. 投票分裂的脑裂问题以及解决 
(1). 假设5个节点ABCDE, 此时集群的term = 1(所有的term 都为1),leader 节点E宕机;
(2). AB 的随机时间同时到期, A、B term 设为2向其他节点拉票, 然后分别向其他节点拉票。CD 都投赞成票、A不会投B、B不会投A, 此时的状态是: ABCD term 都是2, A、B 收到投票结果判断的时候,选自己的节点为C\D, 不超过一半(3), 因此C、D 会一直向E 拉票(不知道E 宕机)
(3). 此时C 节点,发现没收到主心跳,自己变为候选者,随机时间到期后,自己的term 变为5,然后向其他节点发起拉票(大于另外三个节点的term=4); 此时C 升为主节点

2. raft 数据问题:
leader 强一致性,所有的以leader 为主

3. 机器为什么建议奇数?
原则: 集群有一半的机器存活,集群就能正常工作。 size/2 + 1
集群数量-半数以上-允许宕机数量
2-2-0
3-2-1
4-3-1
5-3-2
6-4-2
7-4-3
部署分布式一致性协议集群时,一般关注的是允许宕机数量,可以看到偶数和奇数允许宕机是一样的,因此奇数可以节约一台机器。

4. 脑裂问题?
脑裂问题和奇数、偶数无关, 甚至奇数节点更好点。 比如双机房,两个机房网络不通的情况下:
7个节点: 4、3 分,假设两个机房网络不通,机房数量为4的还能正常工作,超过半数;
8个节点: 4、4 分,假设两个机房网络不通,无法产生主节点,有可能集群无法正常工作。

参考: nacos raft 实现,源码: com.alibaba.nacos.naming.consistency.persistent.raft.RaftCore

3. ZAB 协议

​ ZAB 是 Apache ZooKeeper 项目使用的一种一致性算法,它结合了Paxos和Multi-Paxos的思想,用于实现原子广播(Atomic Broadcast)。

​ ZAB 专注于提供高可用性和一致性保证,特别是为分布式协调服务如Zookeeper设计的。

​ ZAB 包括了领导者选举和原子广播两个主要阶段。在选举阶段,一个节点成为领导者,其他节点成为跟随者。一旦选举完成,领导者将负责处理所有事务并广播给跟随者。

​ 与 Raft 类似,ZAB 也依赖于领导者来保证一致性,但它的设计更侧重于满足分布式协调服务的需求,如保证数据的最终一致性。

	主备模式:ZAB协议采用主从结构,其中有一个领导者(Leader)和多个跟随者(Followers)。领导者负责接收和处理客户端的请求,以及协调集群内部的一致性。
	原子广播:领导者接收到客户端的更新请求后,会将这些请求转化为事务提案(Proposal)并广播给所有跟随者。跟随者接收到提案后,会执行并确认事务。
	崩溃恢复:当领导者崩溃或网络分区发生时,ZAB协议会启动崩溃恢复模式。这个过程包括选举新的领导者和同步所有跟随者的状态,确保新领导者拥有所有已提交的事务。
	选举过程:通过ZXID(事务ID)和服务器ID来决定新领导者,ZXID较大的服务器有更高的优先级,如果ZXID相同,则ID大的服务器成为领导者。
领导者选举完成后,所有服务器与新领导者同步状态,包括未完成的事务和已经提交的事务。
	单一线程模型:为了简化一致性,ZAB协议在领导者节点上使用单线程处理提议,确保了提案的顺序性。
	同步协议:领导者和跟随者之间使用同步协议来确认事务已经被正确处理。一旦大多数跟随者确认,领导者就会将事务标记为已提交,并广播给所有节点。
	持久化:为了保证容错性,ZooKeeper会将事务日志和快照持久化到磁盘,以便在重启后恢复状态。

4. Raft、zab 区别

设计目标:Raft协议的设计目标是易于理解和实现,而ZAB协议则是为ZooKeeper这样的系统设计的,注重高可用性和高性能。

日志和提案标识:Raft使用术语(Term)和索引(Index)来唯一标识每个提案,而ZAB使用Epoch(时代)和计数器(Count)的组合。

选举逻辑:在选举过程中,Raft的follower简单地根据term投票,而ZAB的follower在投票给一个leader之前,必须确保自己的日志与leader的日志一致。

日志匹配:在ZAB中,follower必须与leader的日志达到同步才能成为follower,而在Raft中,follower通常只需确认term即可。

心跳机制:在Raft和ZAB中,心跳都是从leader到follower,以检测节点的存活状态。然而,ZAB的心跳还用于同步和确认事务。

数据流向:在Raft中,数据流仅从leader到follower,确保所有节点都有相同的日志状态。ZAB也有类似的机制,但可能更关注确保领导者和跟随者之间的事务同步。

一致性模型:Raft使用一种称为“日志复制”的模型,确保了线性一致性。ZAB也实现了类似的一致性模型,但更侧重于快速恢复和高可用性。

应用范围:Raft被广泛应用于各种分布式系统,而ZAB是ZooKeeper专有的协议。

5. 无主协议

​ 无主协议,也可以理解为多主协议。只是不是属于通用协议。节点都是同角色的兄弟节点。

1. Eureka 集群

​ Eureka Server之间通过自我复制机制来实现数据同步。

​ 当一个新的Eureka Server加入集群时,它会从现有的Eureka Server那里拉取服务注册表信息,也就是进行全量同步。当节点收到新的

写入请求时,会通过http 接口调用同步到其他兄弟节点。 内嵌Jersey(一种http 框架) http 接口。 读取的时候客户端随机选择节点进行获

取,每个节点存的都是全量数据。

2. nacos 集群 - DISTRO 协议

​ nacos 有AP\CP, 默认是AP,也就是默认走DISTRO 协议,可以通过配置设置为走Raft 协议。

​ 自研的一致性协议,主要用于在集群节点之间实现数据的快速同步和一致性保证。 思想是实现AP,节点分数据处理,也就是一个节点处理部分数据。 处理完之后通过异步任务,同步到其他节点,趋向于最终一致性。

思路:读请求所有节点都可以处理;写请求是根据service_name 或者 实例信息(ip:port) 进行分片,分到对应的节点进行处理,节点处理完异步通知其他节点进行同步。(目的就是将写入的请求分片分到不同的节点,然后处理完成后同步给集群其他节点;该方式避免同一节点处理大量写入请求造成服务阻塞。)

1. com.alibaba.nacos.naming.web.DistroFilter#doFilter
(1). 判断是否能处理响应: 根据服务名称或者ip加端口获取服务下标
int index = distroHash(responsibleTag) % servers.size();
return servers.get(index);

private int distroHash(String responsibleTag) {
	return Math.abs(responsibleTag.hashCode() % Integer.MAX_VALUE);
}
(2). 如果是当前服务自己,放行到后面的处理过程
(3). 否则拿到请求参数和请求头,http 调用到指定的机器进行处理
2. com.alibaba.nacos.naming.core.InstanceOperatorServiceImpl#registerInstance 处理注册逻辑
(1). 内部处理相关的注册逻辑
(2). 异步调用其他兄弟节点进行同步数据:com.alibaba.nacos.core.distributed.distro.DistroProtocol#sync
    public void sync(DistroKey distroKey, DataOperation action, long delay) {
        for (Member each : memberManager.allMembersWithoutSelf()) {
            syncToTarget(distroKey, action, each.getAddress(), delay);
        }
    }

大致过程:

  1. 初始化: 节点启动时初始化distro 相关组件,包含数据同步处理器以及服务监听器。
  2. 全量同步: 新加入集群的节点会请求全量数据,其他节点发送全量数据; 新节点收到全量数据后,进行校验和处理
  3. 增量同步:全量同步完成后,后续的同步是基于增量同步,只同步新产生的数据。 每个节点定期向其他节点发送增量请求,同步到本地进行处理
  4. 心跳与确认:节点之前定时发送心跳,以检测对方的存活状态
posted @ 2024-06-25 20:20  QiaoZhi  阅读(68)  评论(1编辑  收藏  举报