Zookeeper和跨数据中心分布式协调

EipsteinDavid 发布于15天前 阅读172次
0 条评论

1. Introduction

不记得什么时候看了饿了吗异地多活改造[10],萌生了对跨数据中心的解决方案学习和了解,这几天抽空阅读了一些资料,主要是基于文献[8],向大家介绍Zookeeper跨数据中心解决方案。本文将核心介绍如下内容:

  1. 什么是Sequential consistency(顺序一致性)?
  2. Zookeeper如何实现Sequential consistency的 ?
  3. 分布式协调服务常见的跨数据中心方案有哪些 ?各自的优缺点是 ?

2. Sequential Consistency

首先看看什么是顺序一致性?Lamport老爷子的说法[1]:

the result of any execution is the same as if the operations of all the processors were executed in some sequential order, and the operations of each individual processor appear in this sequence in the order specified by its program.

翻译过来的意思就是[5]:

任意一种可能的执行的结果和 某一种 所有的处理器的操作按照顺序排列执行的结果是一样的,并且每个独立的处理器的操作都会按照程序指定的顺序出现在操作队列中。

Lamport老爷子的解释项如此,云里雾里,其实大白话就是:

多线程程序在多个核心运行,其只有保证顺序一致性,才能保证正确性,那怎么样才是满足顺序一致性的呢?首先,程序保证Program Order(代码顺序),也就是代码顺序不动它,不要乱序,多个线程在操作系统的调度下交错的运行,如果多核运行的结果和此程序在单核新上交错运行的结果是一样的,那么就是顺序一致的。

实际上Lamport就是这么粗暴的解释,至于好不好理解,仁者见仁智者见智。

我还是比较喜欢从Memory order的角度去解释,可以参考文献[6] chapter3,这里就不贴原文,说个大白话的解释吧:

  • 没有乱序,所有的Program Order是被保持的
  • 如果operation A 在 operation B前面,那么所有CPU核心看operation A的操作结果先于operation B的操作结果(注意这里只约束了看到的先后顺序,并没有规定operation A操作之后,所有CPU核心都能看到操作结果)
  • 所有CPU核心看到所有共享变量的value变化的顺序是一致的

上面的描述不一定准确,而且缺乏例子,所以还是其实建议读者参考文献[7],对照的线性一致性,对比理解,文献[6、7]已经已经解释的比较清楚了,这里就不赘述了。

3. Zookeeper

Zookeeper是一个分布式协调服务的组件(同类型的还有Chubby、Etcd等),Zookeeper实现的顺序一致性,这样对于实现锁等逻辑是非常必要的。

  • writes: 实现了Linearizable(线性一致性) write,通过zab[2]实现了update的Atomic Broadcast(这里需要说明的满足线性一致性,必定满足顺序一致性,更多顺序一致性的介绍可以参考[7、9])
  • read:实现了Sequential Consistency,官方描述为:

Single System Image :A client will see the same view of the service regardless of the server that it connects to.

翻译成大白话就是:一个client无论其链接到哪个节点(即使中间切换了链接的节点),其读取的数据永远都不会比之前读到的旧,也就是一旦一个client看到版本为3的数据,那么就不会再读到比版本3更低的数据,只会读到和版本3或者比版本3更高版本的数据。实际上就是不同client看到数据变化的版本的顺序是一致的。

  • Zookeeper是如何实现Sequential Consistency ?
  • zookeeper的每个client和节点建立链接了之后,实际上就是创建了一个session,那么每次read都会从此节点read数据,那么自然读到的数据不会出现版本反转,因为Zab保证了各个副本Op复制的顺序是一致性, 这里关键是如何应对节点宕机或者失联 ,一旦client发现某节点可能下线,那么它会尝试去连接其他节点,但是它会携带上它已经最新的事务id:zxid,如果对端的最新zxid比client已知的新,那么建立连接,否则拒绝, 这样保证了client不会链接到比自己状态旧的节点上实际上每次server返回client请求的时候,都会将自己最新的zkid携带返回给client
  • 除此之外,follower在收到write请求之后,会转发给leader处理,为了保证顺序一致性,也就是write返回之后,后面的read能读到,follower server会等到这个write完成之后才返回给client,这样保证即使update转发给了leader完成,但是仍然能在follower被read到,且之前的write也能够被读到了,从而保证了顺序一致性read
  • 当然Zookeeper也实现了Linearizable read:其通过增加一个sync操作来保证从follower read的时候会去leader上read最新的数据然后返回给follower,在返回给client。这里其实就是相当于将read转发给了leader处理,和etcd的follower read处理方法一致

