1,ZooKeeper
- ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务
- 是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件
- 为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、名字服务、分布式同步、组服务等
2,ZooKeeper使用场景
- 分布式配置中心(数据发布与订阅)
-
- 【说明】发布者将数据发布到ZK节点上,供订阅者动态获取数据,实现配置信息的集中式管理和动态更新
- 配置
-
- 应用在启动的时候会主动来获取一次配置,同时,在节点上注册一个Watcher
- 以后每次配置有更新的时候,都会实时通知到订阅的客户端,从来达到获取最新配置信息的目的
- 分布式搜索
-
- 索引的元信息和服务器集群机器的节点状态存放在ZK的一些指定节点,供各个客户端订阅使用
- 分布式日志收集系统
-
- 核心工作是收集分布在不同机器的日志
- 收集器通常是按照应用来分配收集任务单元,因此需要在ZK上创建一个以应用名作为path的节点P,并将这个应用的所有机器ip,以子节点的形式注册到节点P上
- 这样一来就能够实现机器变动的时候,能够实时通知到收集器调整任务分配
- 动态信息获取
-
- 系统中有些信息需要动态获取,并且还会存在人工手动去修改这个信息的访问
- 命名服务(Naming Service)
-
- 在分布式系统中,通过使用命名服务,客户端应用能够根据指定名字来获取资源或服务的地址,提供者等信息
- 被命名的实体通常可以是集群中的机器,提供的服务地址,远程对象等等——这些我们都可以统称他们为名字(Name)
- 较为常见的就是一些分布式服务框架中的服务地址列表。通过调用ZK提供的创建节点的API,能够很容易创建一个全局唯一的path,这个path就可以作为一个名称
-
- 服务提供者在启动的时候,向ZK上的指定节点/dubbo/${serviceName}/providers目录下写入自己的URL地址,这个操作就完成了服务的发布
- 服务消费者启动的时候,订阅/dubbo/${serviceName}/providers目录下的提供者URL地址, 并向/dubbo/${serviceName} /consumers目录下写入自己的URL地址
- 注意,所有向ZK上注册的地址都是临时节点,这样就能够保证服务提供者和消费者能够自动感应资源的变化
- Dubbo还有针对服务粒度的监控,方法是订阅/dubbo/${serviceName}目录下所有提供者和消费者的信息
- 分布式通知/协调
-
- 原理
-
- 使用zookeeper来进行分布式通知和协调能够大大降低系统之间的耦合
- ZooKeeper中特有Watcher注册与异步通知机制,能够很好的实现分布式环境下不同系统之间的通知与协调,实现对数据变更的实时处理
- 不同系统都对ZK上同一个znode进行注册,监听znode的变化(包括znode本身内容及子节点的),其中一个系统update了znode,那么另一个系统能够收到通知,并作出相应处理
- 使用场景
-
- 另一种心跳检测机制
-
- 检测系统和被检测系统之间并不直接关联起来,而是通过zk上某个节点关联,大大减少系统耦合
- 另一种系统调度模式
-
- 某系统有控制台和推送系统两部分组成,控制台的职责是控制推送系统进行相应的推送工作
- 管理人员在控制台作的一些操作,实际上是修改了ZK上某些节点的状态,而ZK就把这些变化通知给他们注册Watcher的客户端,即推送系统,于是,作出相应的推送任务
- 另一种工作汇报模式
-
- 一些类似于任务分发系统,子任务启动后,到zk来注册一个临时节点,并且定时将自己的进度进行汇报(将进度写回这个临时节点),这样任务管理者就能够实时知道任务进度
- 集群管理与Master选举
-
- 利用ZooKeeper有两个特性,就可以实施另一种集群机器存活性监控系统
-
- 客户端在节点 x 上注册一个Watcher,那么如果 x 的子节点变化了,会通知该客户端
- 创建EPHEMERAL类型的节点,一旦客户端和服务器的会话结束或过期,那么该节点就会消失
- 使用场景
-
- 监控系统
-
- 监控系统在 /clusterServers 节点上注册一个Watcher,以后每动态加机器,那么就往 /clusterServers 下创建一个 EPHEMERAL类型的节点:/clusterServers/{hostname}
- 监控系统就能够实时知道机器的增减情况,至于后续处理就是监控系统的业务了
- 一旦有机器挂掉,该机器与 zookeeper的连接断开,其所创建的临时目录节点被删除(跟上一条重复)
- Master选举则是zookeeper中最为经典的应用场景
-
- 分布式环境中,相同的业务应用分布在不同的机器上,有些业务逻辑(例如一些耗时的计算,网络I/O处理),往往只需要让整个集群中的某一台机器进行执行,其余机器可以共享这个结果,这样可以大大减少重复劳动,提高性能,于是这个master选举便是这种场景下的碰到的主要问题
- 利用ZooKeeper的强一致性,能够保证在分布式高并发情况下节点创建的全局唯一性
-
- 同时有多个客户端请求创建 /currentMaster 节点,最终一定只有一个客户端请求能够创建成功
- 利用这个特性,就能很轻易的在分布式环境中进行集群选取了
- 动态Master选举
-
- 这就要用到EPHEMERAL_SEQUENTIAL类型节点的特性了
- 就是允许所有请求都能够创建成功,但是得有个创建顺序
- 于是所有的请求最终在ZK上创建结果的一种可能情况是这样: /currentMaster/{sessionId}-1 ,?/currentMaster/{sessionId}-2 ,?/currentMaster/{sessionId}-3 ….. 每次选取序列号最小的那个机器作为Master
- 如果这个机器挂了,由于他创建的节点会马上消失,那么之后最小的那个机器就是Master了
- 搜索系统
-
- 如果集群中每个机器都生成一份全量索引,不仅耗时,而且不能保证彼此之间索引数据一致
- 因此让集群中的Master来进行全量索引的生成,然后同步到集群中其它机器
- Master选举的容灾措施是,可以随时进行手动指定master,就是说应用在zk在无法获取master信息时,可以通过比如http方式,向一个地方获取master
- Hbase
-
- 使用ZooKeeper来实现动态HMaster的选举
- 在Hbase实现中,会在ZK上存储一些ROOT表的地址和HMaster的地址,HRegionServer也会把自己以临时节点(Ephemeral)的方式注册到Zookeeper中,使得HMaster可以随时感知到各个HRegionServer的存活状态
- 同时,一旦HMaster出现问题,会重新选举出一个HMaster来运行,从而避免了HMaster的单点问题
- 分布式锁
-
- 分布式锁,这个主要得益于ZooKeeper为我们保证了数据的强一致性。锁服务可以分为两类,一个是保持独占,另一个是控制时序
- 独占
-
- 所谓保持独占,就是所有试图来获取这个锁的客户端,最终只有一个可以成功获得这把锁
- 通常的做法是把zk上的一个znode看作是一把锁,通过create znode的方式来实现
- 所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁
- 控制时序
-
- 控制时序,就是所有视图来获取这个锁的客户端,最终都是会被安排执行,只是有个全局时序了
- 做法和上面基本类似,只是这里 /distribute_lock 已经预先存在,客户端在它下面创建临时有序节点(这个可以通过节点的属性控制:CreateMode.EPHEMERAL_SEQUENTIAL来指定)
- Zk的父节点(/distribute_lock)维持一份sequence,保证子节点创建的时序性,从而也形成了每个客户端的全局时序
- 分布式队列
-
- 队列方面,简单地讲有两种,一种是常规的先进先出队列,另一种是要等到队列成员聚齐之后的才统一按序执行(屏障/Barrier)
- 先进先出队列(FIFO),和分布式锁服务中的控制时序场景基本原理一致
- 等到队列成员聚齐之后的才统一按序执行,屏障(Barrier)
-
- 类似Java多线程的CyclicBarrier
- 第二种队列其实是在FIFO队列的基础上作了一个增强
- 通常可以在 /queue 这个znode下预先建立一个/queue/num 节点,并且赋值为n(或者直接给/queue赋值n),表示队列大小,之后每次有队列成员加入后,就判断下是否已经到达队列大小,决定是否可以开始执行了
- 这种用法的典型场景是,分布式环境中,一个大任务Task A,需要在很多子任务完成(或条件就绪)情况下才能进行。这个时候,凡是其中一个子任务完成(就绪),那么就去 /taskList 下建立自己的临时时序节点(CreateMode.EPHEMERAL_SEQUENTIAL),当 /taskList 发现自己下面的子节点满足指定个数,就可以进行下一步按序进行处理了
3,ZooKeeper原理
- 数据模型
-
- ZooKeeper数据模型的结构与Unix文件系统很类似,整体上可以看作是一棵树,每个节点称做一个ZNode
- 每个ZNode都可以通过其路径唯一标识
- 每个ZNode上可存储少量数据(默认是1M, 可以通过配置修改, 通常不建议在ZNode上存储大量的数据)
- 每个ZNode上还存储了其Acl信息
- 每个ZNode的Acl的独立的,子结点不会继承父结点的
- ZNode
-
- 持久性分类
-
- Regular ZNode: 常规型ZNode, 用户需要显式的创建、删除
- Ephemeral ZNode: 临时型ZNode, 用户创建它之后,可以显式的删除,也可以在创建它的Session结束后,由ZooKeeper Server自动删除
- ZNode还有一个Sequential的特性,如果创建的时候指定的话,该ZNode的名字后面会自动Append一个不断增加的SequenceNo
- 细分
-
- PERSISTENT-持久化目录节点:客户端与zookeeper断开连接后,该节点依旧存在
- PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点:客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
- EPHEMERAL-临时目录节点:客户端与zookeeper断开连接后,该节点被删除
- EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点:客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号
- Session
-
- Client与ZooKeeper之间的通信,需要创建一个Session,这个Session会有一个超时时间
- 因为ZooKeeper集群会把Client的Session信息持久化,所以在Session没超时之前,Client与ZooKeeper Server的连接可以在各个ZooKeeper Server之间透明地移动
- 在实际的应用中,如果Client与Server之间的通信足够频繁,Session的维护就不需要其它额外的消息了,否则,ZooKeeper Client会每t/3 ms发一次心跳给Server,如果Client 2t/3 ms没收到来自Server的心跳回应,就会换到一个新的ZooKeeper Server上。这里t是用户配置的Session的超时时间
- Zab协议
-
- Zookeeper 的核心是原子广播,这个机制保证了各个Server之间的同步
- Zab协议有两种模式,它们分 别是恢复模式(选主)和广播模式(同步)
- 当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和 leader的状态同步以后,恢复模式就结束了
- 状态同步保证了leader和Server具有相同的系统状态
- 为 了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上 了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数
- Leader(选举)选主流程
-
- 基于fast paxos算法实现
-
- 原则:在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点都执行相同的操作序列,那么他们最后能得到一个一致的状态
- Paxos解决的就是保证每个节点执行相同的操作序列
- 数据一致性与paxos算法
- ZooKeeper三个角色
-
- Leader:进行投票的发起和决议,更新系统状态
- Learner
-
- Follower
-
- 用于接受客户请求并向客户端返回结果
- 在选主过程中参与投票
- Observer
-
- 可以接受客户端连接,将写请求转发给Leader节点
- Observer不参与投票过程,只同步Leader的状态
- Observer的目的是为了扩展系统,提高读取速度
- Client
-
- Curator
-
- Recipes
-
- Elections
-
- Leader Latch
- Leader Election
- Locks
-
- Shared Reentrant Lock
- Shared Lock
- Shared Reentrant Read Write Lock
- Shared Semaphore
- Multi Shared Lock
- Barriers
-
- Barrier
- Double Barrier
- Counters
-
- Shared Counter
- Distributed Atomic Long
- Caches
-
- Path Cache
- Node Cache
- Tree Cache
- Nodes
-
- Persistent Ephemeral Node
- Queues
-
- Distributed Queue
- Distributed Id Queue
- Distributed Priority Queue
- Distributed Delay Queue
- Simple Distributed Queue
- Framework
- Utilities
- Client
- Errors
- Extensions
- ZooKeeper