目录
概述
ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,它提供了一项基本服务:分布式服务。
- ZooKeeper设计了一种新的数据结构Znode;
- 并在数据结构的基础上定义了一些原语,用来操作Znode;
- 由于在分布式坏境下各个服务是通过消息以网络的形式通信的,所以还需要一个通知机制,即Watcher机制
所以ZooKeeper提供的服务主要是通过:数据结构+原语+watcher机制这三个部分实现的
数据模型Znode
Zookeeper拥有一个树形结构层次的命令空间,与标准文件系统非常类似;文件数中的每个节点被称为Znode,每个Znode都可以拥有子节点
引用方式
Znode通过路径引用,类似于Linux中的文件路径,路径必须是绝对的(必须从根目录开始,以/开头的)。而且路径必须是唯一的,因此路径不能改变
Znode结构
Znode具有文件和目录的特点,即维护这数据(原信息、ACL、时间戳等),又可以作为路径标识的一部分。每个Znode由3部分组成:
- stat:状态信息,描述该Znode的版本权限等信息
- data:与该Znode关联的数据
- children:该Znode下的子节点
Zookeeper虽然可以关联一些数据,但它并不是数据库!Zookeeper是用来管理调度数据的,比如分布式应用中的配置文件信息、状态信息等,这些元数据的大小通常以KB为单位。ZooKeeper的服务器和客户端都被设计为严格检查并限制每个Znode的数据大小至多1M。
数据访问
对于Zookeeper中每个节点存储的数据的操作都是原子性的。读操作将获取与节点相关的所有数据;写操作会替换节点中的所有数据。每一个节点都拥有自己的ACL表,规定了用户权限
节点类型
Zookeeper中有两种类型的节点:临时节点和永久节点。节点的类型在创建时被确定,并且不能改变
- 临时节点(ephemeral):生命周期依赖于创建它们的会话。一旦会话结束,临时节点就会被删除。虽然每个临时节点都绑定到一个客户端会话,但它们对所有的客户端都是可见的。临时节点不允许拥有子节点
- 永久节点(persistent):只有在客户端执行删除操作时才会被删除
顺序节点
在创建Znode是用户可以请求在路径的末尾添加一个递增的计数。计数对于该节点的父节点是唯一的,计数的格式为%10d,即10位数字,如0000000001
监视器
客户端可以在节点上设施监视器,当节点状态发生变化(Znode的增删改)将会触发Watcher,zookeeper将会向客户端发送一条通知,watcher只能被触发一次
Zookeeper特性
1、Zookeeper:由一个leader,多个follower组成的集群
2、全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的
3、分布式读写,更新请求转发,由leader实施
4、更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
5、数据更新原子性,一次数据更新要么成功,要么失败
6、实时性,在一定时间范围内,client能读到最新数据
Zookeeper应用举例
分布式系统中的单点故障:通常分布式系统采用主从结构,主节点负责分发任务,从节点富足处理任务,当主节点发生故障那么整个系统就瘫痪了,这是因为系统中只有1个主节点导致的
传统解决方式是采用一个备用主节点,备用主节点定期向主接待你发送ping包,主节点收到ping包后向备用主节点发送ack回复,当备用主节点接受到了回复就会认为当前主节点还存货着,让它继续提供服务。
但这么做若主节点发送ack回复的时候网络出问题了,备用主节点收不到ack回复就会认为主节点宕机了,然后备用主节点将它的Master实例启动起来,这样系统中就存在了2个主节点,会发生脑裂情形。
Zookeeper拥有一套Master选举机制,并且能够保证系统中只有1个主节点:
在引入了zookeeper之后启动两个主节点:masterA、masterB,它们都会向zookeeper去注册Znode,假设masterA注册的Znode为master-0000000001,masterB为master-000000002。注册完后会进行选举,Znode编号小的获胜,即masterA成为主节点,masterB被阻塞成为备用节点。
若masterA宕机了,这是它所注册的Znode会被自动删除,Zookeeper会自动感知到节点的变化,会再次发起选择,此时masterB获胜成为主节点
若masterA恢复了,它会再次向zookeeper注册一个Znode,此时的Znode将会是master000000003。zookeeper感知到节点的变化后再次发起选举,因为masterB的Znode编号更小,masterB获胜继续担任主节点,而masterA成为备用节点
zoo.cfg参数分析
在Zookeeper的搭建中,conf目录下的zoo.cfg记录了zookeeper集群的配置信息
- tickTime:Zookeeper服务器之间或客户端与服务器之间维持心跳的时间间隔,每隔tickTime发送一次心跳
- dataDir:Zookeeper保存数据的目录,默认情况下写数据的日志文件也保存在这个目录中
- clientPort:客户端连接zookeeper服务器的端口,zookeeper会监听这个端口接受客户端的访问请求
- initLimit:Follower初始化连接到Leader服务器最长能忍受的心跳时间间隔数。即超过10个tickTime后Leader服务器还未收到Follow客户端发送的信息,则表明此Followwe客户端连接失败
- synclimit:Leader与Follower之间发送信息、请求和应答时间长度最长不能超过多少个tickTime
- server.A=B:C:D:A用来标识是第几号服务器,与dataDir下的myid文件内容相同;B是这个服务器的ip地址;C标识此无服务器与集群中的Leader交换信息的端口;D端口用来执行选举时服务器之间互相通信的断头
选举机制
考虑到zookeeper的高可用性,一般都配置3台以上奇数台zookeeper服务器,其中只有一台服务器作为leader,由它来管理协调所有数据,而其他服务器作为follower。当leader宕机时,zookeeper会在所有follower中发起新leader的竞选。
选举状态:
- LOOKING:竞选状态
- FOLLOWING:随从状态,同步leader状态,参与投票。
- OBSERVING:观察状态,同步leader状态,不参与投票
- LEADING:领导者状态。
全新集群选举机制
假设一个zookeeper集群由5台server构成,它们的id从1-5,且它们是最新启动的没有历史数据,若它们依次启动:
1、server.1启动,它先给自己投一票,由于只有一台服务器启动,它发送的报文没有任何响应,所以它的选举状态为LOOKING
2、server.2启动,它先给自己投一票,然后与server.1进行通信,server.1给它投一票,但还没有半数以上的票,所以它也保持LOOKING状态
3、server.3启动,它先给自己投一票,并且能够与server.1和server.2通信,获取了2票,一共3票超过了半数,则它成为了Leader,server.1 2成为了Follower
4、server.4启动,同理虽然可以有4票但Leader已经被选出了,只能做Follower了
5、server.5同理也是Follower
只有当半数以上的服务器宕机才代表zookeeper服务器宕机,所以zookeeper集群的服务器数量小设置为奇数
数据恢复的选举机制
当zookeeper运行一段时间后有server宕机,zookeeper感知到节点变化就会再一次发起选举。此时的选举考量3个因素:
- 数据id:数据越新的数据id则越大,可理解为时间戳越大,数据每次更新都会更新id
- Leader id:myid中的值
- 逻辑时钟:这个值从0开始递增,每次选举对应一个值,在同一轮选举中该值应该是一致的。逻辑时钟确保了参与投票的是来自同一个选举会议。逻辑时钟越大即选举的进程更新
选举机制
- 逻辑时钟小的投票权被忽略,因为不是来自最新的选举会议
- 逻辑时钟值相同情况下,数据id大的胜出
- 数据id相同的情况下,leader id大的胜出