zk基础—2.架构原理和使用场景

大纲

1.zk的使用场景

2.zk主要会被用于那些系统

3.为什么在分布式系统架构中需要使用zk集群

4.zk分布式系统具有哪些特点

5.zk集群机器的三种角色

6.客户端与zk之间的长连接和会话

7.zk的数据模型znode和节点类型

8.zk最核心的Watcher监听回调机制

9.ZAB协议的主从同步机制和崩溃恢复机制

10.ZAB协议流程之集群启动-数据同步-崩溃恢复

11.采用2PC两阶段提交思想的ZAB消息广播流程

12.zk到底是强一致性还是最终一致性

13.ZAB协议下两种可能存在的数据不一致问题

14.崩溃恢复时新Leader和Follower的数据同步

15.ZAB协议会如何处理需要丢弃的消息的

16.zk的Observer节点的作用

17.zk适合小集群部署 + 读多写少场景的原因

18.zk特性的总结

1.zk的使用场景

(1)分布式锁

(2)集群元数据管理

(3)分布式协调(HA)

(4)zk使用场景总结

Kafka里使用zk进行元数据管理、Master选举、分布式协调,Canal也一样使用zk进行元数据管理、Master选举(HA主备切换),HDFS的HA也是基于zk来做的。

(1)分布式锁

在分布式架构中的分布式锁,就有:Redis分布式锁和zk分布式锁。

(2)集群元数据管理

Kafka和Canal是在分布式集群中运行的分布式架构,都需要一个地方集中式地存储和管理分布式集群的核心元数据,所以它们都选择把分布式集群的核心元数据放在zk中。

(3)分布式协调(HA)

如果有客户端对zk中的数据做了变更,然后zk会通知其他监听这个数据的客户端数据发生变更了。

非常经典的几个分布式协调的场景:

一.Kafka

Kafka有多个Broker,多个Broker会竞争成为一个Controller的角色。如果作为Controller的Broker挂了,那么它在zk里注册的一个节点就会删除。然后其他Broker紧接着会被zk反向通知,继续竞争成为新的Controller。

二.HDFS

HDFS中NameNode的HA架构就部署主备两个NameNode,只有一个NameNode通过zk选举成为Master,另一个NameNode作为备份。

三.Canal

Canal的HA架构也是通过zk,确保一个节点挂掉后,可以通知其他备用节点进行切换,来保证HA。

(4)zk使用场景总结

zk封装了分布式架构中很多核心和主流的需求功能,比如很多分布式系统都需要分布式锁、集中式存储分布式集群的元数据、Master选举、分布式协调,这些功能需求都可以使用zk来实现。

2.zk主要会被用于那些系统

(1)分布式Java业务系统

(2)开源的分布式系统

(3)自研的分布式系统

(1)分布式Java业务系统

比如分布式电商平台、Java开发的互联网平台、或者是传统架构系统,都属于分布式Java业务系统。

这些系统大部分依赖Dubbo、Spring Cloud来对系统进行拆分,拆分成很多服务或子系统后,再相互协调工作来完成最终的功能。

但zk在这类Java业务系统中用得是比较少的,zk在这类Java业务系统中用得比较多的功能也只是分布式锁,即便是分布式锁的功能很多时候也会选择使用Redis分布式锁。

(2)开源的分布式系统

比如Dubbo、HBase、HDFS、Kafka、Canal、Storm、Solr,主要使用zk进行:集中式存储分布式集群的元数据、Master选举实现HA架构、分布式协调和通知。

复制代码
Dubbo:使用zk作为注册中心 + 集中式存储分布式集群的元数据;
HBase:使用zk进行集中式存储分布式集群的元数据;
HDFS:使用zk进行Master选举实现HA架构;
Kafka:使用zk进行集中式存储分布式集群的元数据,分布式协调和通知;
Canal:使用zk进行集中式存储分布式集群的元数据,Master选举实现HA;

Canal、Kafka、HDFS等这些技术都用了zk进行元数据管理和Master选举。

