[关闭]
@zhuanxu 2018-03-16T11:24:34.000000Z 字数 5289 阅读 2015

ZooKeeper 设计原理

分布式系统


第一步介绍下大数据相关的知识。

大数据技术体系

大数据必备技能

大数据就业方向


介绍完大数据的一些利好后,我们来看我们迈出的第一步:zookeeper。

zookeeper 概述

什么是zookeeper?

a service for coordinating(协调) processes of distributed applications,是一个重要的基础服务,目标是从更底层提供一个简单、高性能的服务,用来按需构建同步服务


zookeeper(动物管理员),为什么叫这个名字?

zookeeper是Hadoop和Hbase的重要组件,hadoop里面各种组件都是以动物命名的,而zookeeper相当于这动物园的管理员了


zookeeper特点是什么?

提供了一组通用(generic)的,无等待的(wait-free)api,同时提供了两个重要的特性:


zookeeper 介绍

我们先来回答为什么需要 zookeeper?

在传统的应用程序中,线程、进程的同步,都可以通过操作系统提供的机制来完成。但是在分布式系统中,多个进程之间的同步,操作系统层面就无能为力了。这时候就需要像ZooKeeper这样的分布式的协调(Coordination)服务来协助完成同步。

分布式系统中对于 Coordination 提出了各种各样的需求:

解决上述coordination需求的一种方案是:为每种coordination需求都开发专门的服务。但是我们要知道一个道理:更powerful primitives的实现可以用于less powerful primitives,所以基于这个假设我们在设计coordination的服务上:我们不在实现具体的primitives,而是提供通用(generic)的API来实现满足个性化的primitives,一旦作出这种决策,带来的好处有两点:

在设计ZooKeeper的API的时候,我们移除了阻塞primitives,例如锁,基于的考虑有如下两点:

ZooKeeper由于实现了wait-free的数据对象,从而和其他基于阻塞语义(blocking primitives)有了显著的区别,ZooKeeper在组织wait-free的数据对象借鉴了文件系统的思路,将wait-free的数据对象按层级组织起来,不同只是移除了open和close这种阻塞方法。

ZooKeeper实现了pipelined architecture,提高了系统的吞吐。客户端可以同时发出多个请求,异步执行,同时保证请求的FIFO。

为了实现写请求linearizable,实现了Zab协议,一个leader-based atomic broadcast protocol,但是对于读请求,我们不适用Zab,只是本地读,这样能很方便的扩展系统。

在客户端缓存数据可以有效的提高系统性能,但是缓存的数据怎么更新呢?ZooKeeper使用watch机制,不直接操作客户端缓存,这是因为:由于Chubby直接管理客户端缓存,一旦某个客户端处理慢了(可能是挂了),会导致阻塞数据更新。针对这个问题,Chubby 使用租期来解决,一旦某个客户端有错误,不会影响更新操作太长时间,但这也只是确定了影响的上限,无法避免,而ZooKeeper的watches可以彻底解决改问题。

注:Chubby 是什么?
Google的三篇论文影响了很多很多人,也影响了很多很多系统。这三篇论文一直是分布式领域传阅的经典。根据MapReduce,于是我们有了Hadoop;根据GFS,于是我们有了HDFS;根据BigTable,于是我们有了HBase。而在这三篇论文里都提及Google的一个lock service—Chubby,于是我们有了Zookeeper。

总结起来,本文的主要内容是:

Zookeeper服务

ZooKeeper提供了client library来访问服务,client library主要做两件事:

术语:

Service overview


ZooKeeper给客户端提供了znode的抽象,客户端通过api来操作znode中存储的数据,znode的地址类似文件系统中的path,像上图中节点p_1就通过路径/app1/p_1来访问,客户端可以创建两种znode:

除此之外,创建的时候可以带sequential的flag,此时创建znode p,则会自动带上一个下标n,n是一个单调递增的数,并且满足seq(parent)>= max(children),意思是新建的node,其下标总是大于其父节点下面创建过的所有node的最大n。


