这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战
基本概念
- Zookeeper可以作为注册中心和分布式锁
- Zookeeper是Hadoop系统中的一员
- 构建Zookeeper集群时,使用的服务器的数量是奇数个
- 原语:
- 操作系统和计算机网络术语
- 由若干条指令组成的,用于完成一定功能的一个过程
- 原语具有不可分割性.即原语的执行必须是连续的,在执行过程中不允许被中断
- Zookeeper是一个Apache开源的分布式协调服务框架:
- 将复杂且容易出错的分布式一致性服务封装起来,构成一个高效的原语集,并以一系列简单易用的接口提供给调用方
- 主要为分布式应用提供协调服务
-
- Zookeeper用于维护配置信息,命名,提供分布式同步以及组服务的集中式服务,这些类型的服务可供分布式应用程序使用
- Zookeeper主要负责存储和管理这些服务中需要关注的配置数据,如果这些配置数据的状态发生变化,Zookeeper就会通知注册在Zookeeper上的服务来及时响应
- Zookeeper提供了高可用,高性能,稳定的分布式数据一致性解决方案,通常用于以下几个方面:
- 数据的发布和订阅
- 统一命名服务
- 分布式通知和协调
- 集群管理
- Master选举
- 负载均衡
- 分布式锁
- 分布式队列
- Zookeeper将数据保存在内存中,性能高.在读操作高于写操作的应用中性能表现更好. 读操作多于写操作是协调服务的典型场景,因为写操作会导致所有的服务器间的同步状态
- Zookeeper包含以下优点:
- 简单的数据结构:
- Zookeeper服务器内存中的数据模型由一系列数据节点Znode组成
- Zookeeper使得分布式应用可以通过一个共享的树形结构的名称空间进行相互协调
- Zookeeper将数据全量存储在内存中,这样可以提高服务器的吞吐量并且减少延迟
- 由于内存限制,所以需要保持Zookeeper中Znode存储的数据量尽可能的小
- 构建集群:
- Zookeeper集群通常是由一组机器组成,使用的机器数量是奇数个
- Zookeeper中组成集群的每台机器都会在内存中维护当前服务器的状态,并且每台机器之间可以相互通信
- 顺序访问:
- 对于来自客户端的每一个更新请求 ,Zookeeper都会分配一个递增的全局唯一编号
- Zookeeper中可以根据这个编号区分所有事务操作的先后顺序
- 高性能:
- Zookeeper和Redis类似,将数据全量存储在内存中
- Zookeeper具有高吞吐量,低延迟的优势
- 简单的数据结构:
Zookeeper特点
- Zookeeper中的原子广播协议就是一致性协议
- Zookeeper是一个高效的,可扩展的服务
- Zookeeper中的read操作和write操作都很快速 ,read操作比write操作更快
顺序一致性Sequential Consistency
- 从一个客户端发起的更新请求会被顺序执行
- 从同一客户端发起的事务请求,最终将会严格按照顺序被应用到Zookeeper中
- 顺序性包括以下两种:
- 全局有序: 如果一条服务器上的一个消息在另一个消息之前发布,那么所有服务器上的这个消息都是在另一个消息前发布
- 偏序: 如果另一个消息在一个消息之后被同一个发布者发布,那么这个消息一定在另一个消息前面
原子性Atomicity
- 所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的
- 也就是说,在整个集群中的所有机器要么都成功应用了某一个事务,要么都没有应用某一个事务.没有中间状态
- 更新要么成功要么失败,没有部分成功的情况
单一系统镜像Single System Image
- 无论客户端连接到哪一个服务器Server,获取到的系统镜像是一致的
- 无论客户端连接到哪一个Zookeeper服务器上,最终获取到的服务端数据模式都是一致的,也就是完全一样的树形结构
- 通过最终一致性保证单一系统镜像
- 在ZAB协议中:
- 写操作并不保证更新会得到所有的Follower立即确认
- 部分Follower以及Leader可以读取到最新的数据,所以通过其余部分Follower读取数据不能保证会读取到最新的数据
- 此时可以在读操作前使用sync同步方法
可靠性Reliability
- 如果更新有效,就会持续有效,直到更新被覆盖
- 一旦某个更改请求被应用,更改的结果会被持久化,直到被下一次更改覆盖
- 一个更新操作如果接受就不会意外丢失,除非其余的更新操作覆盖
实时性Timeliness
- 保证在一定的时间内各个客户端看到的系统信息是一致的
- Zookeeper保证客户端可以在一个时间间隔范围内获取服务器的更新信息或者是服务器失效信息
- 由于网络延迟的原因 ,Zookeeper不能保证两个客户端同时得到立即更新的数据.如果需要最新数据,可以在读数据前使用sync() 同步接口
等待无关wait-free
- 慢的失效的客户端不得干预快速的客户端的请求,这样使得每个客户端都能够进行有效的等待
Zookeeper使用场景
- Zookeeper的应用在于Zookeeper可以保存数据的功能,但是需要注意的是Zookeeper不适合保存大量数据,因为Zookeeper将数据全量保存在内存中
数据发布和订阅
- 分布式环境下的配置文件管理和配置文件同步问题:
- 在一个集群中,所有节点的配置信息是一致的. 比如Hadoop集群,集群中的数据库配置等全局配置信息等
- 配置文件中的信息修改之后,需要能够快速同步到各个节点上
- 发布与订阅模型,也就是配置中心
- 发布者将数据信息发布到Zookeeper节点上,订阅者可以从Zookeeper节点上动态获取数据信息,这样可以实现数据信息的集中管理和动态更新
- 分布式环境下可以使用Zookeeper实现配置管理:
- 将配置信息写入Zookeeper的一个节点Znode
- 其余各个节点可以监听这个节点Znode
- 如果Znode中的配置信息发生修改 ,Zookeeper会将修改的配置信息通知到各个监听的节点
- 通过Zookeeper的Watcher机制可以很方便实现数据的发布和订阅
- 将数据发布到Zookeeper被监听的节点上,其余机器可用通过监听Zookeeper上节点的变化来实现配置的动态更新
统一命名服务
- 分布式环境中经常需要对服务进行统一命名:
- 当一个服务部署多个副本时,因为不确定哪个服务可以高性能地处理请求,所以无法直接调用具体的服务
- 这时可以将多个服务进行统一命名,然后在内部进行负载均衡调用,这样来实现对服务的最优化调用. 比如Dubbo服务等
- 统一命名服务的实现方式:
- 发布者将自身的地址列表写入到Zookeeper节点上
- 订阅者可以从固定名称的节点获取地址列表,链接到发布者实现相关通信
- 通过Zookeeper的顺序节点生成全局唯一ID
分布式通知和协调
- 通过使用Zookeeper的watcher注册和异步通知机制,很好的实现分布式环境中不同系统之间的通知和协调,实现对数据的实时处理
集群管理
- 集群管理包括在线率,节点的上线下线通知等信息
- 分布式环境中需要实时掌握每个节点的状态:
- 监控集群中各个机器的状态
- 收集集群中各个机器的运行时状态数据
- 收集服务器动态的上线下线通知
- Zookeeper实现集群管理的方式:
- 将节点信息写入Zookeeper中的一个节点Znode
- 监听这个节点Znode获取这个节点的实时状态变化
- 实例: HBase中Master状态监控和选举
Master选举
- Master选举应用场景:
- 分布式环境中相同的业务应用分布在集群中不同的机器上,部分业务逻辑,比如耗时计算,网络I/O处理.只需要集群中某一台机器进行执行,其余机器共享执行结果即可
- 这样可以极大减少重复执行的操作,提高系统性能
- Master选举实现方式:
- 通过利用Zookeeper的强一致性,可以保证在分布式高并发情况下创建的节点一定是全局唯一的节点
- 当同时存在多个客户端请求创建currentMaster节点时,最终一定会是只有一个客户端请求能够创建节点成功
- Zookeeper中根据节点全局唯一的特性,可以创建一个Master节点,其余客户端通过Wacther监控这个Master节点是否存活
- 如果这个Master节点发生宕机,其余机器可以继续创建新的Master节点,实现重新选举
负载均衡
- 软件负载均衡,包括:
- 消息中间件的生产
- 消费者的负载均衡
分布式锁
- 通过利用Zookeeper的强一致性,使用临时节点实现分布式锁
- 通过创建唯一节点获得分布式锁
- 当获得锁的一方执行完相关的代码或者宕机之后释放锁
- 锁服务分为:
- 独占锁:
- 所有的客户端都会来获取这个锁,但是最终只有一个客户端能够获取这个锁
- 独占锁使用的是临时节点
- 控制时序锁:
- 所有用来获取锁的客户端,都会根据顺序安排得到锁
- 控制时序锁使用的是某个节点下的临时顺序子节点
- 独占锁:
分布式队列
- 分布式队列包括以下两种:
- FIFO:
- 类似于分布式锁服务中的控制时序
- 使用临时顺序节点实现
- 等待分布式队列中各个元素聚齐之后按顺序执行:
- 首先在队列的节点中创建一个queue(num) 节点,并且复制队列的大小
- 通过监控队列节点子节点的变化来确认队列是否已满或者条件是否满足执行的需要
- 这个方式应用于有条件执行的任务,需要等条件满足后才能执行任务的场景
- FIFO:
Zookeeper工作原理
- Zookeeper中的设计模式:
- Zookeeper是一个基于观察者模式设计的分布式服务管理框架
- Zookeeper负责存储和管理配置数据以及关心的重要数据,接收观察者的注册
- 如果Zookeeper中的数据的状态发生变化 ,Zookeeper负责通知已经在Zookeeper上注册的观察者做出反应,实现集群中的Master-Slave模式
- Zookeeper的核心 : 原子广播
- 原子广播机制保证了各个服务器Server之间的同步,通过ZAB(Zookeeper Atomic Broadcast protocol)协议实现
- ZAB协议:
- 恢复模式 : Recovery选主
- 当服务器启动或者领导者leader宕机时 ,ZAB进入恢复模式
- 当领导者leader选举出并且大多数服务器server完成和领导者leader的状态同步后,恢复模式结束
- 状态同步保证领导者leader和服务器server具有相同的系统状态
- 广播模式 : Broadcast同步
- 恢复模式 : Recovery选主
- zxid:
- Zookeeper中使用递增的事物ID号zxid来标识事务来来保证事务的顺序一致性,所有的提议proposal在提出的时候都有一个zxid
- zxid是一个64位的数字:
- 高32位是epoch用来标识领导者leader关系是否改变,每一个领导者leader选举出来,都会有一个新的epoch, 标识出当前处于指定的领导者leader下
- 低32位是一个递增的计数器
写操作
- leader的写操作包括以下五个步骤:
- 客户端向leader发起写请求
- leader将写请求以proposal的形式发送给所有的follower并且等待ack
- follower接收到leader的proposal后给leader返回ack
- leader得到超过半数的ack, 包括自身默认的一个ack后向所有的follower和observer发送commit
- leader将处理结果返回给客户端
- 注意点:
- observer没有投票权 ,leader不需要得到observer的ack
- leader只需要得到超过半数的ack即可,不需要得到所有follower的ack, 要注意的是leader本身也包含一个ack
- observer没有投票权,也要同步leader的数据,这样可以保证处理读请求时可以返回尽可能新的数据
- follower或者observer的写操作:
- follower或者observer的写操作中follower和observer都可以接收写请求,但是不直接处理,而是将写请求转发给leader进行处理
- follower或者observer的写操作中多了一步请求转发,其余流程和leader的写操作一样
读操作
- leader和follower和observer都可以处理读请求,从本地内存中读取数据并返回给客户端
- 处理读请求不需要服务器之间的交互,在follower和observer越多时,整体可处理的读请求量越大,读请求性能越高
会话Session
- 会话Session指的是Zookeeper服务器与客户端之间的会话
- Zookeeper中的一个客户端连接是指客户端和服务器之间的一个TCP长连接:
- 客户端启动时,首先会与服务器建立一个TCP连接,第一次建立连接开始时,客户端会话的生命周期也开始
- 在这个TCP长连接中,客户端能够通过心跳检测与服务器保持有效的会话,也可以向Zookeeper服务器发送请求并且接收响应,同时还可以接收来自服务器的watch事件通知
- 客户端会话Session作为会话实体,包括以下4个属性:
- SessionID: 会话Session的全局唯一标识,用来识别会话Session
- TimeOut: 会话超时事件
- 客户端在创建会话Session实例时,会设置一个会话超时时间
- 由于服务器压力巨大,网络故障,客户端主动断开连接等原因导致客户端连接断开时,只要在Session的TimeOut规定的时间范围内能够重新连接上集群中的任意一台服务器,那么之前创建的会话Session还是有效的
- TickTime: 下次会话超时的时间点
- isClosing: 服务端检测到会话Session超时失效后,会通过这个设置将会话Session关闭
- 客户端Client和Zookeeper集群建立连接时,整个会话Session的状态变化如下图:
- 如果客户端Client由于TimeOut和Zookeeper服务器Server失去连接,客户端Client处于CONNECTING状态,也就是图中的2状态.此时会自动尝试连接Zookeeper服务器Server
- 如果在会话Session有效期内成功连接到Zookeeper服务器集群中任意一台服务器Server, 客户端Client就进入到CONNECTED状态,也就是图中的3状态
- 注意点:
- 客户端Client由于网络的原因失去和Zookeeper服务器Server的联系时,客户端Client会停留在当前的状态,客户端Client会尝试主动连接Zookeeper服务器Server
- 客户端Client不能宣布自身的会话Session过期expired, 会话Session过期expired是由Zookeeper服务器Server决定的,客户端Client可以选择自身主动关闭会话Session
权限控制ACL
- Zookeeper使用ACL(Access Control Lists)策略进行权限控制. 这个和UNIX文件系统的权限控制类似
- Zookeeper中包括以下五种权限:
- CREATE : 创建子节点的权限
- READ : 读取节点数据和子节点列表的权限
- WRITE : 更新节点数据的权限
- DELETE : 删除子节点的权限
- ADMIN : 设置节点ACL的权限
- 注意:
- CREATE和DELETE这两种权限都是针对子节点的权限控制
Zookeeper应用
- Kafka:
- Zookeeper主要为Kafka提供Broker和Topic的注册以及多个Partition的负载均衡等功能
- HBase:
- Zookeeper确保HBase整个集群中只有一个Master
- 保存和提供regionserver的状态信息
- Hadoop:
- Zookeeper为NameNode提供高可用支持
Zookeeper应用场景选择
- Zookeeper发挥巨大作用的应用场景:
- 粗粒度分布式锁
- 分布式选主
- 主备高可用切换
- 不需要高TPS事务数支持的场景
- 这些需求往往集中在大数据,离线任务等相关业务领域
- 大数据领域讲究分割数据集,并且大部分时间是分任务多进程多线程并行处理这些数据集
- 这时可以应用Zookeeper在一些点上将这些任务和进程线程进行统一协调
- Zookeeper使用要进行严格的场景,容量,SLA需求评估的应用场景:
- 交易场景的交易链路服务
- 主业务数据存取
- 大规模服务发现和服务器注册
- 大规模健康监测
- 这些场景下应该尽量避免引入Zookeeper
- Zookeeper应用场景选择的原因 :
- Zookeeper中的写操作不是可扩展的,不可以通过增加节点解决水平扩展性问题
- 可以在项目实践中想方设法梳理业务,垂直划分业务领域,将业务划分到多个Zookeeper注册中心.但是不允许业务来按照技术来划分治理业务
- 因为不能由于Zookeeper注册中心的技术限制破坏了业务服务的可连通性,阻碍业务服务的发展
- Zookeeper中的长连接可能会出现闪断的情况.在闪断发生后,这期间的业务操作是否需要重试等机制也需要异常捕获的业务来控制
- Zookeeper中的写操作不是可扩展的,不可以通过增加节点解决水平扩展性问题