zk的主要应用场景有:服务注册中心、分布式锁、master选举、分布式事务一致性等。
一、架构
1、如下为Zookeeper的整体架构
leader通过zab协议选举产生。
各个server之间通过zab协议(原子广播协议)进行数据同步。
要搭建一个高可用的Zookeeper集群,需要确定好集群规模。一般将节点(指leader及follower节点,不包括observer节点)个数设置为 2*n+1 ,n为可容忍宕机的个数。
2、集群角色
Zookeeper集群中的角色包括Leader、Follower和Observer,每个角色在集群中承担不同的职责:
- Leader(必须):
-
- 事务请求处理者:Leader节点负责处理所有的事务请求,例如创建、更新和删除节点(写操作)。
- 集群协调者:Leader节点负责协调集群中的其他节点,确保集群状态的一致性。
- 事务日志管理:Leader节点负责将事务日志分发给Follower节点,以保证数据的同步。
- 选举过程:在集群启动或Leader节点故障时,负责启动和执行领导者选举过程。
- Follower(必须):
-
- 事务请求参与者:Follower节点接收客户端的事务请求,并将其转发给Leader节点。
- 投票参与者:Follower节点参与Leader选举过程,通过投票决定新的Leader。
- 数据同步:Follower节点接收来自Leader节点的事务日志更新,以保持数据的一致性。
- 客户端服务:Follower节点可以处理客户端的非事务请求,如读取节点数据。
- Observer(从Zookeeper 3.3.0版本开始引入,可选角色,需要手动单独部署):
-
- 读请求处理:Observer节点可以独立处理客户端的非事务请求,如读取节点数据。
- 不参与投票:Observer节点不参与Leader选举过程和事务请求的投票。
- 数据同步:Observer节点通过接收Leader节点的INFORM消息来同步数据。
- 扩展读性能:Observer节点用于扩展集群的读性能,特别是在大量客户端并发读请求的场景下。
- 跨数据中心部署:Observer节点可以部署在不同的数据中心,以减少客户端读请求的延迟。
- 部署方式:需要在该节点的zoo.cfg配置文件中添加peerType=observer
每种角色在Zookeeper集群中发挥着关键作用,确保了集群的高可用性、一致性和扩展性。Leader和Follower共同负责处理写请求和集群协调,而Observer主要用于提高读性能和支持跨地域部署。
二、ZooKeeper数据模型
从图中我们可以看出ZooKeeper的数据模型,在结构上和标准文件系统的非常相似,都是采用这种树形层次结构,ZooKeeper树中的每个节点被称为—Znode。和文件系统的目录树一样,ZooKeeper树中的每个节点可以拥有子节点。但也有不同之处:
(1) 引用方式
Zonde通过路径引用,如同Unix中的文件路径。路径必须是绝对的,因此他们必须由斜杠字符来开头。除此以外,他们必须是唯一的,也就是说每一个路径只有一个表示,因此这些路径不能改变。在ZooKeeper中,路径由Unicode字符串组成,并且有一些限制。字符串"/zookeeper"用以保存管理信息,比如关键配额信息。
(2) Znode结构
ZooKeeper命名空间中的Znode,兼具文件和目录两种特点。既像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分。图中的每个节点称为一个Znode。 每个Znode由3部分组成:
① stat:此为状态信息, 描述该Znode的版本, 权限等信息
② data:与该Znode关联的数据
③ children:该Znode下的子节点
ZooKeeper虽然可以关联一些数据,但并没有被设计为常规的数据库或者大数据存储,相反的是,它用来管理调度数据,比如分布式应用中的配置文件信息、状态信息、汇集位置等等。这些数据的共同特性就是它们都是很小的数据,通常以KB为大小单位。ZooKeeper的服务器和客户端都被设计为严格检查并限制每个Znode的数据大小至多1M,但常规使用中应该远小于此值。
(3) 数据访问
ZooKeeper中的每个节点存储的数据要被原子性的操作。也就是说读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据。另外,每一个节点都拥有自己的ACL(访问控制列表),这个列表规定了用户的权限,即限定了特定用户对目标节点可以执行的操作。
(4) 节点类型
ZooKeeper中的节点有两种,分别为临时节点和永久节点。节点的类型在创建时即被确定,并且不能改变。
① 临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话(Session)结束,临时节点将被自动删除(这是个很常用的场景,如HBase集群和Zookeeper保持的就是会话,并维护临时节点,一但会话丢失,则临时节点也删除,临时节点删除,表示对应的HBase的服务器不可用了),当然可以也可以手动删除。虽然每个临时的Znode都会绑定到一个客户端会话,但他们对所有的客户端还是可见的。另外,ZooKeeper的临时节点不允许拥有子节点。
② 永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。
(5) 顺序节点
当创建Znode的时候,用户可以请求在ZooKeeper的路径结尾添加一个递增的计数。这个计数对于此节点的父节点来说是唯一的,它的格式为"%10d"(10位数字,没有数值的数位用0补充,例如"0000000001")。当计数值大于232-1时,计数器将溢出。
(6) Watcher
Zookeeper中的所有读操作有:getData(), getChildren()和exists(),都有一个设置Watcher的选项,我们称之为监视器。Zookeeper的Watcher会在观察数据发生变化时,发送给建立Watcher的客户端一个一次性触发器。在客户端接收到Watcher信息后,这个Watcher就会关闭。
三、案例:利用zookeeper的znode节点路径的唯一性,从而方便的控制task的分布式运行
@Service
@Slf4j
public class ZookeeperUtils {
public static String parentZnode = "/hubble-task";
@Value("${zookeeper_address}")
private String zookeeper_address;
@Value("${zookeeper_user}")
private String zookeeper_user;
@Value("${zookeeper_password}")
private String zookeeper_password;
public static CuratorFramework curatorFramework = null;
public CuratorFramework getCuratorFramework() throws Exception {
try {
if (curatorFramework != null)
return curatorFramework;
curatorFramework = CuratorFrameworkFactory.builder().connectString(zookeeper_address).sessionTimeoutMs(30000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3)).namespace("curator").build();
curatorFramework.start();
if (!StringUtils.isEmpty(zookeeper_user) && !StringUtils.isEmpty(zookeeper_password)) {
ZooKeeper zk = curatorFramework.getZookeeperClient().getZooKeeper();
zk.addAuthInfo("digest", (zookeeper_user + ":" + zookeeper_password).getBytes());
}
if (curatorFramework.checkExists().forPath(parentZnode) != null)
return curatorFramework;
curatorFramework.create().withMode(CreateMode.PERSISTENT).forPath(parentZnode,
String.valueOf(System.currentTimeMillis()).getBytes());
} catch (Exception e) {
log.error("getCuratorFramework has error:",e);
}
return curatorFramework;
}
/**
* 创建节点。创建成功即获得执行权。
*
* @throws Exception
*/
public void createNote(String nodeName) throws Exception {
String path = parentZnode + nodeName;
// 获取连接
CuratorFramework curatorFramework = getCuratorFramework();
try {
// 获取节点值
byte[] valNote = curatorFramework.getData().forPath(path);
// 节点存在时
if (valNote != null && valNote.length > 0) {
// 获取节点值
String strVal = new String(valNote);
// 节点保存时间
long logVal = Long.parseLong(strVal);
// 当前时间
long logCurrent = System.currentTimeMillis();
// 节点超过存活时间,删除节点 暂定统一30秒
if (logCurrent - logVal > 1000 * 30) {
curatorFramework.delete().forPath(path);
}
}
} catch (Exception e) {
}
// 创建节点
curatorFramework.create().withMode(CreateMode.PERSISTENT).forPath(path,
String.valueOf(System.currentTimeMillis()).getBytes());
}
}
四、Watch机制
Zookeeper提供了数据的发布/订阅功能,多个订阅者可同时监听某一特定主题对象,当该主题对象的自身状态发生变化时(例如节点内容改变、节点下的子节点列表改变等),会实时、主动通知所有订阅者。
Zookeeper采用了Watcher机制实现数据的发布/订阅功能。该机制在被订阅对象发生变化时会异步通知客户端,因此客户端不必在Watcher注册后轮询阻塞,从而减轻了客户端压力。
Watcher机制实际上与观察者模式类似,也可看作是一种观察者模式在分布式场景下的实现方式。
五、基于ZooKeeper实现简单的服务注册于发现
- 基于watcher机制,监听服务地址的变化,当有新增服务或服务宕机的时候,及时的更新服务
- 临时有序节点:当宕机的时候,zookeeper能够及时的剔除掉
- Znode的子节点机制:即将某个应用集群的的所有服务器地址注册成子节点。
大致实现方式分如下几个步骤:
1、服务端(应用)启动,将自身的IP地址和PORT注册到Zookeeper的某个Znode的child上;
2、客户端启动的时候,init方法会读取Zookeeper的某个Znode的所有child,并注册watcher,此watcher的逻辑是当此Znode变更的时候通知我
3、客户端接收到通知后,对本地已经缓存的服务列表进行更新。
六、分布式锁
- 基于watcher机制,临时有序节点
Zookeeper基于临时有序节点实现分布式锁。
七、配置管理
- 基于watcher机制
目前很多公司开发或者使用的程序都是分布式的,而程序总会或多或少的存在一些额外配置,且分散部署在多台机器上。某一条要修改配置,要逐个去修改配置就变得有些困难,特别是应用部署的点数特别大的时候,就成了不可能完成的事情了。一种方式就是把相关配置写到数据库中,每个应用去读取数据库的配置,这种方式优点就是把配置集中管理,缺点也很明显,就是不能及时获得配置的变革,要及时获得变更后的配置,就要不停的去扫描数据库,而这又会造成数据库的压力巨大。
我要说的这种方式就是利用zookeeper的这种发布订阅、watch来实现。即,把相关的配置数据写到zookeeper的某个指定的节点下。应用服务监听这个节点的数据变化,一旦节点数据(配置信息)发生了变化,应用服务就会收到zookeeper的通知,然后应用服务就可以从zookeeper获得新的配置信息。
八、ZooKeeper在HBase中的应用
HMaster
所有的 HMaster启动的时候竞争去创建一个名称相同的临时节点。Zookeeper确定只有一个能创建成功,其它失败的子节点针对这个成功的子节点注册Watcher事件,当临时节点被删除的时候,所有竞争失败的节点会重新参与竞争,这样就保证了一个集群中一定有且只有一个HMaster能成功,且当一个HMaster挂掉之后会有另一个立即晋升为matser,保证HA。
RegionServer
当HBase启动时,每个RegionServer都会到ZooKeeper的/hbase/rs
节点下创建一个信息节点(下文中,我们称该节点为"rs状态节点"),例如/hbase/rs/[Hostname]
,同时,HMaster会对这个节点注册监听。当某个 RegionServer 挂掉的时候,ZooKeeper会因为在一段时间内无法接受其心跳(即 Session 失效),而删除掉该 RegionServer 服务器对应的 rs 状态节点。与此同时,HMaster 则会接收到 ZooKeeper 的 NodeDelete 通知,从而感知到某个节点断开,并立即开始容错工作。
HBase为什么不直接让HMaster来负责RegionServer的监控呢?如果HMaster直接通过心跳机制等来管理RegionServer的状态,随着集群越来越大,HMaster的管理负担会越来越重,另外它自身也有挂掉的可能,因此数据还需要持久化。在这种情况下,ZooKeeper就成了理想的选择。
RootRegion管理
对应HBase集群来说,数据存储的位置信息是记录在元数据region,也就是RootRegion上的。每次客户端发起新的请求,需要知道数据的位置,就会去查询RootRegion,而RootRegion自身位置则是记录在ZooKeeper上的(默认情况下,是记录在ZooKeeper的/hbase/meta-region-server
节点中)。当RootRegion发生变化,比如Region的手工移动、重新负载均衡或RootRegion所在服务器发生了故障等是,就能够通过ZooKeeper来感知到这一变化并做出一系列相应的容灾措施,从而保证客户端总是能够拿到正确的RootRegion信息。
Region管理
HBase里的Region会经常发生变更,这些变更的原因来自于Region分裂与合并、系统故障、负载均衡、配置修改等。一旦Region发生移动,它就会经历下线(offline)和重新上线(online)的过程。
在下线期间数据是不能被访问的,并且Region的这个状态变化必须让全局知晓,否则可能会出现事务性的异常。对于大的HBase集群来说,Region的数量可能会多达十万级别,甚至更多,这样规模的Region状态管理交给ZooKeeper来做也是一个很好的选择。
分布式SplitWAL任务管理
当某台RegionServer服务器挂掉时,由于总有一部分新写入的数据还没有持久化到HFile中,因此在迁移该RegionServer的服务时,一个重要的工作就是从WAL中恢复这部分还在内存中的数据,而这部分工作最关键的一步就是SplitWAL,即HMaster需要遍历该RegionServer服务器的WAL,并按Region切分成小块移动到新的地址下,并进行日志的回放(replay)。
由于单个RegionServer的日志量相对庞大(可能有上千个Region,上GB的日志),而用户又往往希望系统能够快速完成日志的恢复工作。因此一个可行的方案是将这个处理WAL的任务分给多台RegionServer服务器来共同处理,而这就又需要一个持久化组件来辅助HMaster完成任务的分配。当前的做法是,HMaster会在ZooKeeper上创建一个SplitWAL节点(默认情况下,是/hbase/SplitWAL
节点),将"哪个RegionServer处理哪个Region"这样的信息以列表的形式存放到该节点上,然后由各个RegionServer服务器自行到该节点上去领取任务并在任务执行成功或失败后再更新该节点的信息,以通知HMaster继续进行后面的步骤。ZooKeeper在这里担负起了分布式集群中相互通知和信息持久化的角色。
九、Zookeeper在Kafka中的应用
Kafka对Zookeeper的依赖性很强,不仅依赖于进行副本Leader选举,还将几乎所有元数据都存储在Zookeeper上。
1、Broker注册
Broker是分布式部署并且相互之间相互独立,但是需要有一个注册系统能够将整个集群中的Broker管理起来,此时就使用到了Zookeeper。在Zookeeper上会有一个专门用来进行Broker服务器列表记录的节点:
/brokers/ids
每个Broker在启动时,都会到Zookeeper上进行注册,即到/brokers/ids下创建属于自己的节点,如/brokers/ids/[0...N]。
Kafka使用了全局唯一的数字来指代每个Broker服务器,不同的Broker必须使用不同的Broker ID进行注册,创建完节点后,每个Broker就会将自己的IP地址和端口信息记录到该节点中去。其中,Broker创建的节点类型是临时节点,一旦Broker宕机,则对应的临时节点也会被自动删除。
2、Topic注册
在Kafka中,同一个Topic的消息会被分成多个分区并将其分布在多个Broker上,这些分区信息及与Broker的对应关系也都是由Zookeeper在维护,由专门的节点来记录,如:
/brokers/topics
Kafka中每个Topic都会以/brokers/topics/[topic]的形式被记录,如/brokers/topics/login和/brokers/topics/search等。Broker服务器启动后,会到对应Topic节点(/brokers/topics)上注册自己的Broker ID并写入针对该Topic的分区总数,如/brokers/topics/login/3->2,这个节点表示Broker ID为3的一个Broker服务器,对于"login"这个Topic的消息,提供了2个分区进行消息存储,同样,这个分区节点也是临时节点。
3、leader选举
Leader副本所在的 Broker 宕机时 ,Kafka 依托于 ZooKeeper 提供的监控功能能够快速的感知到,并立即开启新一轮的Leader选举,从追Follower副本中选一个作为新的领导者。老 Leader 副本重启回来后,只能作为追随者副本加入到集群中。
十、ZooKeeper在 Hadoop 中的应用
Hadoop 通过 ZooKeeper 保障高可用的原理:
当 Active NameNode 发生故障时:
- Active NameNode 与 ZooKeeper 的连接会断开,其在 ZooKeeper 中注册的临时节点会被自动删除。
- ZooKeeper 检测到这个变化后,会通知所有的 Standby NameNode。
- Standby NameNode 收到通知后,开始竞争在 ZooKeeper 中创建临时节点,第一个成功创建的 Standby NameNode 被选举为新的 Active NameNode。
- 新的 Active NameNode 接管服务,并从 JournalNode 读取编辑日志,快速恢复到最新状态,继续为 Hadoop 集群提供服务。
在Hadoop中,ZooKeeper主要用于实现HA(Hive Availability),包括HDFS的NamaNode和YARN的ResourceManager的HA。同时,在YARN中,ZooKeepr还用来存储应用的运行状态。HDFS的NamaNode和YARN的ResourceManager利用ZooKeepr实现HA的原理是一样的,所以本节以YARN为例来介绍。
YARN主要由ResourceManager(RM)、NodeManager(NM)、ApplicationMaster(AM)和Container四部分组成。其中最核心的就是ResourceManager。
ResourceManager负责集群中所有资源的统一管理和分配,同时接收来自各个节点(NodeManager)的资源汇报信息,并把这些信息按照一定的策略分配给各个应用程序(Application Manager),其内部维护了各个应用程序的ApplicationMaster信息、NodeManager信息以及资源使用信息等。
为了实现HA,必须有多个ResourceManager并存(一般就两个),并且只有一个ResourceManager处于Active状态,其他的则处于Standby状态,当Active节点无法正常工作(如机器宕机或重启)时,处于Standby的就会通过竞争选举产生新的Active节点。
主备切换
下面我们就来看看YARN是如何实现多个ResourceManager之间的主备切换的。
- 创建锁节点
在ZooKeeper上会有一个/yarn-leader-election/appcluster-yarn
的锁节点,所有的ResourceManager在启动的时候,都会去竞争写一个Lock子节点:/yarn-leader-election/appcluster-yarn/ActiveBreadCrumb
,该节点是临时节点。ZooKeepr能够为我们保证最终只有一个ResourceManager能够创建成功。创建成功的那个ResourceManager就切换为Active状态,没有成功的那些ResourceManager则切换为Standby状态。
[zk: localhost:2181(CONNECTED) 16] get /yarn-leader-election/appcluster-yarn/ActiveBreadCrumb
appcluster-yarnrm2
cZxid = 0x1b00133dc0
ctime = Tue Jan 03 15:44:42 CST 2017
mZxid = 0x1f00000540
mtime = Sat Jan 07 00:50:20 CST 2017
pZxid = 0x1b00133dc0
cversion = 0
dataVersion = 28
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 22
numChildren = 0
可以看到此时集群中ResourceManager2为Active。
-
注册Watcher监听
所有Standby状态的ResourceManager都会向/yarn-leader-election/appcluster-yarn/ActiveBreadCrumb
节点注册一个节点变更的Watcher监听,利用临时节点的特性,能够快速感知到Active状态的ResourceManager的运行情况。 -
主备切换
当Active状态的ResourceManager出现诸如宕机或重启的异常情况时,其在ZooKeeper上连接的客户端会话就会失效,因此/yarn-leader-election/appcluster-yarn/ActiveBreadCrumb
节点就会被删除。此时其余各个Standby状态的ResourceManager就都会接收到来自ZooKeeper服务端的Watcher事件通知,然后会重复进行步骤1的操作。
以上就是利用ZooKeeper来实现ResourceManager的主备切换的过程,实现了ResourceManager的HA。
HDFS中NameNode的HA的实现原理跟YARN中ResourceManager的HA的实现原理相同。其锁节点为/hadoop-ha/mycluster/ActiveBreadCrumb
。
十一、关于zookeeper集群自身高可用
- 如果一台服务器挂掉,集群中剩余的两台服务器仍然构成多数(即2/3),因此 Zookeeper 集群还能正常工作。集群将继续为客户端提供服务,并保持数据的一致性。
- 如果两台服务器同时挂掉,剩下的一台服务器无法构成多数(即1/3),因此 Zookeeper 集群将无法正常工作。
- 一般将节点(指leader及follower节点)个数设置为 2*n+1 ,n为可容忍宕机的个数
十二、zookeeper集群命令
1、服务管理命令:
- 启动Zookeeper服务:zkServer.sh start
- 注意:要所有节点都要执行./zkServer.sh start
- 启动服务端后,hadoop、kafka等就可以连接了
- 查看Zookeeper服务状态:zkServer.sh status,此命令可以显示服务器的角色(leader、follower等)。
- 停止Zookeeper服务:zkServer.sh stop
- 重启Zookeeper服务:zkServer.sh restart
2、客户端命令:
- 连接到Zookeeper服务器:zkCli.sh -server host:port
- 创建节点:create [-s] [-e] path data acl,其中-s表示顺序节点,-e表示临时节点。
- 查看节点内容:get path
- 设置节点内容:set path data
- 删除节点:delete path
- 递归删除节点:rmr path
- 查看子节点列表:ls path
- 查看节点状态:stat path
3、启动Zookeeper客户端:./zkCli.sh -server localhost:2181
- 启动客户端后可以进行相关的操作,如创建节点、读取节点数据、设置节点数据、删除节点等
- zkServer.sh start:这个命令用于启动 Zookeeper 服务端。Zookeeper 服务端是一个分布式协调服务,它管理配置信息、命名、提供分布式同步和组服务。启动服务端后,Zookeeper 可以接受客户端的连接,并提供服务。
- zkCli.sh -server localhost:2181:
- 这个命令用于启动 Zookeeper 客户端。Zookeeper 客户端是一个命令行工具,用于与 Zookeeper 服务端进行交互。通过客户端,你可以执行各种操作,如创建节点、读取节点数据、设置节点数据、删除节点等。-server localhost:2181 参数指定了客户端连接的服务端地址和端口。
十三、zookeeper客户端操作
查看zookeeper数据:
- 列出根节点下的所有子节点:ls /
- 查看节点/brokers/topics的数据:ls /brokers/topics
- 案例:
- 列出根节点下的所有子节点:
- [zk: localhost:2181(CONNECTED) 0] ls /
[admin, brokers, cluster, config, consumers, controller, controller_epoch, hadoop-ha, isr_change_notification, latest_producer_id_block, log_dir_event_notification, yarn-leader-election, zookeeper]
- 列出各个节点的数据:
- [zk: localhost:2181(CONNECTED) 6] ls /brokers/topics
[]
[zk: localhost:2181(CONNECTED) 7] ls /yarn-leader-election
[myYarnWyz]
[zk: localhost:2181(CONNECTED) 8] ls /hadoop-ha
[wyz]
[zk: localhost:2181(CONNECTED) 9] ls /hadoop-ha/wyz
[ActiveBreadCrumb, ActiveStandbyElectorLock]
[zk: localhost:2181(CONNECTED) 10] ls /hadoop-ha/wyz/ActiveBreadCrumb
[]
[zk: localhost:2181(CONNECTED) 11] ls /yarn-leader-election/myYarnWyz
[]
十四、Zab协议
1、什么是Zab协议?
Zab协议 的全称是 Zookeeper Atomic Broadcast (Zookeeper原子广播)。
Zab协议是为Zookeeper集群自身服务的,如选举Zookeeper集群中的一台作为leader;如将Mater的数据同步到其它Zookeeper服务器等。
Zookeeper 是通过 Zab 协议来保证分布式事务的最终一致性。
Zab协议是Zookeeper保证数据一致性的核心算法。Zab借鉴了Paxos算法,但又不像Paxos那样,是一种通用的分布式一致性算法。它是特别为Zookeeper设计的支持崩溃恢复的原子广播协议。 基于该协议,zk实现了一种主备模型(即Leader和Follower模型)的系统架构来保证集群中各个副本之间数据的一致性。
2、Zab 协议实现的作用
1、 当主进程出现异常的时候,整个zk集群依旧能正常工作。
2、保证分布式数据的一致性。
Zab协议内容
Zab 协议包括两种基本的模式:崩溃恢复 和 消息广播
- 崩溃恢复
崩溃恢复主要包括两部分:Leader选举 和 数据恢复
-
消息广播具体步骤
1)客户端发起一个写操作请求。
2)Leader 服务器将客户端的请求转化为事务 Proposal 提案,同时为每个 Proposal 分配一个全局的ID,即zxid。
3)Leader 服务器为每个 Follower 服务器分配一个单独的队列,然后将需要广播的 Proposal 依次放到队列中取,并且根据 FIFO 策略进行消息发送。
4)Follower 接收到 Proposal 后,会首先将其以事务日志的方式写入本地磁盘中,写入成功后向 Leader 反馈一个 Ack 响应消息。
5)Leader 接收到超过半数以上 Follower 的 Ack 响应消息后,即认为消息发送成功,可以发送 commit 消息。
6)Leader 向所有 Follower 广播 commit 消息,同时自身也会完成事务提交。Follower 接收到 commit 消息后,会将上一条事务提交。
zookeeper 采用 Zab 协议的核心,就是只要有一台服务器提交了 Proposal,就要确保所有的服务器最终都能正确提交 Proposal。这也是 CAP/BASE 实现最终一致性的一个体现。
Leader 服务器与每一个 Follower 服务器之间都维护了一个单独的 FIFO 消息队列进行收发消息,使用队列消息可以做到异步解耦。 Leader 和 Follower 之间只需要往队列中发消息即可。如果使用同步的方式会引起阻塞,性能要下降很多。
疑问
1、Follower事务处理失败了怎么办?zab如何保证数据一致性?
2、
参考: