之前写过关于zookeeper的一篇文章《zookeeper-paxos》,paxos太难理解了,当时理解了,但现在又忘记了,机械学习果然是不行的
虽然曾经有一篇文章讲阿里不使用zk做服务发现,但大多数公司的分布式架构中基本都能看到zk的身影,而且他躲在里面,你可能看不到他,感受不到他的存在
对于架构体系中的这样一位选手,了解,学习,研究是相当有必要的
ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby 一个开源的实现
ZooKeeper 是集群的管理者,监视着集群中各节点的状态,根据节点提交的反馈进行下 一步合理的操作。最终,将简单易用的接口和功能稳定,性能高效的系统提供给用户
zooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services
这大概描述了Zookeeper的作用,配置管理,名字服务,提供分布式同步以及集群管理
知道了zk的定义,其实跟不知道差不多,还是要追根溯源,看看zk今世因缘,存在的意义
zk的历史很多地方都有介绍,这儿就不赘述了
相对历史,更想知道为什么需要zk?
以前经历的系统,都是使用redis做为服务中心了,不管使用single redis,还是redis cluster,能胜任架构需求,全局命名服务、订阅发布监听服务列表、分布式锁足矣
一度怀疑zk的价值,也阻碍了进一步学习的热情,但存在即合理
设计 ZooKeeper 的目的是为了减轻分布式应用程序所承担的协调任务
还是从ZK的定义追溯它的作用
在我们的应用中除了代码外,还有一些就是各种配置。比如数据库连接等
一般我们都是使用配置文件的方式,在代码中引入这些配置文件。但是当我们只有一种配置,只有一台服务器,并且不经常修改的时候,使用配置文件是一个很好的做法,但是如果我们配置非常多,有很多服务器都需要这个配置,而且还可能是动态的话使用配置文件就不是个好主意了。
这个时候往往需要寻找一种集中管理配置的方法,我们在这个集中的地方修改了配置,所有对这个配置感兴趣的都可以获得变更。比如我们可以把配置放在数据库里,然后所有需要配置的服务都去这个数据库读取配置
但是,因为很多服务的正常运行都非常依赖这个配置,所以需要这个集中提供配置服务的服务具备很高的可靠性。
一般我们可以用一个集群来提供这个配置服务,但是用集群提升可靠性,那如何保证配置在集群中的一致性呢? 这个时候就需要使用一种实现了一致性协议的服务了。Zookeeper就是这种服务,它使用Zab这种一致性协议来提供一致性
比如为了通过网络访问一个系统,我们得知道对方的IP地址,但是IP地址对人非常不友好,这个时候我们就需要使用域名来访问。
但是计算机是不能是别域名的。
怎么办呢?
如果我们每台机器里都备有一份域名到IP地址的映射,这个倒是能解决一部分问题,但是如果域名对应的IP发生变化了又该怎么办呢?于是我们有了DNS这个东西。
我们只需要访问一个大家熟知的(known)的点,它就会告诉你这个域名对应的IP是什么。
在我们的应用中也会存在很多这类问题,特别是在我们的服务特别多的时候,如果我们在本地保存服务的地址的时候将非常不方便,但是如果我们只需要访问一个大家都熟知的访问点,这里提供统一的入口,那么维护起来将方便得多了
比如在一个分布式环境中,为了提高可靠性,我们的集群的每台服务器上都部署着同样的服务
但是,一件事情如果集群中的每个服务器都进行的话,那相互之间就要协调,编程起来将非常复杂。而如果我们只让一个服务进行操作,那又存在单点。通常还有一种做法就是使用分布式锁,在某个时刻只让一个服务去干活,当这台服务出问题的时候锁释放,立即fail over到另外的服务
这在很多分布式系统中都是这么做,这种设计有一个更好听的名字叫Leader Election(leader选举)。比如HBase的Master就是采用这种机制。但要注意的是分布式锁跟同一个进程的锁还是有区别的,所以使用的时候要比同一个进程里的锁更谨慎的使用
这儿其实说了两个作用
在分布式的集群中,经常会由于各种原因,比如硬件故障,软件故障,网络问题,有些节点会进进出出。有新的节点加入进来,也有老的节点退出集群。这个时候,集群中其他机器需要感知到这种变化,然后根据这种变化做出对应的决策
比如我们是一个分布式存储系统,有一个中央控制节点负责存储的分配,当有新的存储进来的时候我们要根据现在集群目前的状态来分配存储节点
这个时候我们就需要动态感知到集群目前的状态,这也就是注册中心
分布式系统在设计时,都会考虑一下CAP,在现有理论下,CAP是不能同时满足的,所以需要根据业务场景选择合适的设计要求
CAP定义在《zookeeper-paxos》中有详细说明
ZooKeeper是个CP(一致性+分区容错性)的,即任何时刻对ZooKeeper的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性;但是它不能保证每次服务请求的可用性。也就是在极端环境下,ZooKeeper可能会丢弃一些请求,消费者程序需要重新请求才能获得结果。
ZooKeeper是分布式协调服务,它的职责是保证数据在其管辖下的所有服务之间保持同步、一致;所以就不难理解为什么ZooKeeper被设计成CP而不是AP特性的了
而且, 作为ZooKeeper的核心实现算法Zab,就是解决了分布式系统下数据如何在多个服务之间保持同步问题的
在谈到分布式的时候,我们通常说的“节点"是指组成集群的每一台机器 然而,在 ZooKeeper 中,“节点"分为两类:
与Linux文件系统不同的是,Linux文件系统有目录和文件的区别,而Zookeeper的数据节点称为ZNode,ZNode是Zookeeper中数据的最小单元,每个ZNode都可以保存数据,同时还可以挂载子节点,因此构成了一个层次化的命名空间,称为树
znode除了名称、数据以外,还有一套属性:zxid
ZooKeeper状态的每一次改变, 都对应着一个递增的Transaction id, 该id称为zxid. 由于zxid的递增性质, 如果zxid1小于zxid2, 那么zxid1肯定先于zxid2发生
创建任意节点, 或者更新任意节点的数据, 或者删除任意节点, 都会导致Zookeeper状态发生改变, 从而导致zxid的值增加
此外,znode还有操作权限。如果我们把以上几类属性细化,又可以得到以下属性的细节:
znode是由客户端创建的,它和创建它的客户端的内在联系,决定了它的存在性:
另外,无论是EPHEMERAL还是EPHEMERAL_SEQUENTIAL节点类型,在zookeeper的client异常终止后,节点也会被删除。
服务器具有四种状态,分别是LOOKING,FOLLOWING,LEADING,OBSERVING
最典型集群模式:Master/Slave 模式(主备模式)
在这种模式中,通常 Master 服务器作为主服务器提供写服务,其他的 Slave 服务器从服务器通过异步复制的方式获取 Master 服务器最新的数据提供读服务
zookeeper都是集群形式部署的,而zk服务又分为不同角色来执行不同的任务,ZooKeeper中没有选择传统的 Master/Slave 概念
而是引入了Leader、Follower 和 Observer 三种角色
在区分zk服务器角色之前,需要解释几个概念:
选举(election)是分布式系统实践中常见的问题,通过打破节点间的对等关系,选得的leader(或叫master、coordinator)有助于实现事务原子性、提升决议效率
集群本身有很多种类,如tomcat集群,集群里面每一台机器是对等的,所以其自身不存在leader之说
另外一类,如fastDfs,其依赖于独特的HASH算法,建立文件名和路径之间的映射关系,写操作都是通过namenode分发到各台datanode之上,算法保证了文件名的独一无二,也不存在leader的说法
还有memcache集群,集群里面的机器之间彼此无心跳,通过一致性hash尽可能将key值的存储分散化,降低单一memcahe服务器down机的影响。
还有一类是主从复制,主节点负责写,从节点负责读,提高读的性能。从节点定期通过心跳与主节点沟通,一旦主节点挂掉了,从节点马上接手主节点的任务
对于分布式应用,难以避免出现网络的抖动。比如, 主节点暂时失去响应,如瞬时负载过高,网络拥塞或者其他原因导致主节点暂时失去响应,超过响应超时时间,这个时候从节点启动,承担起leader的职责,但是原先的主节点又恢复了服务。这个时候,如果没有选举机制(不能仅仅自己宣告自己是leader,还要广而告之,让其他服务器或者客户端知道自己是leader),有可能会存在两个leader节点,导致集群发生混乱
上图示例一下此类场景
主节点出现问题,那就是单点故障
传统方式是采用一个备用节点,这个备用节点定期给当前主节点发送ping包,主节点收到ping包以后向备用节点发送回复Ack,当备用节点收到回复的时候就会认为当前主节点还活着,让他继续提供服务
当主节点挂了,这时候备用节点收不到回复了,然后他就认为主节点挂了接替他成为主节点如下图
但是这种方式就是有一个隐患,就是网络问题,来看一网络问题会造成什么后果,如下图
也就是说我们的主节点的并没有挂,只是在回复的时候网络发生故障,这样我们的备用节点同样收不到回复,就会认为主节点挂了,然后备用节点将他的Master实例启动起来,
这样我们的分布式系统当中就有了两个主节点也就是---双Master,
出现Master以后我们的从节点就会将它所做的事一部分汇报给了主节点,一部分汇报给了从节点,这样服务就全乱了
在哪些场景下需要进行leader选举
若进行Leader选举,则至少需要两台机器,这里选取3台机器组成的服务器集群为例。在集群初始化阶段,当有一台服务器Server1启动时,其单独无法进行和完成Leader选举,当第二台服务器Server2启动时,此时两台机器可以相互通信,每台机器都试图找到Leader,于是进入Leader选举过程。选举过程如下
对于Server1而言,它的投票是(1, 0),接收Server2的投票为(2, 0),首先会比较两者的ZXID,均为0,再比较myid,此时Server2的myid最大,于是更新自己的投票为(2, 0),然后重新投票,对于Server2而言,其无须更新自己的投票,只是再次向集群中所有机器发出上一次投票信息即可。
在Zookeeper运行期间,Leader与非Leader服务器各司其职,即便当有非Leader服务器宕机或新加入,此时也不会影响Leader,但是一旦Leader服务器挂了,那么整个集群将暂停对外服务,进入新一轮Leader选举,其过程和启动时期的Leader选举过程基本一致。假设正在运行的有Server1、Server2、Server3三台服务器,当前Leader是Server2,若某一时刻Leader挂了,此时便开始Leader选举。选举过程如下
过程中出现了宕机、网络延迟、网络物理层断开等情况
在第三轮的选举过程后,“S1”,“S2”两个节点就断开了,他们的投票信息根本没有发送出去
此篇zookeeper的基础内容基本都包含了
了解这些基本已经入门
下一篇学习其中最核心的zab协议,理解原子性广播概念,以及zab的实现过程
面试问题,请说明zookeeper的选举机制
zookeeper选举机制
Zookeeper的Leader选举