Zookeeper系统应用越来越广泛,在同一领域内开源软件方面基本没有其他选择处于垄断地位,但是实际用过的人都会觉得这个软件属于可用但又不那么好用的类型。本文是本人结合自己的实际使用经验与思考,同时参考真正大牛对这个系统的分析与评价进行的总结,主要还是想归纳一下真正的使用需求并思考相应对策与改进的办法。
1.常见应用场景
先归纳一下工程应用中常见的Zookeeper使用场景(以下简称ZK),这里按照个人感觉应用的频率从高到低排序说明。
可靠存储
在实际使用中可以表现为配置管理、名字服务,这种应用完全是因为ZK多备份的可靠性强。当然也可以利用回调机制在数据变更时可以进行全体通知。实现起来非常简单而且很有效,所以是应用最广的场景。
集群管理
利用ZK的通讯与回调机制完成分布式集群的机器状态监视,甚至很多系统中做主从备份时都会在ZK中注册以方便做热备切换。
服务注册发现管理
由可靠存储加上通知回调机制其实满足了服务注册发现的最基本需求,某些在本人看起来不那么靠谱的应用场景,居然也在采用ZK实现。大有一统天下之势,所有类似的需求都开始采用ZK方案,比较出名的系统比如国内的Dubbo和国外的Kafka(居然还把ZK用在了负载均衡上面)、jStorm、Heron(twitter)等等
选主服务
选主服务是ZK参考的原始系统Chubby设计出来最初的应用需求,当时是满足BigTable的master选主。ZK最初也是用在HBase里面,而后所有需要选主服务的都在采用,很多KV系统用来方便从多节点中选择一个中心节点(但是本人还真没找到什么)。
需要注意的是有时选主服务在讨论里也被称为分布式锁的一种,很容易混淆概念。的确使用ZK来实现选主服务(实现方法最好跟分布式锁的方法完全一样,这里官方文档都曾经犯过错误)客观上遵循了时间优先原则,但是实际需求并非一定要满足这条,只要保证关键的唯一性就可以了,因此与同步意义上的锁很是有不同的。分布式同步机制
即真正的分布式锁,但是实际应用并不常见。本人实现过几次,目前准备运用在表单提交的同步上。
负载均衡
2.特性设计与优势
ZK主要使用场景远不是满足最初设计时对一致性调解的需求,这么受欢迎是因为其灵活的特性设计,只要简单组合就能满足很多种需求,同样将特性的受欢迎程度按照个人感觉从高到低进行说明
通知回调机制
通过创建节点与设置Watcher可以很方便的建立回调通知。ZK的所有应用都基于这个特性,没有这个机制那么机器监控相关的应用都不能处理,也就不会诞生后来在服务注册发现相关的使用方法。实际上为分布式系统提供节点间回调通知方法的系统真的很少,甚至可能只有ZK(大家可以提供一些其他答案?)
可靠存储
系统设计最初的需求之一,也是ZK特性中实现最好的部分,作为可靠存储ZK基本没出现过问题,仅此一项就可保证其的流行。
连接状态维护
ZK自动维护了客户端所在的应用与服务器通信连接状态的变化,可以比较简单地维护系统中的成员通信情况。主要是不需要自己再去处理麻烦的通信状态监控问题,比如断线后自动释放节点并产生回调。
文件系统模型
提供文件接口模型而不是锁接口,更具通用性。文件系统模型中文件与目录的概念可以映射多种含有层级关系的其他模型
自增长序列
这点包含了锁的本质,但是因为zk的模型设计导致判断与仲裁需在客户端进行
3.实现技术选择与优点
zk本身的系统特性设计很出色,同时选择的实现技术也比较扎实,可谓蕴含相当的分布式系统工程经验在其中。下面结合个人理解讨论下这些实现技术有哪些特别优点与选择时可能的设计思路。
通讯机制与状态的实现
基于jute进行编解码处理保证通用性,服务器端通信使用nio或netty都是标准选择。Zab协议与Paxos
zk使用Zab协议保证部署的多台机器间构成的整体系统的一致性与可靠性。这个分布式协议类似Paxos但是更加具体有效,实际上Paxos工程实现会碰到很多协议中没有定义的问题,G家员工为在Chubby中使用Paxos算法甚至专门发了一篇文章来说明Paxos工程化踩了多少坑。
Zab协议中将选主阶段与正常运行之间的阶段用catch up方式进行弥补,而关键的选主阶段使用了一个极其工程化的算法“fast leader election”(这个算法似乎没有经过形式化证明),这个算法足够粗暴有效,实现起来很简单。
最近Paxos的工程简化版算法Raft很火,所有考虑使用Paxos的系统都在实现Raft协议,其过程与Zab协议很类似,但是选主算法更加简单(可能实现结果是比Zab选主更慢)而且无法如Zab一样简单替换这个部分的算法。个人看法是Zab协议比Raft更容易理解,而且容易工程实现。(为何没有Raft火爆?值得研究,但是Raft目前还没有工业级的系统验证!)使用JVM
zk作为一个以稳定性与一致性为主的系统,性能上面肯定有一点损失。相信大家实现这种系统首先都会考虑要利用语言本身的速度优势尽量弥补系统的性能损失,于是我们就能看到很多c++实现的类zk系统(比如Chubby),但是这些新系统却没有zk的普及率。
可以说zk的流行中很重要的一点就是牺牲部分可能的性能使用JVM作为底层。正是因为虚拟机的使用屏蔽了各种异构系统底层,让zk可以很容易的稳定部署在多台配置性能都可能各异的机器上。个人理解这也是为什么现在那么多分布式系统都基于JVM技术栈,分布式系统需求的机器多,不可能所有配置都一样,而且机器都需要很容易进行物理替换或是系统升级,目前还只有JVM可以非常简单的提供这种等级的虚拟化屏蔽。
当然最近docker容器技术大放异彩,轻量级虚拟化方案以极快的速度兴起,让各种异构系统有了更简单可定制的底层虚拟化方式,也许有可能改变分布式系统的底层技术栈。