(3)自研的分布式系统

在很多自研类似的一些分布式系统,都可能会考虑:是否需要一个地方集中式存储分布式集群的元数据?是否需要一个组件辅助进行Master选举来实现HA架构?是否需要进行分布式协调和通知?

如果在自研分布式系统时,有类似这样的需求,那么就可以考虑引入zk来满足该需求。

3.为什么在分布式系统架构中需要使用zk集群

(1)自研一个类似zk的系统

(2)使用zk集群

当需要对分布式集群进行:集中式存储元数据、Master选举实现HA、分布式协调和通知时,可以自研一个类似zk的系统,也可以使用zk集群。

(1)自研一个类似zk的系统

如果是单机版本,只部署在一台机器上,里面提供了一些功能。虽然已实现存储一些元数据、支持Master选举、支持分布式协调和通知。但是对于单机版本的系统,万一挂掉了怎么办?

所以需要集群部署,通过多台机器保证高可用,即便挂掉一台机器,都可以继续运行下去。

假设现在有3台机器,要进行元数据的存储。已经向机器1写了一条数据,那么机器1应该怎么把数据同步给其他的机器?所以自研一个类似的zk系统一旦集群部署后,数据一致性应该怎么保证?

(2)使用zk集群

久经考验的zk,bug很少且功能全面,已用在很多工业级的分布式系统中,所以直接使用zk集群即可。

4.zk分布式系统具有哪些特点

(1)集群化部署

(2)树形结构的数据模型

(3)顺序写

(4)数据一致性

(5)高性能

(6)高可用

(7)高并发

(1)集群化部署

3~5台机器组成一个集群,每台机器都在内存保存zk的全部数据。机器间互相通信同步数据,客户端可连接任何一台机器。

(2)树形结构的数据模型

znode的数据结构跟文件系统类似,是有层级关系的树形数据结构。znode的数据结构是树形结构,纯内存保存,znode可以认为是一个节点而已。

lua 复制代码
create /usr/local/uid
create /usr/local/test_file

uid:可以写入一些数据的值,比如hello world
test_file:也可以写入一些数据的值

(3)顺序写

集群中只有一台机器可以写,所有机器都可以读。所有写请求都会分配一个zk集群全局的唯一递增编号ZXID,ZXID的作用就是用来保证客户端发起的写请求都是有顺序的。

(4)数据一致性

任何一台zk机器收到了写请求后都会同步给其他机器,保证数据一致。客户端连接到任何一台zk机器看到的数据都是一致的。

(5)高性能

每台zk机器都在内存维护数据,所以zk集群绝对是高并发高性能的。如果让zk部署在高配置机器上,3台机器的zk集群能抗下每秒几万请求。

(6)高可用

哪怕集群中挂掉不超过一半的机器,都能保证集群可用,数据不会丢失。3台机器可以挂1台,5台机器可以挂2台。

(7)高并发

高并发是由高性能决定的,只要基于纯内存数据结构来处理,那么并发能力是很高的。使用高配置的物理机器进行写,比如1台16核32G可以支持几万QPS,3台16核32G可以支持十几万QPS。

5.zk集群机器的三种角色

通常来说zk集群里有三种角色的机器,分别是Leader、Follower、Observer。集群启动后会自动选举一个Leader出来,只有Leader可以写,Follower只能同步数据和提供数据的读取。如果Leader挂了,那么Follower会继续选举出新的Leader。Observer只能读,而且Observer不参与选举。

6.客户端与zk之间的长连接和会话

zk集群启动后,集群中的各个节点会自己分配好角色。之后客户端跟zk集群建立的连接,是TCP长连接。也就建立了一个会话Session,会通过心跳来感知会话是否存在。

7.zk的数据模型znode和节点类型

zk的核心数据模型就是znode树,往zk写数据就是创建树形结构的znode,里面可以写入值,存放在zk的内存中。

