1,ZooKeeper
- ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务
- 是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件
- 为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、名字服务、分布式同步、组服务等
2,ZooKeeper使用场景
- 分布式配置中心(数据发布与订阅)
- 【说明】发布者将数据发布到ZK节点上,供订阅者动态获取数据,实现配置信息的集中式管理和动态更新
- 配置
-
- 应用在启动的时候会主动来获取一次配置,同时,在节点上注册一个Watcher
- 以后每次配置有更新的时候,都会实时通知到订阅的客户端,从来达到获取最新配置信息的目的
- 分布式搜索
-
- 索引的元信息和服务器集群机器的节点状态存放在ZK的一些指定节点,供各个客户端订阅使用
- 分布式日志收集系统
-
- 核心工作是收集分布在不同机器的日志
- 收集器通常是按照应用来分配收集任务单元,因此需要在ZK上创建一个以应用名作为path的节点P,并将这个应用的所有机器ip,以子节点的形式注册到节点P上
- 这样一来就能够实现机器变动的时候,能够实时通知到收集器调整任务分配
- 动态信息获取
-
- 系统中有些信息需要动态获取,并且还会存在人工手动去修改这个信息的访问
- 服务提供者在启动的时候,向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来注册一个临时节点,并且定时将自己的进度进行汇报(将进度写回这个临时节点),这样任务管理者就能够实时知道任务进度
- 客户端在节点 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的单点问题
- 所谓保持独占,就是所有试图来获取这个锁的客户端,最终只有一个可以成功获得这把锁
- 通常的做法是把zk上的一个znode看作是一把锁,通过create znode的方式来实现
- 所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁
- 控制时序,就是所有视图来获取这个锁的客户端,最终都是会被安排执行,只是有个全局时序了
- 做法和上面基本类似,只是这里 /distribute_lock 已经预先存在,客户端在它下面创建临时有序节点(这个可以通过节点的属性控制:CreateMode.EPHEMERAL_SEQUENTIAL来指定)
- Zk的父节点(/distribute_lock)维持一份sequence,保证子节点创建的时序性,从而也形成了每个客户端的全局时序
- 类似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的独立的,子结点不会继承父结点的
- 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给该节点名称进行顺序编号
- 原则:在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点都执行相同的操作序列,那么他们最后能得到一个一致的状态
- Paxos解决的就是保证每个节点执行相同的操作序列
- 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