其实通过上面的实现,熟悉线性一致性的同学就会发现,顺序一致性相对于线性一致性是一种较弱的一致性,所以实现上性能就可以做得更好些,以raft实现线性一致性read为例,要么只能从leader read,要是read request发送到了follower,但还是需要到leader来查最新的commit index,然后read返回,实际上就是只能从leader read。但是对于Zookeeper来说,write使用zab保持线性一致性,但是read就可以直接从follower read,而不需要任何leader的参与,read的性能是不是肯定比线性一致性的会好些了?

4. Cross Data Center

单数据中心Zookeepr是顺序一致性的,那么跨数据中心呢?该如何部署呢?是否还是顺序一致的呢?首先给出三种常见的跨数据中心部署方案:

1. Single Coordination Service

扩数据中心部署单个协调服务,每个数据中心都有协调服务的一个或者多个副本(acceptors)。

Zookeeper和跨数据中心分布式协调

如上图,协调服务的5个副本分别在3个数据中心中,缺点很明显,update会很慢,因为每次update都需要获取扩数据中心的多个副本的大多数投票同意,read可以很快,因为读本地的副本即可,正确性没有问题,可用性也很好,没有单点的问题。

2. Learners

将所有的acceptors副本部署在一个数据中心中(如下图),其他的数据中心仅仅部署Learner副本,仅仅接受数据复制,没有投票权,这种做法优点很明显,部署acceptor的数据中心update很快(如图DC1),但是部署Learner的数据中心的update就需要通过learner转发给DC1的leader处理,是跨数据中心的,会比较慢,不过投票是数据中心内部的,相比上一种部署方式还是会快一些,正确性也没有问题,不过会存在单点问题,一旦部署acceptors的数据中心挂了,那么update服务就不可用了,或者DC1和DC2的网络被隔离了,那么DC2上的update也不可用了

Zookeeper和跨数据中心分布式协调

3. Multiple Coordination Services

就是每个数据中心部署自己的独立的协调服务(如下图),其会将协调服务的数据切成不同的Partation,存放在不同的数据中心中,以下图为例子,将数据按照一定的规则切成两个部分,每个数据中心仅仅负责自己Partation数据的update操作,关于这部分的数据所有acceptors副本都部署在本数据中心,并且为了保证另外一个数据中心可以读到自己的数据,其会在另外一个数据中心中部署一个自己的learner节点,另外一个数据中心从这个learner上读数据。

Zookeeper和跨数据中心分布式协调

首先,自己负责Partation的update的投票都是在本数据中心完成,性能会很好,不是自己负责Partation会通过learner转发到相应Partation的数据中心的leader处理;对于read,如果是自己负责的Partation数据,任意的acceptors副本都可以read,如果不是自己负责的Partation数据,则从部署在自己数据的leaner去read,都在数据中心内部完成,性能会很好,而且任何一个数据中心挂了,都只会影响这个数据中心负责的那部分数据,其他的并不会影响,但是其正确性并不能得到保证,例如:

client 1操作DC1的ZooKeeper,client 2操作DC2的ZooKeeper,初始x=0,y=0,那么下图显示的操作序列是不满足顺序一致性的,因为对client 1和client 2来说,看到x,y的value的顺序是不一致的:

client 1: x=0 -> x=5 -> y=0 -> y=3

client 2: y=0 -> y=3 -> x=0 -> x=5

client 1看到x=5之后,才看到y=3,但是client 2看到y=3之后才看到x=5,所以不满足顺序一致性。

Zookeeper和跨数据中心分布式协调

Zookeeper和跨数据中心分布式协调

总结三种跨数据中心部署方式的优缺点如上表格:

4. Modular Composition

文献[8]修复Multiple Coordination Services正确性的问题,提出了Modular Composition Services的方案。

在介绍Modular Composition的方案前,首先分析上图给的例子,看Multiple Coordination Services方案的问题到底出在哪里?以client 1为例子,set(x, 5)之后,执行get(y)->0(非本Partation的数据),没能获取最新的y值,对于client 2同理,get(x)->0没能获取x的最新值,如果能够通过什么方法拿到最新的值,不就解决问题了吗?下面来看看Modular Composition的方案:

