zookeeper 概览与性能

本文根据zookeeper 概览进行整理汇总,大量加入了个人的理解,不当之处欢迎交流.

ZooKeeper是一个针对分布式应用的分布式、开源的协调服务。它公开了一组简单的原语,分布式应用程序可以在这些原语的基础上构建,以实现更高级别的服务,用于同步、配置维护、分组和命名。它被设计成易于编程,并且使用了一种类似于文件系统目录树结构的数据模型。它在Java中运行,并且有针对Java和C的绑定。

协调服务是出了名的难搞。它们特别容易出现竞争条件和死锁等错误。ZooKeeper背后的动机是为了减轻分布式应用从头开始实现协调服务的责任。

设计目标

  • ZooKeeper is simple.

    • ZooKeeper允许分布式进程(集群中的各个服务节点)通过共享的层次结构命名空间(类似于标准文件系统)进行协调.命名空间由数据寄存器组成,用ZooKeeper的说法就是znode(它们类似于文件和目录).与为存储而设计的典型文件系统不同,ZooKeeper的数据保存在内存中,这意味着ZooKeeper可以实现高吞吐量和低延迟.
  • ZooKeeper is replicated

    • zookeeper是一个分布式的服务,可以将很对的zookeeper分布式的部署在多个服务器上并组建成副本(replica)集群,提升服务的健壮性
  • ZooKeeper is ordered

    • 对于zookeeper服务来讲,数据操作是有序的(数据更改操作一定从leader节点执行,但是读取操作可以分散到各个集群中的各个副本上),每个操作都有一个成先后关心的zxid,这些可以追踪读写操作的先后顺序
  • ZooKeeper is fast

    • zookeeper的非常适合读多写少的工作负载场景,在10:1的读写比时它的性能最好.同时zookeeper集群的读取压力可以分散到集群中的各个节点上.zookeeper的读性能其实很好的原因时数据是存放在内存中的并在数据改变时会有事务提交到磁盘上,由于多节点间要做强一致性保障所以比一般的单机事务要花更多时间,数据的改变只能从leader执行,也制约了数据改动操作无法做到负载均衡.这是分布式事务一致性的本身限制不是zookeeper的技术原因

Data model and the hierarchical namespace

ZooKeeper提供的命名空间类似于标准的文件系统.名称是用斜杠(/)分隔的路径元素序列.ZooKeeper命名空间中的每个节点都用路径标识.与标准的文件系统结构不一样的是zookeeper的路径全部是绝对路径完全没有相对路径,所以任何node的path都是/开头的

下面是node的层次继承图
image

zookeeper采用高度类似文件系统的数据结构而不是重新设计一个专属的结构,极大的简化的了zookeeper的学习难度,非常容易上手.

一致性保障

zookeeper确保下面的几个保障:

  • Sequential Consistency
  • Atomicity
  • Single System Image
  • Reliability
  • Timeliness

关于它们的详细解读请看: zookeeper 一致性保障

持久化

事务日志

针对每一次客户端的事务操作,Zookeeper都会将他们记录到事务日志中,当然Zookeeper也
会将数据变更应用到内存数据库中/我们可以在zookeeper的主配置文件zoo.cfg中配置数据持久化目录,也就是事务日志的存储路径dataLogDir. 如果没有配置dataLogDir(非必
填), 事务日志将存储到dataDir(必填项)目录

Zookeeper进行事务日志文件操作的时候会频繁进行磁盘IO操作,事务日志的不断追加写操作会
触发底层磁盘IO为文件开辟新的磁盘块,即磁盘Seek.因此\为了提升磁盘IO的效率,
Zookeeper在创建事务日志文件的时候就进行文件空间的预分配,即在创建文件的时候,就向操
作系统申请一块大一点的磁盘块.这个预分配的磁盘大小可以通过系统参数
zookeeper.preAllocSize进行配置。

关于zookeeper的日志更多的信息请看:logging

快照

数据快照用于记录Zookeeper服务器上某一时刻的全量数据,并将其写入到指定的磁盘文件中.
可以通过配置snapCount配置每间隔事务请求个数,生成快照,数据存储在dataDir指定的目录
中.

有了事务日志,为啥还要快照数据?
快照数据主要时为了快速恢复,事务日志文件是每次事务请求都会进行追加的操作,而快照是达
到某种设定条件下的内存全量数据.所以通常快照数据是反应当时内存数据的状态.事务日志是
更全面的数据,所以恢复数据的时候,可以先恢复快照数据,再通过增量恢复事务日志中的数据
即可.

zookeeper的持久化机制和Redis几乎是完全一样的.同时有快照和操作日志.

性能

理论上zookeeper的性能是很不错的,官方给出的详细的说明:Performance

zookeeper集群中对于每个服务节点来讲其实有2份数据,一份是缓存在内存中,反应了当前最新的数据,例外一份就是持久化到磁盘上保证数据的可靠性.对于读操作来讲毫无疑问的是读取内存中的数据,由于zookeeper数据结构简单且数据的实际大小不大,所以读性能是十分优秀的,并且可以分散读请求的压力到多个节点,在读多写少的场景下轻松的突破上万的QPS完全没有压力,但是zookeeper的目标在于分布式一致性,那么对于写操作来讲,分布式一致性的协商和事务日志的持久化就要花一些时间了,对于写操作,单节点而言数据被更新到内存中并持久化到磁盘上,多节点间同时做了分布式一致性协商确认后才能返回给客户端最终的写操作成功回执.

详细的性能相关的文档请看: Performance

所以我对zookeeper的性能制约因素总结如下:

  • 分布式协商

    • follow数量: 对于一个zookeeper集群而言,leader只会有一个但是follow有多个,follow越多协商的成本越高,所以在满足可靠性的前提下,follow合理的数量有利于zookeeper的写性能并反应到混合读写性能上,读写比越高,follow数量的影响越小,但是follow的数量过少又会制约并发读取性能. 现在的典型的zookeeper最好采取 1 leader + 合理数量的follow + 多个obersver 的搭配. 多个obersver基本等同于follow但是不参与选举和一致性协商,可以被认为是leader的同步镜像承担读操作的压力,它可以有效弥补follow数量多了会增加协商成本但数量不够又影响读操作性能的尴尬.
  • 持久化IO限制.zookeeper是强一致性高可靠设计,那么对于每个写操作都会产生持久化操作,这时传统的机械硬盘很容易因为IO性能不好而制约zookeeper的写性能

    • 使用高IOPS的固态硬盘
    • 分离zooker的dataDirdataLogDir,数据快照和持久化操作不在一个磁盘上或者一个文件路径下,分离这它们的位置后可能降低单个磁盘的IOPS性能要求

此外一个无法回避的但是影响zookeeper性能的因素是zookeeper的故障恢复会导致重新选举的过程中会有短暂的性能下降,但是时间一般是几秒以内,文档请看: Reliability

本文原创链接:zookeeper 概览与性能

你可能感兴趣的:(zookeeper)