watches怎么创建?

读请求上设置watch参数


watches作用?

客户端不必轮询服务器获取数据,当数据发生改变的时候,通知客户端


watches什么时候失效?

当数据发生改变通知客户端后

session关闭


watches通知了什么?

watches通知只是告知状态改变了,但是不提供改变的数据


数据模型

如图一所示:类似于文件系统,但是znodes不是用来做数据存储的,而是用来跟实际的应用映射的,像图1中,有两个应用app1,app2,app1下面实现了个简单的group membership protocol。

虽然znode设计之初不是为了存储数据,但是也可以存储一些meta-data或者configuration信息,同时znode本身会存储time stamps 和 version counters等元信息

会话(sessions)

代表client和ZooKeeper之间的网络连接,作用有:

Client API

  1. create(path, data, flags)
  2. delete(path, version) //if znode.version = version, then delete
  3. exists(path, watch)
  4. getData(path, watch)
  5. setData(path, data, version) //if znode.version = version, then update
  6. getChildren(path, watch)
  7. sync()

以上所有操作有syn和asyn两个版本。ZooKeeper的客户端保证所有写操作是完全有序的,写操作后其他client的写能看到。

在访问的znode的时候都是通过完整的path来访问的,而不是像文件系统那样通过open,close来操作文件句柄,大大简化了servers端的复杂度,不需要保存额外的信息了。

ZooKeeper guarantees

考虑场景:leader election

当新的leader产生的时候,需要改变大量的配置后,通知其他processes,需要满足两个要求:

通过锁能满足第一个需求,zookeeper的实现:

  1. 新leader改变前删除 ready znode

  2. 改变配置(通过pipeline加速)

  3. 新建 ready znode

因为写顺序的保证,其他客户端能看到ready的时候,肯定新配置也生效了,如果在更改配置中leader挂了,就不会有ready。

上面仍然有一个问题:如果process先是看到了ready,此时在读取之前,leader删除了ready,开始更改配置,那process会读取到不完整的配置了,怎么解决呢?

这是通过对通知的顺序性保证解决的,具体来说就是:如果客户端在watch一个Ready改变事件,那只有当配置改变后,才会通知client Ready有变化的事件(不是Ready删除就通知事件),这就保证了客户端收到通知,肯定是配置变化了。

另一个可能的问题是:客户端之间除了ZooKeeper之外,还有别的通信通道,场景是:

A和B在ZooKeeper上有共享数据,A改变数据后,通过其他通信手段告诉B数据改变了,此时B去读取数据,可能会读取不到改变的数据,因为ZooKeeper集群可能存在的主从延迟,解决方案是:B读之前先发个sync请求,类似于文件系统中的flush操作,让pending的写请求真正执行。

除此之外,ZooKeeper还有两个保证:

ZooKeeper 实现

作为一个 coordination,非常重要的就是高可用和数据可靠性,我们来看下如何实现的。

先来看数据的写入过程:

  1. 客户端提交写请求
  2. follower写请求交给leader,由leader作为整个事务的协调者,负责整个写入过程
  3. leader在整个事务中是通过ZAB算法保证了数据的最终一致,由leader发起事务提议(重点是一个zxid,全局递增的一个id生成器,通过zxid来达到全局时钟的效果)
  4. follower接收到leader发起的事务提议,返回收到(所有请求都是在一个FIFO的队列中)
  5. leader在收到follower的回复后,提交本次事务
  6. 客户端收到回复

此处ZAB算法是保证数据一致性的关键,我们在raft那再讲。

总结

本文主要是介绍了zookeeper是什么:一个开源的针对大型分布式系统的可靠协调系统;设计目标是:将复杂且容易出错的分布式式一致性服务封装起来,构成一个高效可靠的原语集,并以简单易用的接口提供给用户使用,其特性有:

其中一致性算法将会在raft中讲解。

你的鼓励是我继续写下去的动力,期待我们共同进步。
这个时代,每个人都是超级个体!关注我,一起成长!

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注