ZooKeeper 基本架构
ZooKeeper 服务通常由奇数个 ZooKeeper 实例构成,其中一个实例为 leader 角色,其他为 follower 角色,它们同时维护了层级目录结构的一个副本,并通过 ZAB(ZooKeeper Atomic Broadcast)协议维持副本之间的一致性。ZooKeeper 将所有数据保存到内存中,具有吞吐率高、延迟低等优点。ZooKeeper 读写数据的路径如下:
读路径:任意一个 ZooKeeper 实例均可为客户端提供读服务。ZooKeeper 实例数目越多,读吞吐率越高。
写路径:任意一个 ZooKeeeper 实例均可接受客户端的写请求,但需进一步转发给 leader 协调完成分布式写。ZooKeeper 采用了 ZAB 协议(可认为是一个简化版的 Paxos 协议),该协议规定,只要多数 ZooKeeper 实例写成功,就认为本次写是成功的。这意味着,如果一个集群中存在 2N+1 个 ZooKeeper 实例,只要其中 N+1 个实例写成功,则本次写操作是成功的,从容错性角度看,这种情况下,集群的最大容忍失败实例数目为 N。由于 ZAB 协议要求多数写成功即可返回,因此 2N+1 和 2N+2 个节点的集群具备的容错能力是相同的(最大容忍失败实例数均为 N),这是建议 ZooKeeper 部署奇数个实例的最主要原因(多一个节点并没有提高容错能力)。需要注意的是,ZooKeeper 实例数目越多,写延迟越高。
当 leader 出现故障时,ZooKeeper 会通过 ZAB 协议发起新一轮的 leader 投票选举,保证集群中始终有一个可用的 leader。
ZooKeeper 中多个实例中的内存数据并不是强一致的,它采用的 ZAB 协议只能保证,同一时刻至少多数节点中的数据是强一致的。为了让客户端读到最新的数据,需给对应的 ZooKeeper 实例发送同步指令(可通过调用 sync 接口实现),强制其与 leader 同步数据。
在 ZooKeeper 集群中,随着 ZooKeeper 实例数目的增多,读吞吐率升高,但写延迟增加。为了解决集群扩展性导致写性能下降的问题,ZooKeeper 引入了第三个角色:Observer。Observer 并不参与投票过程,除此之外,它的功能与 follower 类似:它可以接入正常的 ZooKeeper 集群,接收并处理客户端读请求,或将写请求进一步转发给 leader 处理。由于 Observer 自身能够保存一份数据提供读服务,因此可通过增加 Observer 实例数提高系统的读吞吐率。由于 Observer 不参与投票过程,因此它出现故障并不会影响 ZooKeeper 集群的可用性。Observer 常见应用场景如下:
作为数据中心间的桥梁
由于数据中心之间的确定性通信延迟,将一个 ZooKeeper 部署到两个数据中心会误报网络故障和网络分区导致 ZooKeeper 不稳定。然而,如果将整个 ZooKeeper 集群部署到单独一个集群中,另一个集群只部署 Observer,则可轻易地解决网络分区问题。
作为消息总线
可将 ZooKeeper 作为一个可靠的消息总线使用,Observer 作为一种天然的可插拔组件能够动态接入 ZooKeeper 集群,通过内置的发布订阅机制近实时获取新的消息。
版权声明: 本文为 InfoQ 作者【穿过生命散发芬芳】的原创文章。
原文链接:【http://xie.infoq.cn/article/25270610814efee1909687efa】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论