ZooKeeper架构原理你学会了吗?

Zookeeper是分布式一致性问题的工业解决方案,是Apache Hadoop下解决分布式一致性的一个组件,后被分离出来成为Apache的顶级项目。java

工程来源:是雅虎公司内部项目,听说雅虎内部不少项目都是以动物命名,这个动物管理员的名字起的非常形象。node

被开源出来后获得开源社区的快速推动,服务端Java语言实现,棒,git有3000+的star:linux

https://github.com/apache/zookeeperandroid

ZooKeeper架构原理你学会了吗?

 

zookeeper集群结构

集群的角色,比较典型的是Master/Slave(主备模式),zk中的概念跟这个不同,包含Leader、Follower、Observer三个角色,leader提供读和写的能力,follower只对外提供读的能力。git

会话(session)

客户端跟服务端交互,是先与服务端创建一个TCP长链接,会话开始,经过心跳检测与服务端保持会话有效,向服务端发送请求和接收响应。github

zk将全部的数据都加载在内存一份,同时有事务日志文件(持久化文件),服务端会定时dump快照数据,重启机器的时候会根据快照和事务日志恢复内存数据库的数据,这跟redis的AOF和RDB概念相似。redis

zookeeper上的数据结构

zk上的数据的结构跟linux文件系统很像,是个树状结构算法

ZooKeeper架构原理你学会了吗?

 

 

节点(node)上的信息字段

ZooKeeper架构原理你学会了吗?

 

 

节点类型包括:数据库

  • 持久型节点
  • 顺序持久型节点
  • 临时节点
  • 顺序临时节点

 

其中临时节点特性就是建立它的主体消失后,它就跟着消失了。后续的应用就是利用的节点的特性实现的。apache

事件监听器(watcher)

这个应该是zookeeper最重要的概念之一了,zk容许用户在特定的节点(znode)上注册watcher,而且在特定事件触发的时候,zk服务端会将事件通知到感兴趣的客户端上。

伪集群的搭建:

ZooKeeper架构原理你学会了吗?

 

 

zoo.cfg 配置文件

  • 拷贝三份文件
  • 修改配置zoo.cfg,区别出日志目录和端口号,dataDir文件下添加表示机器号的文件myid
  • 集群配置列表,第一个端口是机器间业务通信的端口,第二个端口是用来进行leader选举的端口
  • 分别启动三台服务器

启动成功后,命令行链接zk,能够用指令作些增删改查的操做

telnet 127.0.0.1 2181

stat:能够看集群的状态信息

ZooKeeper架构原理你学会了吗?

 

 

stat信息

每次事务操做,会在dataDir的目录下的事务日志,是序列化的二进制文件,zookeeper提供了查看事务日志的工具类LogFormatter

ZooKeeper架构原理你学会了吗?

 

 

LogFormatter转换后的事务日志文件

Java客户端使用

  1. zookeeper自带的
  2. 开源的客户端ZkClient,实现session超时重连,watcher反复注册的功能,简化开发人员的使用
  3. 开源客户端Crurator,解决底层的细节开发工做,目前是apache的顶级项目,是使用最普遍的zk客户端。
  4. 提供了可读性更新的api接口
  5. 提供了各类应用场景的抽象封装(共享锁服务、Master选举机制,分布式计数器等)
  6. guava is to java what cruator is to zookeeper

 

ZooKeeper架构原理你学会了吗?

 

 

cruator客户端例子

zookeeper应用场景

利用zookeeper的特性,能够比较方便的构建分布式应用会涉及的核心功能,好比:配置中心、命名服务、分布式协调/通知、集群的管理、master选举、分布式锁等

如下应用基本基于zookeeper的两大特性实现

  • 客户端若是对zookeeper的一个数据节点注册watcher监听,那么当该数据节点的内容或其子节点的列表发生变动是,zookeeper服务器就会想订阅的客户端发送变动通知
  • 对在zookeeper上建立的临时节点(sequent类型),一旦客户端与服务器之间的回话失效,那么临时节点会被自动清除

 

配置中心

ZooKeeper架构原理你学会了吗?

 

 

