`

深入理解zookeeper

zk 
阅读更多

      

zookeeper概况

背景&问题

在生产环境中,为了提高服务可用性、支撑更多的用户量等,分布式应用服务都会在不同IDC多个节点上部署,我们很可能会遇到以下问题:

  • 分布在各个机器、IDC的应用程序如何能高效读取、修改配置?
  • 当配置变更时,各节点应用如何快速发现变化、及时响应处理?
  • 如何在应用程序部署的各个节点中,选举一个节点,作为leader,执行协调相关操作? leader挂掉时,其他节点能重新发起leader选举? 如何避免脑裂? 如何处理网络分区?
  • 当某个节点异常挂掉时,如何及时发现?

第1、2点在节点数较少、对性能要求不高的情况下,我们可以通过将配置存储在mysql+定时轮询解决。若对性能要求较高我们就需要结合cache、agent、配置变更notify、mysql等组件实现一套配置系统来解决,如淘宝的diamond

第3、第4点,在复杂的分布式环境中,我们会遇到高网络延时、网络波动、磁盘故障、机器宕机、机器半死不活、机房断电、网络分区等一系列问题,同时要避免数据不一致、脑裂,还要追求高吞吐、低延时,最大程度减少因选举leader导致服务不可用时间等,最糟糕的是分布式理论FLP(consensus is impossible with asynchronous systems and even one failure)、CAP(consistency,high availability,partition-tolerance)告诉我们在设计上需要权衡取舍,这些如果让业务应用程序来处理,就具有一定的复杂性。

因此,这类复杂问题不适合应用程序自己解决,应用程序需要一个God,一个值得信赖的Oracle,同时God提供的Service应该尽量简单、易理解、高性能、易扩展。

Yahoo的工程师们为了解决应用这些问题,设计实现了zookeeper,为什么叫zookeeper? 因为yahoo内部不少分布式系统命名是动物名字,同时分布式环境中的复杂、混乱跟动物园(zoo)是不是有点类似?而zookeeper就是维持、管理整个动物园的秩序,这就是zookeeper的名称的来历。

ZooKeeper是一个分布式管理服务,可为应用提供配置管理、名称服务、状态同步、集群管理等功能,我们的应用场景主要是配置管理、分布式锁。

  • 为什么apache给它定义是个分布式协调式服务,而不是存储服务?它的设计目标定位是什么?
  • 它可以当存储服务来使用吗? 它的数据模型是怎样的? 如何持久化存储的?
  • zookeeper服务端的读写流程是怎样实现的?
  • zookeeper c api是如何实现的?
  • 如何通过zookeeper实现分布式锁、Leader Election?
  • 在生产环境实践中我们遇到了哪些问题?如何优化zookeeper性能? 对zookeeper进行监控?

本文将结合zookeeper源码(3.4.6)、在生产环境实践经验,通过分析以上问题来深入理解zookeeper,以及分享我们在实践中遇到的问题及经验。

首先,我们一窥zookeeper全貌,了解下其总体架构及设计目标。

zookeeper架构

zookeeper架构

zookeeper集群节点数量一般由奇数个节点组成,节点角色由follower和leader组成,所有写请求需转发到leader,每次写请求需集群一半以上节点应答成功才写入成功,读请求在任意一台follower节点上都可以处理,只要集群中有一半以上的节点存活、并能相互通信,zookeeper集群就可以持续提供服务,因此具有较高的可用性。节点数量越多,可用性会进一步提高,但是会影响写性能,因此在生产环境中一般部署5台。 zookeeper提供的接口类似nosql系统,常用的接口有get/set/create/getchildren等,接口简单易用。

zookeeper设计目标

简单

zookeeper数据模型简单,易懂,类似文件系统的层次树形数据结构,存储数据未做shard分散到多机,而是各单机完整存储整个树形层次空间上所有路径的节点数据,数据全部保存在内存,因此可提供高吞吐量、低延迟的服务,也意味着zookeeper不适合保存大节点数据。

高可用、高性能读

因单机上保存了所有数据,若没有多机之间数据同步复制机制,zookeeper系统可用性将极低,因此zookeeper在设计上一个重要目标是可复制的,各节点通过zookeeper atomic broadcast算法选举leader,同步数据。所有写请求follower节点都需转发给leader,读请求在任意一台follower节点上都可以处理。

有序

zookeeper通过基于tcp连接、写请求由leader处理等机制提供有序保证,基于有序机制,zookeeper可以提供同步原语,实现分布式锁等机制。

zookeeper数据模型

存储系统常见的数据模型有关系型表格型(Relational Model)、层次树型(Hierarchical model)、扁平型(Flat model)、网络型(Network Model)、对象型(Object-oriented Model).

五种常见存储模型图

zookeeper的数据模型是层次型,类似文件系统,但是zookeeper的设计目标定位是简单、高可靠、高吞吐、低延迟的内存型存储系统,因此它的value不像文件系统那样会适合保存大的值,官方建议保存的value大小要小于1M,提供的接口类似nosql存储系统(key是路径)。

zookeeper层次模型

那么zookeeper的层次模型是通过什么数据结构实现的呢? get、set、getchildren的时间复杂度又分别是多少呢? 通过阅读zookeeper server源码,zookeeper是基于ConcurrentHashMap实现的,path是key,value是DataNode,DataNode保存了value、children、 stat等信息。

  1. zookeeper database模型的调用链路
  2. ZKDatabase
  3. DataTree
  4. ConcurrentHashMap<String,DataNode> nodes =newConcurrentHashMap<String,DataNode>();
  5. DataNode
  6. data,acl,stat,children
  7. classStat{
  8. long czxid;// created zxid
  9. long mzxid;// last modified zxid
  10. long ctime;// created
  11. long mtime;// last modified
  12. int version;// version
  13. int cversion;// child version
  14. int aversion;// acl version
  15. long ephemeralOwner;// owner id if ephemeral, 0 otw
  16. int dataLength;//length of the data in the node
  17. int numChildren;//number of children of this node
  18. long pzxid;// last modified children
  19. }

ConcurrentHashMap是线程安全的hash table,采用了锁分段技术来减少锁竞争,以提高性能。其结构如下图所示,由两部分组成,Segment和HashEntry,锁的粒度是Segment,每个Segment 对象包含整个散列映射表的若干个桶,散列冲突时通过链表来解决.

ConcurrentHashMap

因此zookeeper在使用ConcurrentHashMap时其各接口期望时间复杂度如下:

  • get:O(1)
  • create/set:O(1)
  • getchildren:O(1)

zookeeper持久化存储

从数据模型我们知道zookeeper所有数据都是加载都内存,基于ConcurrentHashMap构建一颗DataTree,那么zookeeper要保证机器重启数据不丢失就需要实现持久化存储,而zookeeper的持久化实现是通过snapshot、txnlog实现的,snapshot是zookeeper内存数据的完整镜像,zookeeper在运行中会定时生成,txnlog是快照时间点之后的事物日志,zookeeper在重启时,通过snapshot和txnlog重建DataTree. 下图是运行中的zookeeper集群的生成的数据文件。

zookeeper数据文件

snapshot和log文件分布保存在哪?保留多少个snapshot和log文件? 什么时候清理废弃的snapshot和log 文件? 这些都可以通过在zookeeper的zoo.cfg配置文件中指定,dataDir指定snapshot路径,dataLogDir指定事物日志路径,事物日志对zk吞吐量、延时有着非常大的延时,建议datadir与dataLogDir使用不同的设备,避免磁盘IO资源的争夺,影响整个系统性能和稳定性。autopurge.snapRetainCount项表示保留多少个snapshot,每个snapshot快照清理间隔小时可以通过autopurge.purgeInterval来指定。

snapshot的生成和log文件的写入是在SyncRequestProcessor类中实现的,事物日志类TxnLog,快照类FileSnap,事物日志会追加到TxnLog,当记录数大于1000会刷到磁盘,当写入log数大于snapCount/2+randRoll(nextInt(snapCount/2)时,会开启线程将DataTree dump到磁盘,具体实现逻辑如下:

  1. if(zks.getZKDatabase().append(si)){
  2. logCount++;
  3. if(logCount >(snapCount /2+ randRoll)){
  4. randRoll = r.nextInt(snapCount/2);
  5. // roll the log
  6. zks.getZKDatabase().rollLog();
  7. // take a snapshot
  8. if(snapInProcess !=null&& snapInProcess.isAlive()){
  9. LOG.warn("Too busy to snap, skipping");
  10. }else{
  11. snapInProcess =newThread("Snapshot Thread"){
  12. publicvoid run(){
  13. try{
  14. zks.takeSnapshot();
  15. }catch(Exception e){
  16. LOG.warn("Unexpected exception", e);
  17. }
  18. }
  19. };
  20. snapInProcess.start();
  21. }
  22. logCount =0;
  23. }
  24. }
  25. toFlush.add(si);
  26. if(toFlush.size()>1000){
  27. flush(toFlush);
  28. }

从zookeeper持久化的基本实现可知若写请求较大会频繁生成快照,同时因为toFlush是同步刷新数据到磁盘的,所以会影响吞吐率、延时,这也是为什么txnlog建议使用性能较好的存储硬件的原因(如SSD)。

zookeeper核心角色及概念

leader

follower

observer

session

watcher

access control

zookeeper server读写流程分析

在zookeeper的服务端实现中,通过抽象出leader、follower、observer共性特点,读写请求的处理流程可以按照功能拆分成各阶段(pipeline),每个processor负责处理其中一个阶段,采用设计模式的职责链形式,一个processor处理完,通过队列分发到下一个processor中。processor相当于工厂各元部件,而leader、follower、observer只是使用、组装的各元部件不一致,但他们可以高度复用相同的元部件,精简实现,减少代码冗余。

职责链处理类介绍

PrepRequestProcessor

此处理类根据请求的命令(create,set等)负责生成事物请求信息数据结构request,统计正在进行的事物等。

FollowerRequestProcessor

此处理类负责将写请求分发给leader.

CommitProcessor

SyncRequestProcessor

如前面持久化存储所述,此处理类负责持久化存储,将批量事物日志刷新到磁盘和定时生成快照。

SendAckRequestProcessor

此处理类在收到写请求提议后,回复ACK给leader.

ProposalRequestProcessor

此处理类负责将所有写请求转发给follower节点。

ToBeAppliedRequestProcessor

FinalRequestProcessor

此处理类如名字所言,是请求流行线式处理最后一环,负责处理查询请求(从zkdatabase的DataTree读取数据)和写事务请求。

zookeeper读流程

zookeeper写流程

zookeeper c api

总结

参考资料

分享到:
评论

相关推荐

    zookeeper3.4.6 pdf文档

    `zookeeperInternals.pdf` 深入剖析了 Zookeeper 内部工作原理,可能包括其数据模型、选举算法、客户端通信机制等,适合希望深入理解 Zookeeper 的读者。 `zookeeperTutorial.pdf` 和 `zookeeperStarted.pdf` 是...

    深入分析zookeeper实现原理

    在深入了解Zookeeper之前,我们先简要介绍下Zookeeper以及它所处的分布式环境的一些特点。 **分布式环境的特点:** - **分布性:** 系统由多个通过网络连接的节点组成。 - **并发性:** 多个节点可以同时执行任务...

    深入浅出Zookeeper

    在深入了解Zookeeper之前,我们不妨先从一位实践者的视角出发。最初接触到Zookeeper时,很多人可能会感到困惑,尤其是当其与Kafka这样的分布式消息系统结合使用时。例如,对于Zookeeper如何在集群中进行调度、客户端...

    zookeeper的maven形式的源码包。

    在这个“zookeeper的maven形式的源码包”中,我们可以深入理解ZooKeeper的实现机制,以及如何将其集成到Maven项目中进行调试和开发。 首先,ZooKeeper基于Java编写,因此源码包中的内容主要是Java源文件。源码包...

    【Zookeeper管理工具】

    对于开发者来说,深入理解Zookeeper管理工具的源码可以帮助我们更好地定制和优化工具。通过阅读源码,我们可以了解到如何与Zookeeper服务器通信,如何解析和展示数据,以及如何实现图形化操作的逻辑。这对于理解和...

    zookeeper-3.8.0安装包下载

    5. src:源代码目录,如果你需要深入理解 Zookeeper 内部工作原理或者进行定制开发,可以查阅这里的代码。 6. lib:依赖的库文件,包括各种 JAR 包,这些是 Zookeeper 正常运行所必需的。 7. logs:日志文件默认保存...

    ZooKeeper-分布式过程协同技术详解 和从Paxos到Zookeeper

    总的来说,《ZooKeeper:分布式过程协同技术详解》和《从Paxos到Zookeeper:分布式一致性原理与实践》两本书提供了深入理解ZooKeeper和分布式一致性理论的全面资源。无论是理论探讨还是实战指南,它们都为读者提供了...

    Zookeeper源码剖析:深入理解Leader选举机制

    1. **先使用框架**:先通过官方文档了解Zookeeper的基本使用,建立基础认知。 2. **抓住主线**:从一个简单的示例开始,追踪源码的主要流程,绘制流程图,避免陷入细节。 3. **画图做笔记**:关注核心功能,深入源码...

    zookeeper 3.6.3 源码下载

    在深入理解源码之前,我们需要先了解ZooKeeper的基本概念和工作原理。 **ZooKeeper的基本概念** 1. **节点(ZNode)**:ZooKeeper 的数据存储结构类似文件系统,由一系列的节点构成,每个节点称为ZNode。每个ZNode...

    Zookeeper

    深入理解Zookeeper,需要对其源码有一定的了解。例如,ZAB协议的实现、Znode的创建与删除流程、Watcher的注册与触发机制等。通过阅读源码,可以更清楚地理解Zookeeper内部的工作原理。 ### 6. 工具支持 Zookeeper...

    ZooInspector 用于查看zookeeper的节点信息

    **ZooInspector 知识点详解** ...总之,ZooInspector 是 ZooKeeper 管理和调试的重要工具,通过其直观的界面,我们可以深入了解 ZooKeeper 的数据结构和状态,从而优化和保证分布式系统的稳定运行。

    zookeeper资料.zip

    这份“zookeeper资料.zip”包含的资源无疑为我们深入理解Zookeeper提供了丰富的学习材料。 Zookeeper的核心概念包括节点(Znode)、会话(Session)和观察器(Watcher)。Znode是Zookeeper中的基本数据单元,类似于...

    zookeeper测试小程序

    在这个测试程序中,我们可以深入理解Zookeeper的客户端API以及它是如何与服务器进行交互的。 首先,我们要了解Zookeeper的基本概念。在Zookeeper中,数据存储在树形结构的节点中,称为ZNode。每个ZNode都可以存储...

    ZooKeeper深入浅出.pdf

    ZooKeeper是一款分布式的、开放源码的分布式应用程序协调服务,最初是由Google设计实现...作者提到了自己最初对ZooKeeper的认识,以及通过学习和实践逐渐深入理解的过程,鼓励大家分享知识,共同促进知识的更新与进步。

    zookeeper源码

    总结,深入理解Zookeeper源码对于掌握其工作原理和优化分布式系统至关重要。通过对Zookeeper架构、ZAB协议、选举机制、数据模型等核心概念的探究,开发者可以更好地运用Zookeeper解决实际问题,提升系统性能和稳定性...

    zookeeper-windows-3.4.6

    此时,就需要对Zookeeper的集群配置有深入理解,包括ensemble(集群)的设置、quorum(多数派)的计算以及数据同步策略等。 总结,Zookeeper在Windows 3.4.6版本下为Dubbo开发提供了强大的支持,它的易用性和稳定性...

    zookeeper压缩包

    通过对压缩包中的源码和文档进行研究,可以深入了解Zookeeper的内部工作原理,以及它如何与Dubbo的各个组件进行交互,这对于优化分布式系统的性能和稳定性非常有帮助。同时,掌握Zookeeper的使用也能为开发人员在...

    zookeeper解压版安装包

    **Zookeeper概述** Zookeeper是Apache软件基金会的一个开源项目,它提供了一个分布式的,开放源码的分布式应用程序协调服务。...通过深入理解Zookeeper的工作原理和特性,我们可以更好地应对分布式环境中的各种挑战。

Global site tag (gtag.js) - Google Analytics