如果read的数据不是自己Partation负责的,那么会在read之前插入一个sync操作,和read一组一起组成 sync read ,其中sync操作会去相应Partation的数据中心拉取最新的到当前的数据中心learner,然后再从learner read,这样就可以保证read的数据是最新的了(如下图所示)

Zookeeper和跨数据中心分布式协调

这样无论是client 1还是client 2看到的顺序就相同了: y=0 -> y=3 -> x=0 -> x=5 。需要注意的是上图中sync(x)和set(x,5)是并发,那么set(x,5)在DC1上生效的瞬间可能先于sync(x)或者晚于sync(x),都是有可能的,所以sync(x)拿到x=5或者x=0都是有可能,上图给出的是拿到x=0(不太理解的同学可以移步[5,9],里面有通俗详细的分析和讨论)。实际上这里read已经不仅仅是顺序一致性,已经是线性一致性read了,sync read相当于raft里面的follower read了,当然满足线性一致,那么也肯定满足顺序一致。

Summary

Zookeeper和跨数据中心分布式协调

Modular Composition Services通过对Multiple Coordination Services简单修改,实现了跨数据中心协调服务部署的正确性,其特性基本延续了Multiple Coordination Services,自己负责Partation的数据,read/write都是直接在数据中心内部完成,其他Partation的数据,read/write都是需要发送给其他数据中心处理,任何数据中心挂了,都仅仅影响自己负责Partation的数据的可用性。最后给出4种方案的比较表格,如上图。

5. Summary

本文算是自己对Cross Data Center部署的一个初探,由于没有实际做过或者接触过跨数据中心的方案,所以理解上可能有很多问题,实际上还有一个疑问,对于Modular Composition Services的方案,为何不去掉Learner,向update一样,直接将read request发到相应Partation的数据中心,直接走sync read就好,还部署一个learner干啥?是因为ZooKeeper的访问模式吗?还是这样做可以保证在一个数据中心挂了之后,对于一些能够容忍一定的数据不一致性的场景,learner还可以继续提供read服务,提高可用性?如果有懂的,不吝赐教~

Notes

限于作者水平,难免在理解和描述上有疏漏或者错误的地方,欢迎共同交流;部分参考已经在正文和参考文献列表中注明,但仍有可能有疏漏的地方,有任何侵权或者不明确的地方,欢迎指出,必定及时更正或者删除;文章供于学习交流,转载注明出处

参考文献

[1]. Lamport L. How to make a multiprocessor computer that correctly executes multiprocess progranm[J]. IEEE transactions on computers, 1979 (9): 690-691.

[2]. Junqueira F P, Reed B C, Serafini M. Zab: High-performance broadcast for primary-backup systems[C]//2011 IEEE/IFIP 41st International Conference on Dependable Systems & Networks (DSN). IEEE, 2011: 245-256.

[3]. Medeiros A. ZooKeeper’s atomic broadcast protocol: Theory and practice[J]. Aalto University School of Science, 2012, 20.

[4]. Hunt P, Konar M, Junqueira F P, et al. ZooKeeper: Wait-free Coordination for Internet-scale Systems[C]//USENIX annual technical conference. 2010, 8(9).

[5]. 不理解Zookeeper一致性原理,谈何异地多活改造. https:// dbaplus.cn/news-141-205 3-1.html

[6]. Sorin D J, Hill M D, Wood D A. A primer on memory consistency and cache coherence[J]. Synthesis Lectures on Computer Architecture, 2011, 6(3): 1-212.

[7]. 分布式线性一致性:理论&验证. https:// zhuanlan.zhihu.com/p/43 949695

[8]. Lev-Ari K, Bortnikov E, Keidar I, et al. Modular composition of coordination services[C]//2016 {USENIX} Annual Technical Conference ({USENIX}{ATC} 16). 2016: 251-264.

[9]. 线性一致性:什么是线性一致性?. https:// zhuanlan.zhihu.com/p/42 239873

[10]. 饿了么异地多活技术实现(一)总体介绍. https:// zhuanlan.zhihu.com/p/32 009822

查看原文: Zookeeper和跨数据中心分布式协调

  • redfish
  • heavycat
  • brownmeercat
  • crazybear
  • greenfish
  • tinypeacock
  • bigladybug
  • purplefish
需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。