配置中心

zookeeper利用推拉结合的方式,客户端向服务端注册本身须要关注的节点,一旦该数据发生变动,那么服务器就会向相应的客户端发送watcher时间通知。

客户收到这个消息通知以后,再主动到服务端获取最新的数据。即回调的event中包含具体的数据。

这个应用的的业务员特色:

  1. 数据不常常变化
  2. 数据量一般比较小,保存的内存里,访问很快
  3. 配置动态变化,不须要重启机器,数据变化,会通知相应的客户端
  4. 集群共享配置一致,好比数据库链接的配置,业务的开关,甚至一些数据量小,不常常变的业务数据如弹窗文案,活动文案也放里边,用于快速迭代实现功能。

 

命名服务

利用zookeeper的顺序节点,树形结构的数据特色,实现命名服务:

  • 好比RPC框架中,每一个服务在zookeeper中对应一个节点(serviceName),节点下存放这个服务所用到的资源,好比部署的ip列表,接口列表

 

这样RPC的客户端只须要传对应的服务名字,和接口,就能找到对应的服务。

  • 全局惟一id的生成,UUID(通用的惟一标识码)能够实现,可是他的缺点是:太长,包含32位字符和4个短线字符串;看不出业务含义,不方便排查问题。

使用zookeeper实现:不一样的业务下建立一个节点,具体的节点下用zk的顺序节点(sequent)生成id当作这个业务的全局惟一id使用

分布式通知/协调

ZooKeeper中特有watcher注册与异步通知机制,可以很好的实现分布式环境下不一样系统之间的通知与协调,实现对数据变动的实时处理。

使用方法一般是不一样系统都对ZK上同一个znode进行注册,监听znode的变化(包括znode自己内容及子节点的),其中一个系统update了znode,那么另外一个系统可以收到通知,并做出相应处理。

应用:

心跳检测机制:传统的方式是ping,复杂的话是创建长链接检测系统和被检测系统之间并不直接关联起来,而是经过zookeeper上某个节点关联,大大减小系统耦合

系统调度模式:某系统由控制台和推送系统两部分组成,控制台的职责是控制推送系统进行相应的推送工做。

管理人员在控制台做的一些操做,其实是修改了ZK上某些节点的状态,而ZK就把这些变化通知给他们注册Watcher的客户端,即推送系统。因而,做出相应的推送任务

做汇报模式:一些相似于任务分发系统,子任务启动后,到ZK来注册一个临时节点,而且定时将本身的进度进行汇报(将进度写回这个临时节点)

总之,使用zookeeper来进行分布式通知和协调可以大大下降系统之间的耦合。

分布式锁

这个应用主要得益于ZooKeeper为咱们保证了数据的强一致性

即用户只要彻底相信每时每刻,zk集群中任意节点(一个zk server)上的相同znode的数据是必定是相同的。

一个节点要么建立成功,要么失败,而且只由一个客户端建立。

独占锁:

保持独占,就是全部试图来获取这个锁的客户端,最终只有一个能够成功得到这把锁。

一般的作法是把ZK上的一个znode看做是一把锁,经过create znode的方式来实现。全部客户端都去建立/distribute_lock节点,最终成功建立的那个客户端也即拥有了这把锁。

共享时序控制锁:

Zookeeper很容易实现这个功能,实现方式是须要得到锁的Server,建立一个EPHEMERAL_SEQUENTIAL目录节点。

而后调用getChildren方法获取当前的目录节点列表中最小的目录节点是否是就是本身建立的目录节点。

若是正是本身建立的,那么它就得到了这个锁,若是不是,那么它就调用exists(String path, boolean watch)方法,并监控Zookeeper上目录节点列表的变化,一直到本身建立的节点是列表中最小编号的目录节点,从而得到锁。

释放锁很简单,只要删除前面它本身所建立的目录节点就好了。

master选举

ZooKeeper架构原理你学会了吗?

 

 

master选举应用图

 

有个容易理解的方案,依靠关系型数据库主键的特性,集群的机器同时往一张表里插入数据,数据库会自动进行主键冲突检查,能够选择插入成功的客户端做为master

