当前位置: 首页 > 科技观察

Zookeeper基本原理&应用场景详解

时间:2023-03-17 21:55:28 科技观察

简单了解ZookeeperTips:如果你之前对Zookeeper不了解,在这里留下个印象就好了Zookeeper是一个分布式协调服务,可以用于元数据管理和分布式锁、分布式协调、发布-订阅、服务命名等等。例如在Kafka中,Zookeeper用于保存其集群中的相关元数据,如Broker、Topic、Partition等。同时基于Zookeeper的Watch监控机制,也可以用来实现发布和订阅的功能。在正常的业务使用场景中,我们几乎只为了一个目的使用分布式锁。Zookeeper的内部运行机制Zookeeper的底层存储原理有点类似于Linux中的文件系统。Zookeeper中文件系统中的每个文件都是一个节点(Znode)。根据文件之间的层次关系,Zookeeper内部会形成这样一个文件树。在Linux中,文件(节点)其实是有类型划分的,比如文件和目录。与Zookeeper中的方式相同,Znode也有类型。在Zookeeper中,所有的节点类型如下:持久节点(Persistent)持久顺序节点(PersistentSequential)临时节点(Ephemeral)临时顺序节点(EphemeralSequential)电脑。除非你主动删除它,否则它会一直存在。持久时序节点除了继承持久节点的特性外,还会保证其下创建的子节点的顺序,并会自动为节点添加一个10位的自增序号作为节点名称,以保证其唯一性节点名称。上图中的子文件已经给出了一个例子。对于临时节点,其生命周期与客户端的连接是否活跃有关。如果客户端断开连接,节点(可以理解为文件)将被删除,临时节点不能创建子节点;PS:这里的断线其实并不是我们直观理解的断线。Zookeeper有它的Session机制。当一个客户端的Session过期时,对应客户端创建的所有节点都会被删除。Zookeeper的节点创建方式接下来我们看一下几种方式节点是如何创建的,举几个简单的例子。创建持久化节点的全栈注意create/node_nameSH这里需要注意的是,命令中的所有节点名必须以/开头,否则会创建失败,因为Zookeeper中不能使用相对路径,必须是绝对路径用过的。为持久化时序节点create-s/node_nameSH创建全栈笔记。可以看到Zookeeper自动给key添加了一个10位的自增后缀。创建临时节点的全栈笔记create-e/testSH创建临时顺序节点的全栈笔记create-e-s/node_nameSHZookeeper的使用我们通过一些具体的例子来了解Zookeeper的详细使用,就是不只是作为分配型锁使用。元数据管理我们都知道Kafka在运行时会依赖一个Zookeeper集群。Kafka通过Zookeeper管理集群的相关元数据,并通过Zookeeper进行Leader选举。Tips:但是在即将到来的Kafka2.8版本中,Zookeeper不再是必须的组件。我现在还没有时间仔细研究这个,但我猜它可能类似于RocketMQ的处理方式,将其集群元数据放入Kafka本身进行处理。分布式锁基于Zookeeper的分布式锁的过程其实很简单。首先我们要知道加分布式锁的本质是什么?答案是创建一个临时顺序节点。当一个客户端成功加锁时,实际上是在Zookeeper上成功创建了一个临时的顺序节点。我们知道,分布式锁可以让一个资源一次只能访问一个资源。那么这就必然涉及到分布式锁的竞争,那么问题来了,当前客户端如何感知自己抢到了锁呢?其实客户端会有一定的逻辑,假设锁定的key是/locks/modify_users。首先客户端会发起一个锁请求,然后在Zookeeper上创建持久节点锁,然后在这个节点下创建临时的时序节点。创建临时序列节点的示例如下图所示。当客户端成功创建一个节点时,它也会得到它对等体的所有节点。即上图中的所有modify_users000000000x节点。此时客户端会根据这个10位自增序号判断自己当前创建的节点是否是所有节点中最小的,如果是最小的则说明自己获取到了分布式锁。你可能会问,我不是最小的又怎样?我的节点已经创建好了。如果不是最小的,说明当前client还没有抢到锁。按照我们的理解,如果没有分布式锁的竞争,它就会等待。底层等待是做什么的?让我们用实际的例子来复习一下。假设Zookeeper中已经存在以下节点。比如当前客户端B创建的节点是modify_users0000000002,那么很明显B并没有抢到锁,因为客户端A已经创建了一个更小的节点modify_users0000000001,此时客户端B会注册一个监听器节点modify_users0000000001,该节点的任何更新都会触发相应的操作。删除后会唤醒客户端B的线程,此时客户端B会判断是否是序号最小的节点。此时modify_users0000000002显然是最小的节点,所以客户端B加锁成功。为了让大家更直观的理解这个过程,我把这个过程浓缩成了下面的流程图。我们都知道在分布式协调中,很多场景为了保证一致性,都会用到经典的2PC(two-phasecommit)。比如MySQL中RedoLog和Binlog提交的数据一致性保证是2PC。详见基于RedoLog和UndoLog的MySQL崩溃恢复过程。2PC中有两个角色,即Participant和Coordinator。Coordinator负责统一调度所有分布式节点的执行逻辑。具体协调是什么?例如。比如2PC的Commit阶段,有两个参与者A和B,A的commit操作成功了,可惜B失败了。这时候协调者需要向A发送一个Rollback操作,Zookeeper大概就是这样一个角色。发布订阅由于Zookeeper自带监听器(Watch)功能,所以发布订阅自然而然的成为了Zookeeper的应用之一。比如在某个配置节点上注册了监听器,一旦配置发生变化,相应的服务就可以实时感知到配置的变化,从而达到动态更新配置的目的。举一个使用Watch的简单例子。命名服务通俗地说,有两种主要类型的命名服务。只需使用Zookeeper的文件系统功能来存储结构化文件。使用文件特征和顺序节点特征生成全局唯一标识符。前者可以用来在系统之间共享某些业务特定的资源,后者可以用来实现分布式锁。