Hadoop生态系统为开源届提供很多优秀软件,zookeeper便是其中一员。
前段时间项目中用到了zookeeper,主要是用作服务的注册和发现使用方式类似阿里的dubbo。实际上zookeeper的功能不仅仅只有这些内容,它提供了一系列非常方便使用的功能,后面会提到。这篇文章仅仅是我个人的一点儿理解,如有错误烦请指正,以免给别人误导。
1、zookeeper是什么
zookeeper的名字很有趣被称为动物管理员,这是因为Hadoop生态系统中很多软件的名字都是动物,hadoop本身就是小象的意思,还有hive小蜜蜂,pig。zookeeper作为一个分布式协调系统在hadhoop中被广泛的应用,其中HBase默认带有zookeeper。zookeeper主要功能有配置维护、分布式锁、选举、分布式队列等,并且zookeeper本身可以是一个集群,提供了高可用性。这一切的功能都离不开zookeeper的数据模型。
2、zookeeper数据模型
zookeeper提供的命名服务看起来和一个unix的文件系统非常相似,下面是从官网复制的一张图:
其中的每个节点称为znode,每个znode节点既可以包含数据又可以包含子节点,由于zookeeper被定位为协调程序因此znode中的数据通常存储的是非常小的数据,比如状态信息,位置信息等等。znode中有一个很重要的概念——节点类型,znode有两种类型的节点:临时节点,永久节点。其中这两种节点又分为有序和无序,重点讲一下临时节点,因为zk中很多基础的功能都是基于临时节点实现的,client在和zookeeper连接的时候两者之间会建立起session,session的状态由zookeeper服务端维护,临时节点的特点是随着session的超时服务端会将client建立的所有临时节点移除,而永久节点即使客户端退出节点也不会消失,同时临时节点不能有子节点但是可以挂载数据。结合watcher机制可以实现非常丰富和灵活的功能。
3、zookeeper集群结构
zookeeper本身支持单机部署和集群部署,生产环境建议使用集群部署,因为集群部署不存在单点故障问题,并且zookeeper建议部署的节点个数为奇数个,只有超过一半的机器不可用整个zk集群才不可用。zookeeper集群中主要有两个角色leader和flower,每个客户端可以连接集群中的任何一个zookeeper节点,同时从其上面read信息,但是针对write操作,flower节点会转发给leader,由leader负责原子广播,从而保证集群中各个节点的数据一致性,zookeeper中规定只有当多余一半的节点同步完成整个write操作才算完成。也就是说可能会有少于一半的数据不是新数据,因此zookeeper中不是强一致性而是实现的最终一致性。但是客户端可以使用sync来强制读取最新的数据。
4、replaction
zookeeper中的高可用性是通过数据冗余和实现的,也就是一份数据存在多个节点中,zookeeper中要求同一份数据需要在超过一半的节点上存在,只有这样才能实现对宕机数量的容忍度更高。zk建议配置奇数个节点,是因为在flower同步数据和进行leader选举的时候都要求有超过一半完成或同意才算ok。举例来说,假如有3个节点,至少需要有2个节点正常,就是容忍度为1(允许宕掉的节点数),有4个节点,至少需要有三个节点正常,容忍度同样为1,多出来一个机器但是容忍度相同在任何时候看来都得不偿失。因此zk建议部署奇数个节点,但这不是强制。另外再看一下为什么写操作的时候要求至少有超过一半节点commit成功整体才成功,假如有2t+1个zk节点,也就是必须有t+1个节点commit成功才算成功,因为只有这种情况下才能达成至少有一个节点存有前后两次的更新操作(两次t+1节点至少会重复一个)。zookeeper使用zab算法实现数据的原子广播,并且每次write会写日志然后更新缓存,每个zk节点维护一个zxid,zxid是一个全局变量,随着znode的每一次改变而递增,当leader挂掉的时候,剩余的flower选择zxid最大的节点作为新的leader,在新leader提供服务前还需要一次数据恢复,新leader只是拥有最多的数据,但不一定拥有最新的数据,因此leader和flower的数据需要同步到最新的状态,通过合并的过程完成整个数据的恢复。
上图5个zk节点允许两个宕机,其他三个节点总是能恢复出来ABCDE。
#p#
5、Watch机制
zookeeper允许客户端对znode节点或者节点中的数据设置监听器,当znode改变的时候服务器触发监听,客户端完成一个回调做自己需要处理的逻辑。zookeeper中的watch是一次性的,也就是当监听触发后,需要再次应用watcher,下次才能在收到变化的通知。exists,getData,getChildren接口都可以指定是否应用watcher,可以使用默认的watcher或者自定义watcher。触发watcher的可以为create、delete、setData、setACL。
6、配置管理
如果是单机或者几台机器,当应用的配置项变更的时候,可能通过手动的方式去修改一下,但是假如一个集群中有成百上千个应用节点,如何才能保证快速无差错的完成配置项的变更。zookeeper的出现可以轻松地解决这个问题
每个节点在zk上建立永久型znode并写入配置项,然后监听该节点下数据的变化,一旦其他客户端修改了其中的数据,所有的监听客户端都会收到变更通知。
7、Leader选举
zookeeper本身提供leader选举机制,大概的思路是所有的节点创建临时有序的znode然后监听所有节点的变化情况,获取最小序号和自己创建的序列作比较,如果自己为最小则当选为leader,当主动删除自己创建的节点或者leader宕机后,临时节点消失,该变化会被其他存活的节点获取到从而触发第二次的leader选举,依次类推。实际上zookeeper提到的很多recipes curator都提供了很好的实现(除了两阶段提交),同时基于底层的zookeeper api开发应用需要考虑的东西很多,curator对这些都提供了封装,所以如果要编写zookeeper应用推荐使用curator。
leader应用的场景很广泛,curator提供了两种不同的选举实现,一种是轮询做leader,另外一种是永久获取leader权直到退出,两种选举实现可以应用在不同的集群应用中。HBase中使用的是获取leader的永久权