上篇博文描述了基于ZooKeeper构建互联网大规模配置系统的基本概念,并对ZooKeeper做了简单的介绍。这里谈谈ZooKeeper的一些关键技术以及用ZooKeeper构建大规模配置系统的细节,最后讲述我们在构建系统过程中的遇到问题及其解决思路,仅作参考,希望对您有所帮助。

         提到zookeeper,我们不得不提起Paoxs算法LesileLamport。Paoxs算法是zookeeper的灵魂,这个算法是Leslie Lamport在1990年提出的一种基于消息传递的一致性算法。Paxos 算法解决的问题是一个分布式系统就某个值达成一致。典型的场景就决定zookeeper中的leader。算法具体可参见http://zh.wikipedia.org/zh-cn/Paxos%E7%AE%97%E6%B3%95  

         集中式的配置管理在应用集群中是非常常见的,一般公司都会实现一套集中的配置管理中心,应对不同的应用集群对于共享各自配置的需求,并且在配置变更时能够通知到集群中的每一个机器。应用Zookeeper很容易实现这种集中式的配置管理,比如将APP1的所有配置配置到/APP1这个节点下,APP1所有机器一启动就对/APP1这个节点进行监控,并且实现回调方法Watcher,那么在zookeeper上/APP1下节点数据发生变化的时候,每个Client机器都会收到通知,Watcher方法将会被执行。以上这个例子只是简单的粗颗粒度配置监控,细颗粒度的数据可以进行分层级监控,这一切都是可以设计和控制。它的具体示例图如下:


         如图中/APP1目录下就项目APP1所有配置的信息,每个配置都是一个节点。Watch就是应用ZooKeeper来监控APP1节点数据变化。Watch可以理解为一个分布式的回调,当client关心的节点发生变化时,zookeeper将会把消息传回到client,并导致client的消息处理函数得到调用。zk的任何一个读操作都能够设置watch,例如:getData(), getChildren(), exists()

可以watch的event包括如下的二种:

n  KeeperState:Disconnected、SyncConnected、Expired

n  EventType:None、NodeCreated、NodeDeleted、NodeDataChanged、NodeChildrenChanged

         Zookeeper的使用主要是通过创建其jar包下的Zookeeper实例,并且调用其接口方法进行的,主要的操作就是对节点的增、删、改操作,监听数据节点的变化以及处理。它的简单示例如下图所示:

         上面对ZooKeeper的一些基本常识以及基本编程方法,下面谈谈我们在搭建集群配置系统中遇到的两个主要问题,以及它的解决思路。

问题1:ZooKeeper的session超时问题。

         超时问题是任何分布式应用程序都需要考虑到的问题,ZooKeeper也不例外。由于网络中断一段时间,当它自动恢复过来时候,如果这段时间大于设置的Session超时时间,此时就会产生超时异常。ZooKeeper客户端和服务器是基于长连接的方式,并用心跳保持连接,一旦遇到超时问题,这个连接就无效了。一般解决思路大致有如下三种:

l  在程序中显式用try和Catch主动获取超时异常,然后将客户端和服务器重新连接,前提是在您应用程序中要缓存一些重新连接需要的属性。

l  在程序中启动一个后台线程和ZooKeeper服务器进行通信,这个线程可以做数据的同步,同时也起到一个心跳作用。当检查到超时异常,程序重新连接ZooKeeperServer。

l  最优雅的一种方式,监控ZooKeeper最上层的父节点,当遇到超时异常时,此Watch的回调方法的参数event的属性KeepState包括了Expired,也就是超时异常,在此你可以重新连接服务器。

问题2:ZooKeeper和应用程序数据同步问题。

         ZooKeeper会协调应用程序的配置的一致性。但是应用程序是否需要始终需要获取配置的最新信息呢?显然不是。一个程序对外提供服务,它可能部署在10台机器上。当它有了新版本更新时,它的一些配置需要重新修改。项目版本更新时,总是先停掉部分机器,一批批的进行版本更新。如果项目始终获取的最新的配置信息时候,一些老版本项目会获取最新配置导致运行出错。这样的思路一般解决思路有如下:

l  ZooKeeper是的节点是带版本信息,项目一个版本可以和节点的一个版本进行对应。

l  将修改配置分为两种情况:修改ZooKeeper服务器配置,但是客户端已经运行配置不做修改;在修改ZooKeeper服务器配置,同时修改客户端的配置。