这种方式存在一个问题就是,master机器挂了,没有人通知

zk实现能够方便作到这一点:zk的建立节点api接口,具备强一致性,可以保证客户端并发建立的时候,最终必定只有一个客户端建立成功。

  • 客户端集群天天定时往/master_election/(当天日期)2017-03-24/binding创 建临时节点,只有一个成功,为master
  • 建立失败的在/master_election/(当天日期)2017-03-24 注册监听事件,当master挂了,其他机器收到通知,从新进行选举

 

集群管理

应用举例:集群机器存活性监控系统,例如:

监控系统在/clusterServers节点注册一个watcher监听,那么但凡进行动态添加机器的操做,就在/clusterServers下建立一个临时节点, /clusterServers/ip。

这样监控系统就可以实时的检测到机器的变更,经过getChild方法获取全部的临时节点,来判断增长的机器。

当有机器down调或者手动下线,相应临时节点会消失,监控系统也会接收到,来处理监控服务的具体业务

具体服务器部署agent实现

zookeeper的HA设计实现

以上说了那么多犀利实用的应用场景,它们依赖zookeeper,说明这些应用服务的高可用性依赖的zookeeper自己的HA。

zk的选举算法

算法协议zab协议,“少数服从多数”协议一种

3.4.0版本以后Zookeeper只保留了TCP版本的FastLeaderElection选举算法

分析选举算法前,先熟悉了解下zk的一些术语定义解释:

  • SID:服务器ID,在集群的配置文件里配置
  • ZXID:是一个事务ID,用来惟一标示一次服务器状态变动,集群中每台机器上的ZXID可能不同
  • Vote:投票选举,当集群中机器发现本身没法检测到leader的时候,开始尝试进行投票
  • Quorum:过半机器数, quorum=(集群机器数)n/2+1,好比集群数量是3, quorum=2

集群数量是4,quorum=2,集群数量是5,quorum=3

 

当哪些状况发生时会出发leader从新选举呢?

当zk的一台服务器出现如下两种状况的时候,会进入leader选举流程

  1. 加机器,服务器初始化
  2. 服务器运行期间没法和leader通讯,leader所在服务器down掉了

 

对于第一种状况,即已经存在一台leader服务器,当改机器试图去选举leader的时候,会被告知当前服务器的leader信息,对于该机器仅仅须要和leader创建链接,并进行状态同步便可

主要看下第二种状况:

有两种状况致使集群不存在leader,一个是集群刚启动初始化的时候,另外一种状况是运行期间leader所在服务器挂了。

不管哪一种状况集群全部集群都处在一个找leader的状态,称做Looking状态,开始想其余机器发送消息投票

开始leader选举投票的协议规则是怎样呢?

  • 投票的消息包含(SID,ZXID)
  • 一开始试图投本身,把投票消息广播出去
  • 先比较ZXID,选择ZXID大的
  • ZXID相等的,比较SID,选择SID大的
  • 若是本身的值大于别的服务器广播来的消息,投票不作变动
  • 反正,更换投票,开始第二轮投票,广播出去投票信息
  • 每轮结束统计投票,若是一台服务器收到超过半数的相同投票,那个这个服务器对用的SID机器为Leader

 

ZooKeeper架构原理你学会了吗?

 

 

5台机器宕机两台后,leader选举的过程图示

 

所以,一个错误的认识,为了使zookeeper集群能顺利的选出leader,必须将zookeeper集群的服务器数部署为奇数。

从上边例子能看出来部署任意台机器都可以正常选举运行。部署奇数台是官方给的建议,由于奇数和奇数+1的容灾能力是同样的。好比:

5台服务器,可以对2台机器挂掉的状况进程容灾

6台服务器,可以对2台机器挂掉的状况进程容灾,若是挂掉3台,剩下的机器就没法实现过半了。

 

转自:https://www.toutiao.com/i6733090741318320653/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1&timestamp=1568424651&app=news_article&utm_source=weixin&utm_medium=toutiao_android&req_id=2019091409305101002004701808B6F48E&group_id=6733090741318320653

相关文章
相关标签/搜索