有两种节点:持久节点和临时节点。持久节点,就是哪怕客户端断开连接,也一直存在。临时节点,就是只要客户端断开连接,节点就没了。

顺序节点,就是创建节点时自增加全局递增的编号。

Curator中关于zk分布式锁的实现就是基于zk的临时顺序节点来实现的,加锁时会创建一个临时顺序节点。zk会自动给临时节点加上一个后缀,也就是全局递增的一个编号。如果客户端断开连接,就自动销毁这个客户端加的锁,此时其他客户端就会感知到而尝试去加锁。

如果进行元数据存储,则需要使用持久节点。如果进行分布式协调和通知,则通常使用临时节点。如果实现分布式锁,则通常使用临时顺序节点。

每个znode还有一个Stat用来存放数据版本:

scss 复制代码
一.version(znode的版本)
二.cversion(znode子节点的版本)
三.aversion(znode的ACL权限控制版本)

8.zk最核心的Watcher监听回调机制

zk最核心的机制是:一个客户端可以对znode进行Watcher监听,当znode发生改变时zk会回调该客户端进行通知。

这是非常有用的一个功能,在分布式系统的协调中是非常有必要的。如果zk只支持写和读,那只能实现元数据存储、Master选举和部分功能,对于分布式系统的协调需求就没办法实现了。如系统A监听一个数据的变化,如果系统B更新了该数据,zk需要能通知系统A该数据的变化。

通过对zk内存数据模型(不同节点类型)进行这两种操作:写数据和读数据、监听数据变化(更新数据时反向通知数据变化),就可以实现:存储集群元数据、分布式锁、Master选举、分布式协调监听等功能;

9.ZAB协议的主从同步机制和崩溃恢复机制

ZAB协议使用的是主从架构,需要划分集群角色,有Leader和Follower两种角色。其中Leader和Follower都可以处理读请求,但只有Leader可以处理写请求。

Leader收到事务请求后,会往本地磁盘日志文件写数据,然后转换为Proposal提议并同步给所有的Follower。Follower收到Leader的Proposal提议后,也会往本地磁盘日志文件写数据。

当Leader发现超过半数Follower都收到Proposal提议时,Leader会给所有Follower发送Commit消息提交事务写数据到内存。

如果Leader崩溃了,Follower会重新选举新的Leader保证服务运行。

所以ZAB协议涉及:角色划分、2PC(两阶段)、过半写机制。

10.ZAB协议流程之集群启动-数据同步-崩溃恢复

(1)zk集群启动时会进入数据恢复模式

(2)zk启动完后会进入消息广播模式

(3)Leader宕机时会进入数据恢复模式

(1)zk集群启动时会进入数据恢复模式

集群启动时会选举一个Leader。只要有过半机器认可某台机器是Leader,那么该机器就可以被选举为Leader。

Leader选举出来后,Leader会等待集群中过半Follower与它进行数据同步。只要过半Follower完成数据同步,集群就会退出恢复模式,就可以对外提供服务。当然还没完成数据同步的Follower会继续与Leader进行数据同步。

(2)zk启动完后会进入消息广播模式

客户端既可以连接Leader,也可以连接Follower,但要注意只有Leader可以处理写请求。

如果客户端发送了一个写请求给Follower,那么Follower会把写请求转发给Leader。Leader收到写请求后,会把写请求以Proposal提议的形式同步给所有Follower。过半Follower都收到Proposal后,Leader再发送Commit消息让Follower提交写请求。

(3)Leader宕机时会进入数据恢复模式

当Leader宕机时,Follower会重新选举一个Leader。只要过半Follower都承认一个Follower成为Leader,那么就可以完成选举。

所以在zk集群中,只要宕机的机器数小于一半,那么集群就还可以正常工作。因为还有过半机器存活下来进行重新选举,此时还可以重新选举出新的Leader。新的Leader选举出来后再重新等待过半Follower跟它进行数据同步,过半Follower完成数据同步后集群就会重新进入消息广播模式。

(4)总结

