Zookeeper基础
Zookeeper是一种为分布式应用所设计的高可用,高性能,且一致的开源协调服务,它提供一项基本服务:分布式锁服务。由于Zookeeper的开源特性,后来在分布式锁的基础上,摸索出其他的使用方法:配置维护,组服务,分布式消息队列,分布式通知/协调等。
1.Zookeeper文件系统
每个子目录项如NameService都被称为znode,和文件系统一样,我们能够自由的增加,删除znode,在一个znode下增加,删除子znode,唯一的不同在于znode是可以存储数据的。
有四种类型的znode:
PERSISTENT–持久化目录节点:客户端与zookeeper断开连接后,该节点依旧存在;
PERSISTENT_SEQUENTIAL–持久化顺序编号目录节点:客户端与zookeeper断开连接后,该节点依旧存在,只是zookeeper给该节点名称进行顺序编号;
EPHEMERAL–临时目录节点:客户端与zookeeper断开连接后,该节点被删除;
2.Zookeeper工作原理
zookeeper的核心是原子广播,这个机制保证了各个server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,分别是恢复模式(选主)
和广播模式
。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
为保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)
都在被提出时加上了zxid。实现zxid是一个4位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
3.Zookeeper功能/作用
3.1分布式锁
在分布式系统中如何对进程进行调度,假设在第一台机器上挂载了一个资源,然后这三个物理分布的进程都要竞争这个资源,但我们不希望他们同时进行访问,这时候就需要一个协调器,让他们有序的访问这个资源。这个协调器就是锁,比如进程-1在使用该资源时,会先去获得锁,进程-1获得锁以后会对该资源保持独占,这样其他进程就无法访问该资源,进程-1用完该资源以后将锁释放掉,让其他进程来获得锁,那么通过这个锁机制,我们就能保证分布式系统中多个进程能够有序的访问该临界资源。这个锁就叫做分布式锁。
锁服务分为两类:一个保持独占
,另一个控制时序
。
第一类,我们将zookeeper上的一个znode看作是一把锁,通过createznode的方式来实现。所有客户都去创建/distribute_lock节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的/distribute_lock节点就释放出锁。
第二类,/distribute_lock已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选master一样,编号最小的获得锁,用完删除。
3.1.1应用场景
单点故障:通常分布式系统采用主从模式,就是一个主控机连接多个处理节点。主节点复制分发任务,从节点负责处理任务,当主节点发生故障时,整个系统就瘫痪了。
传统方式的解决方案:采用一个备用节点,这个备用节点定期给当前主节点发送ping包,主节点收到ping包以后向备用节点发送回复Ack,当备用节点收到回复的时候就会认为当前主节点还活着,让它继续提供服务。
这种方式存在问题,在回复的时候网络发生故障,这样我们的备用节点同样收不到回复,就会认为主节点挂了,然后备用节点将它的Master实例启动起来,这样我们的分布式系统当中就有两个主节点,也就是双Master,出现双Master以后,我们的从节点就会将它所做的事一部分汇报给主节点,一部分汇报给从节点,这样服务就全乱了。
zookeeper解决方案:虽然不能避免网络故障,但它能保证每时每刻只有一个Master。两个主节点启动之后都向zookeeper去注册一个节点,注册完之后进行选举,编号小的获得锁成为主节点。当这个节点挂了,这时所注册的节点被自动删除,zookeeper再次发出选举,另一个主节点将获得锁成为主节点。
3.2服务注册与发现
分布式系统架构中有三类角色:服务提供者
,服务注册中心
,服务消费者
。
服务提供者作为服务的提供方将自身的服务信息注册到服务注册中心中,服务信息包含:隶属于哪个系统,服务的IP,端口,服务的请求URL,服务的权重等;
服务注册中心主要提供所有服务注册信息的中心存储,同时负责将服务注册信息的更新通知实时的push给服务消费者(主要通过zookeeper的watcher机制实现)。
服务消费者在启动时从服务注册中心获取需要的服务注册信息;将服务注册信息缓存在本地;监听服务注册信息的变更,如接收到服务注册中心的服务变更通知,则在本地缓存中更新服务的注册信息;根据本地缓存中的服务注册信息构建服务调用请求,并根据负载均衡策略来转发请求;对服务提供方的存活进行检测,如果出现服务不可用的服务提供方,将从本地缓存中剔除。
服务消费者只在自己初始化以及服务变更时会依赖服务注册中心,在此阶段的单点故障通过zookeeper集群来进行保障。在整个服务调用过程中,服务消费者不依赖于任何第三方服务。
3.3配置维护服务
发布与订阅即所谓的配置管理,顾名思义就是将数据发布到ZK节点上,供订阅者动态获取数据,实现配置信息的集中式管理和动态更新。例如全局的配置信息,地址列表等。集中式的配置管理在应用集群中是非常常见的,一般商业公司内部都会实现一套集中的配置管理中心,应对不同的应用集群对于共享各自配置的需求,并且在配置变更时能够通知到集群中的每一个机器。
3.4统一命名服务
分布式应用中,通常需要有一套完整的命名规则,即能够产生唯一的名称又便于人识别和记住,通常情况下用树形的名称结构是一个理想的选择。Zookeeper的Name Service与JNDI能够完成的功能差不多,他们都是将所有层次的目录结构关联到一定资源上,但是Zookeeper的Name Service更加是广泛意义上的关联,也许你并不需要将名称关联到特定资源上,你可能只需要一个不重复的名称,就像数据库中产生一个唯一的数字主键一样。
分布式系统中,通过使用命名服务,客户端应用能够根据指定的名字获取资源服务的地址,提供者信息。被命名的实体通常是集群中的机器,提供的服务地址,进程对象等,最常见的是一些分布式服务框架中的服务地址列表。
3.5分布通知/协调
Zookeeper中特有的watcher注册与异步通知机制,能偶很好的实现分布式环境下不同系统之间的通知与协调,实现对数据变更的实时处理。
3.6队列管理
两种类型的队列:同步队列
,当一个队列的成员都聚齐时,否则一直等待所有成员到达。
第二种,按照FIFO
方式进行入队和出队操作,例如实现生产者和消费者模型。
3.7集群管理
所谓集群管理无在乎两点:是否有机器退出和加入
、选举master
。
第一点,所有机器约定在父目录GroupMembers下创建临时目录节点,然后监听父目录节点的子节点变化消息。一旦有机器挂掉,该机器与 zookeeper的连接断开,其所创建的临时目录节点被删除,所有其他机器都收到通知:某个兄弟目录被删除。机器加入也是类似,所有机器收到通知:新兄弟目录加入,highcount又有了。
第二点,所有机器创建临时顺序编号目录节点,每次选取编号最小的机器作为master就好。