一.集群启动时的数据恢复模式

Leader选举(过半机器选举机制) + (剩余机器)进行数据同步。

二.消息写入时的消息广播模式

Leader采用2PC模式的过半写机制,来给Follower进行同步。

三.Leader宕机时的数据恢复模式

Leader宕机时,只要剩余存活机器超过一半,那么就还可以选举出新的Leader。选举出新的Leader后,Follower会重新进行数据同步。

11.采用2PC两阶段提交思想的ZAB消息广播流程

(1)Leader发起一个事务Proposal之前

(2)每个Follower收到一个事务Proposal后

(3)Leader自己也会进行Commit操作

对每一条消息进行广播时,都是通过2PC实现的。首先Leader广播Proposal提议,然后各个Follower返回ACK响应,Leader收到过半Follower的ACK响应后再广播Commit消息让Follower进行提交。

(1)Leader发起一个事务Proposal之前

Leader会分配一个全局唯一递增的ZXID来严格保证事务处理的顺序,而且Leader会为每个Follower创建一个FIFO队列。队列里会顺序放入发送给Follower的Proposal,从而保证事务处理的顺序。

(2)每个Follower收到一个事务Proposal后

Follower会立即写入本地磁盘日志,写入成功后就可以保证数据不丢失。然后Follower会返回一个ACK给Leader,当过半Follower都返回ACK时,Leader就会发送Commit消息给全部Follower。

(3)Leader自己也会进行Commit操作

Leader和Follower进行Commit之后,就意味这个数据可以被读取到了。

12.zk到底是强一致性还是最终一致性

(1)强一致性

(2)最终一致性

(3)顺序一致性

(1)强一致性

只要写入一条数据,无论从zk哪台机器上都可以马上读取到这条数据。强一致性的写入操作卡住时,直到Leader和全部Follower都进行了Commit,才能让写入操作返回,才能认为写入成功。所以只要写入成功,无论从哪个zk机器查询都能查到,这就是强一致性。很明显,ZAB协议机制下的zk不是强一致性。

(2)最终一致性

写入一条数据,方法返回写入成功。此时马上去其他zk机器上查有可能是查不到的,可能会出现短暂时间的数据不一致。但是过一会儿,一定会让其他机器同步到这条数据,最终一定可以查到写入的数据。

在ZAB协议中:当过半Follower对Proposal提议返回ACK时,Leader就会发送Commit消息给所有Follower。只要Follower或者Leader进行了Commit,那么这个数据就会被客户端读取到。

那么就有可能出现:有的Follower已经Commit了,但有的Follower还没有Commit。某个客户端连接到某个Follower时可以读取到刚刚Commit的数据,但有的客户端连接到另一个Follower时却没法读取到还没有Commit的数据。

所以zk不是强一致性的。Leader不会保证一条数据被全部Follower都Commit后,才让客户端读取到。在Commit的过程中,可能会出现在不同的Follower上读取到的数据是不一致的情况。但完成Commit后,最终一定会让客户端读取到一致的数据。

(3)顺序一致性

zk官方给自己的定义是顺序一致性,当然也属于最终一致性。但zk的顺序一致性比最终一致性更好一点,因为Leader会保证所有的Proposal提议同步到Follower时是按顺序进行同步的。

如果要求zk是强一致性,那么可以手动调用zk的sync()方法。

13.ZAB协议下两种可能存在的数据不一致问题

(1)Leader还没发送Commit消息就崩溃

(2)Leader还没广播Proposal提议就崩溃

(1)Leader还没发送Commit消息就崩溃

Leader收到了过半的Follower的ACK,接着Leader自己Commit了,但还没来得及发送Commit消息给所有Follower自己却宕机了。此时相当于Leader的数据跟所有Follower是不一致的,所以得保证全部Follower最终都完成Commit。

因此Leader崩溃后,就会选举一个拥有最大ZXID的Follower作为Leader,这个Leader会检查事务日志。如果发现自己事务日志里有一个还没进行提交的Proposal提议,那么旧说明旧Leader没来得及发送Commit消息就崩溃了。此时它作为新Leader会为这个Proposal提议向Follower发送Commit消息,从而保证旧Leader提交的事务最终可以被提交到所有Follower中。

同理,如果Leader收到过半Follower的ACK响应后,在发送Commit消息的过程中,出现Leader宕机或者Leader和Follower的网络问题。那么Follower只要与它能找到的Leader(新选举的ZXID最大的Follower或者原来的Leader)进行数据同步,就可以保证新数据在该Follower中完成Commit。

(2)Leader还没广播Proposal提议就崩溃

Leader没来得及发送Proposal提议给所有Follower的时候就宕机了,此时Leader上的这个请求应该是要被丢弃的。

对于这种情况:如果旧Leader日志里有一个事务Proposal提议,它重启后跟新Leader同步,发现这个事务Proposal提议其实是不应该存在的,那么就会直接丢弃。

14.崩溃恢复时新Leader和Follower的数据同步

(1)先发送Proposal提议再发送Commit消息

(2)Commit操作会把数据写入到内存中的znode

(3)通过已同步Follower列表判断数据可用

(4)选择ZXID最大的Follower作为新Leader的原因

(1)先发送Proposal提议再发送Commit消息

新选举出一个Leader后,其他Follower就会跟它进行数据同步。Leader会给每个Follower准备一个队列,然后把所有的Proposal提议都发送给Follower,并紧接着会发送Commit消息给那个Follower。

(2)Commit操作会把数据写入到内存中的znode

Commit操作就是把这条数据加入内存中的znode树形数据结构里,这样客户端就能访问到该数据,当然也会去通知监听这个znode的客户端。而收到Proposal提议时,会将数据以事务日志的形式顺序写入到磁盘。

(3)通过已同步Follower列表判断数据可用

如果一个Follower跟新Leader完成数据同步后,就会加入新Leader的已同步Follower列表中。当这个已同步Follower列表中有过半的Follower时,那么新Leader就可以对外继续提供服务了。

(4)选择ZXID最大的Follower作为新Leader的原因

在选举新Leader时,会挑选拥有最大ZXID的那个Follower作为新Leader。比如5个机器,1Leader + 4个Follower。1个Leader把Proposal发送给4个Follower,其中3个Follower(过半)都收到了Proposal返回ACK了,但是第四个Follower没收到Proposal。此时Leader执行Commit后挂了,Commit消息没法发送给其他Follower。这时剩余4个Follower,只要其中3个投票某一个当Leader,那它就可成为Leader。假设收到Proposal的那3个Follower都投票给没收到Proposal的Follower,那么这条数据就会永久丢失,所以需要选择一个拥有最大ZXID的Follower作为新Leader。

15.ZAB协议会如何处理需要丢弃的消息的

(1)ZAB协议根据epoch处理需要丢弃的消息

(2)ZAB协议的简单总结

(1)ZAB协议根据epoch处理需要丢弃的消息

每一个事务的ZXID是64位的,高32位是Leader的epoch(表示选举轮次),低32位是自增长的序列号。

如果一个Leader刚把一个Proposal提议写入本地磁盘日志,还没来得及广播Proposal提议给全部Follower就崩溃了。那么当新Leader选举出来后,事务的epoch会自增长一位。然后当旧Leader重启后重新加入集群成为Follower时,会发现自己比新Leader多出一条Proposal提议,但该Proposal提议的epoch比新Leader的epoch低,所以会丢弃这条数据。

(2)ZAB协议的简单总结

一.启动时:过半机器选举Leader + 数据同步

二.对外提供服务时:2PC + 过半写机制,顺序一致性(最终一致性)

三.崩溃恢复时:重新选举Leader + 针对两种数据不一致的情况进行处理

16.zk的Observer节点的作用

(1)对于写请求

(2)对于读请求

Observer节点不参与Leader选举,不参与广播提议时过半Follower进行ACK的环节,只处理客户端读请求和同步数据。

(1)对于写请求

由于Leader在进行数据同步时,Observer不会参与到过半写机制里。所以zk集群无论多少台机器,只能是由一个Leader进行写。Leader单机写入最多每秒上万QPS,这是没法扩展的。

因此zk是适合写少的场景。Redis的写QPS可以达10万,zk的写QPS才上万。虽然Redis和zk都是内存级的,而且对写请求的处理都是单线程处理的。但是由于Redis没有过半写机制,所以它的写性能更高。

(2)对于读请求

Follower通常会有2个或4个,这样处理读请求时就可以达到每秒几万QPS。如果引入更多的Follower,那么在过半写机制中会有更多的Follower参与。这会影响Leader写的效率,因此就有了Observer。

所以为了进一步提升zk集群对读请求的处理能力,可以引入Observer节点。由于它只同步数据提供读服务,所以可以无限扩展节点而不影响写效率。

17.zk适合小集群部署 + 读多写少场景的原因

(1)zk集群通常采用三五台机器小集群部署

(2)zk集群适合读多写少的场景

(1)zk集群通常采用三五台机器小集群部署

假设有1个Leader + 20个Follower,总共21台机器。此时由于Follower要参与到ZAB的写请求的过半ACK,所以一个写请求要等至少10个Follower返回ACK才能发送Commit消息。Leader发送Commit消息后才能告诉客户端写请求成功,所以性能会比较差。所以ZAB协议决定了zk集群通常采用1个Leader + 2个Follower的小集群。

(2)zk集群适合读多写少的场景

zk集群的写请求的处理能力是无法扩展的。如果读请求量大,可以加Observer机器。因此zk只适合读多写少的场景,所以zk主要是用来处理分布式系统的一些协调工作。

18.zk特性的总结

(1)集群模式部署

(2)主从架构

(3)内存数据模型

(4)顺序一致性

(5)高性能

(6)高可用

(7)高并发

(1)集群模式部署

一般奇数节点部署,不能超过一半的机器挂掉。因为5台机器可以挂2台,6台机器也最多只能挂2台。所以5台和6台效果一致,所以奇数节点可以减少机器开销。而且zk集群是小集群部署,适用于读多写少的场景。

(2)主从架构

Leader、Follower、Observer。

(3)内存数据模型

znode,多种节点类型,支持Watcher机制实现监听回调通知。

(4)顺序一致性

消息按顺序同步,但是最终才会一致,不是强一致。ZXID的高32位epoch,低32位是自增长的序列号。

(5)高性能

2PC中的过半写机制,纯内存的数据结构,znode。ZAB协议:2PC、过半ACK + 写事务日志,Commit + 写内存数据。

(6)高可用

Follower宕机没影响,Leader宕机有数据不一致问题。新选举的Leader会自动处理,正常运行。但是在恢复模式期间,可能有一小段时间是没法写入zk的。客户端跟zk进行TCP长连接,通过心跳机制维持Session。

(7)高并发

单机Leader写,Observer节点可以线性扩展读QPS。

相关推荐
东阳马生架构9 小时前
zk基础—3.集群与核心参数
zookeeper
纪元A梦10 小时前
分布式锁算法——基于ZooKeeper的分布式锁全面解析
java·分布式·算法·zookeeper
拾荒的小海螺10 小时前
JAVA:使用 Curator 进行 ZooKeeper 操作的技术指南
java·zookeeper·java-zookeeper
东阳马生架构1 天前
zk基础—1.一致性原理和算法二
zookeeper·分布式原理
Julian.zhou2 天前
MCP服务:五分钟实现微服务治理革命,无缝整合Nacos/Zookeeper/OpenResty
人工智能·微服务·zookeeper·交互·openresty
千航@abc2 天前
zookeeper的作用介绍
分布式·zookeeper·云原生·云原生组件
东阳马生架构2 天前
zk基础—1.一致性原理和算法
zookeeper