Zookeeper work in the zoo?

zookeeper是我在使用dubbo的时候认识的一个中间件,它是一个分布式服务框架,当时候,我只知道dubbo通过它可以注册一些服务列表,然后通过服务提供者和服务消费者互相协助,完整一个分布式的服务应用。

那zookeeper究竟是一个什么东西呢?最近,我想认真的了解一下它到底是何方神圣。经过阅读网上的一些文章后以及官网的一些它的原理图。我开始有了一个大概的认知。

我就用我们项目案例来讲解一下对zookeeper的认知。首先,在以前一个web项目,是所有的服务都是写在一个项目里面的,当需要集群的时候,复制相同的项目代码到其他服务器上面,这样子的话代码重复,以及耦合等等各种问题,从而诞生了微服务-soa。

dubbo就是微服务技术。我们在controller层调用service层的时候,在以前,是直接都写在一个项目里面的。但现在需要把这两层分离,分为两个项目,web-server和web-service。相当于,controller依赖的一些service,调用的时候都需要通过网络传输来实现。那么 web-server怎么知道调用哪一个web-service项目呢?没错,就是通过dubbo这个框架。顺便说说,在一个项目里面,比如用户,权限,还有其他复杂业务都可以把这些分为一个一个的服务,web-servcie1,web-service2.....,这样,web-server1就可以调用web-service2的服务,代码就可以解耦,不需要重复代码了。

说了那么久,为啥还没说到zookeeper?好了,现在来说说zookeeper在这里的作用。我们把web-server,web-service这些项目都统称为client,每当web-server,web-service启动项目,首先都会去与zookeeper服务器进行连接。web-server是cosumer,web-service是provider,provider是把服务注册到zoo上面去了,那到底详细是怎么样实现的。provider项目里面会引用zookeeper-client的api 在zookeeper上面创建数据。zookeeper的数据形式其实是一个树,以/app,/app/n1文件路径为名的 树,每个节点叫znodo.

比如,web-service有一个服务叫userService,client会发送消息到zoo上面,在zoo上面创建节点, create /worker, 然后在这个节点上面挂userSerivice的数据,当然上面可以有ip,port之类的。consumer链接后,进行订阅,它可以对该节点进行监听watcher,当数据更新后,就会通知consumer了,consumer就会知道 对应userService的相关信息,dubbo底层可以通过netty进行 远程调用服务。

对于单一模式,就是非常简单了,一台zookeeper,其他的都是服务。但如果zookeeper挂掉了,那岂不是整个集群都有问题了?所以就必须zookeeper集群。简单来说就是 部署多台zookeeper,然后最好是基数台,他们会选举Leader,其他都是follower, 写操作都会先发送到leader,操作完后,进行同步数据,zoo用的是 zab协议。(下面是抄人的http://www.cnblogs.com/sunddenly/p/4138580.html\)

3.2.1 广播模式

广播模式类似一个简单的两阶段提交:Leader发起一个请求,收集选票,并且最终提交,图3.3演示了我们协议的消息流程。我们可以简化该两阶段提交协议,因为我们并没有"aborts"的情况。followers要么确认Leader的Propose,要么丢弃该Leader的Propose。没有"aborts"意味着,只要有指定数量的机器确认了该Propose,而不是等待所有机器的回应。

图 3.3 The flow of message with protocol

广播协议在所有的通讯过程中使用TCP的FIFO信道,通过使用该信道,使保持有序性变得非常的容易。通过FIFO信道,消息被有序的deliver。只要收到的消息一被处理,其顺序就会被保存下来。

Leader会广播已经被deliver的Proposal消息。在发出一个Proposal消息前,Leader会分配给Proposal一个单调递增的唯一id,称之为zxid。因为Zab保证了因果有序,所以递交的消息也会按照zxid进行排序。广播是把Proposal封装到消息当中,并添加到指向Follower的输出队列中,通过FIFO信道发送到 Follower。当Follower收到一个Proposal时,会将其写入到磁盘,可以的话进行批量写入。一旦被写入到磁盘媒介当中,Follower就会发送一个ACK给Leader。 当Leader收到了指定数量的ACK时,Leader将广播commit消息并在本地deliver该消息。当收到Leader发来commit消息时,Follower也会递交该消息。

需要注意的是, 该简化的两阶段提交自身并不能解决Leader故障,所以我们 添加恢复模式来解决Leader故障。

3.2.2 恢复模式

(1) 恢复阶段概述

正常工作时Zab协议会一直处于广播模式,直到Leader故障或失去了指定数量的Followers。为了保证进度,恢复过程中必须选举出一个新Leader,并且最终让所有的Server拥有一个正确的状态。对于Leader选举,需要一个能够成功高几率的保证存活的算法。Leader选举协议,不仅能够让一个Leader得知它是leader,并且有指定数量的Follower同意该决定。如果Leader选举阶段发生错误,那么Servers将不会取得进展。最终会发生超时,重新进行Leader选举。在我们的实现中,Leader选举有两种不同的实现方式。如果有指定数量的Server正常运行,快速选举的完成只需要几百毫秒。

(2)恢复阶段的保证

该恢复过程的复杂部分是在一个给定的时间内,提议冲突的绝对数量。最大数量冲突提议是一个可配置的选项,但是默认是1000。为了使该协议能够即使在Leader故障的情况下也能正常运作。我们需要做出两条具体的保证:

我们绝不能遗忘已经被deliver的消息,若一条消息在一台机器上被deliver,那么该消息必须将在每台机器上deliver

我们必须丢弃已经被skip的消息。

(3) 保证示例

第一条:

若一条消息在一台机器上被deliver,那么该消息必须将在每台机器上deliver,即使那台机器故障了。例如,出现了这样一种情况:Leader发送了commit消息,但在该commit消息到达其他任何机器之前,Leader发生了故障。也就是说,只有Leader自己收到了commit消息。如图3.4中的C2

图 3.4 The flow of message with protocol

图3.4是"第一条保证"(deliver消息不能忘记)的一个示例。在该图中Server1是一个Leader,我们用L1表示,Server2和Server3为Follower。首先Leader发起了两个Proposal,P1和P2,并将P1、P2发送给了Server1和Server2。然后Leader对P1发起了Commit即C1,之后又发起了一个Proposal即P3,再后来又对P2发起了commit即C2,就在此时我们的Leader挂了。那么这时候,P3和C2这两个消息只有Leader自己收到了。

因为Leader已经deliver了该C2消息,client能够在消息中看到该事务的结果。所以该事务必须能够在其他所有的Server中deliver,最终使得client看到了一个一致性的服务视图。

第二条:

一个被skip的消息,必须仍然需要被skip。例如,发生了这样一种情况:Leader发送了propose消息,但在该propose消息到达其他任何机器之前,Leader发生了故障。也就是说,只有Leader自己收到了propose消息。如图3.4中的P3所示。

在图3.4中没有任何一个server能够看到3号提议,所以在图3.5中当server 1恢复时他需要在系统恢复时丢弃三号提议P3。

图3.5

在图3.5是"第二条保证"(skip消息必须被丢弃)的一个示例。Server1挂掉以后,Server3被选举为Leader,我们用L2表示。L2中还有未被deliver的消息P1、P2,所以,L2在发出新提议P10000001、P10000002之前,L2先将P1、P2两个消息deliver。因此,L2先发出了两个commit消息C1、C2,之后L2才发出了新的提议P10000001和P10000002。

如果Server1 恢复之后再次成为了Leader,此时再次将P3在P10000001和P10000002之后deliver,那么将违背顺序性的保障。

(4) 保证的实现

如果Leader选举协议保证了新LeaderQuorum Server中具有最高的提议编号,即Zxid最高。那么新选举出来的leader将具有所有已deliver的消息。新选举出来的Leader,在提出一个新消息之前,首先要保证事务日志中的所有消息都由Quorum Follower已Propose并deliver。需要注意的是,我们可以让新Leader成为一个用最高zxid来处理事务的server,来作为一个优化。这样,作为新被选举出来的Leader,就不必去从一组Followers中找出包含最高zxid的Followers和获取丢失的事务。

① 第一条

所有的正确启动的Servers,将会成为Leader或者跟随一个Leader。Leader能够确保它的Followers看到所有的提议,并deliver所有已经deliver的消息。通过将新连接上的Follower所没有见过的所有PROPOSAL进行排队,并之后对该Proposals的COMMIT消息进行排队,直到最后一个COMMIT消息。在所有这样的消息已经排好队之后,Leader将会把Follower加入到广播列表,以便今后的提议和确认。这一条是为了保证一致性,因为如果一条消息P已经在旧Leader-Server1中deliver了,即使它刚刚将消息Pdeliver之后就挂了,但是当旧Leader-Server1重启恢复之后,我们的Client就可以从该Server中看到该消息Pdeliver的事务,所以为了保证每一个client都能看到一个一致性的视图,我们需要将该消息在每个Server上deliver。

② 第二条

skip已经Propose,但不能deliver的消息,处理起来也比较简单。在我们的实现中,Zxid是由64位数字组成的,低32位用作简单计数器高32位是一个epoch。每当新Leader接管它时,将获取日志中Zxid最大的epoch,新LeaderZxidepoch位设置为epoch+1,counter位设置0。用epoch来标记领导关系的改变,并要求Quorum Servers通过epoch来识别该leader,避免了多个Leader用同一个Zxid发布不同的提议。

这个方案的一个优点就是,我们可以skip一个失败的领导者的实例,从而加速并简化了恢复过程。如果一台宕机的Server重启,并带有未发布的Proposal,那么先前的未发布的所有提议将永不会被deliver。并且它不能够成为一个新leader,因为任何一种可能的 Quorum Servers ,都会有一个Server其Proposal 来自与一个新epoch因此它具有一个较高的zxid。当Server以Follower的身份连接,领导者检查自身最后提交的提议,该提议的epoch 为Follower的最新提议的epoch(也就是图3.5中新Leader-Server2中deliver的C2提议),并告诉Follower截断事务日志直到该epoch在新Leader中deliver的最后的Proposal即C2。在图3.5中,当旧Leader-Server1连接到了新leader-Server2,leader将告诉他从事务日志中清除3号提议P3,具体点就是清除P2之后的所有提议,因为P2之后的所有提议只有旧Leader-Server1知道,其他Server不知道。

(5) Paxos与Zab

① Paxos一致性

Paxos的一致性不能达到ZooKeeper的要求,我们可以下面一个例子。我们假设ZK集群由三台机器组成,Server1、Server2、Server3。Server1为Leader,他生成了三条Proposal,P1、P2、P3。但是在发送完P1之后,Server1就挂了。如下图3.6所示。

图 3.6 Server1为Leader

Server1挂掉之后,Server3被选举成为Leader,因为在Server3里只有一条Proposal—P1。所以,Server3在P1的基础之上又发出了一条新Proposal—P2',P2'的Zxid为02。如下图3.7所示。

图3.7 Server2成为Leader

Server2发送完P2'之后,它也挂了。此时Server1已经重启恢复,并再次成为了Leader。那么,Server1将发送还没有被deliver的Proposal—P2和P3。由于Follower-Server2中P2'的Zxid为02和Leader-Server1中P2的Zxid相等,所以P2会被拒绝。而P3,将会被Server2接受。如图3.8所示。

图3.8 Server1再次成为Leader

我们分析一下Follower-Server2中的Proposal,由于P2'将P2的内容覆盖了。所以导致,Server2中的Proposal-P3无法生效,因为他的父节点并不存在。

② Zab一致性

首先来分析一下,上面的示例中为什么不满足ZooKeeper需求。ZooKeeper是一个树形结构,很多操作都要先检查才能确定能不能执行,比如,在图3.8中Server2有三条Proposal。P1的事务是创建节点"/zk",P2'是创建节点"/c",而P3是创建节点"/a/b",由于"/a"还没建,创建"a/b"就搞不定了。那么,我们就能从此看出Paxos的一致性达不到ZooKeeper一致性的要求。

为了达到ZooKeeper所需要的一致性,ZooKeeper采用了Zab协议。Zab做了如下几条保证,来达到ZooKeeper要求的一致性。

(a) Zab要保证同一个leader的发起的事务要按顺序被apply,同时还要保证只有先前的leader的所有事务都被apply之后,新选的leader才能在发起事务。

(b) 一些已经Skip的消息,需要仍然被Skip。

我想对于第一条保证大家都能理解,它主要是为了保证每个Server的数据视图的一致性。我重点解释一下第二条,它是如何实现。为了能够实现,Skip已经被skip的消息。我们在Zxid中引入了epoch,如下图所示。每当Leader发生变换时,epoch位就加1,counter位置0。

图 3.9 Zxid

我们继续使用上面的例子,看一下他是如何实现Zab的第二条保证的。我们假设ZK集群由三台机器组成,Server1、Server2、Server3。Server1为Leader,他生成了三条Proposal,P1、P2、P3。但是在发送完P1之后,Server1就挂了。如下图3.10所示。

图 3.10 Server1为Leader

Server1挂掉之后,Server3被选举成为Leader,因为在Server3里只有一条Proposal—P1。所以,Server3在P1的基础之上又发出了一条新Proposal—P2',由于Leader发生了变换,epoch要加1,所以epoch由原来的0变成了1,而counter要置0。那么,P2'的Zxid为10。如下图3.11所示。

图 3.11 Server3为Leader

Server2发送完P2'之后,它也挂了。此时Server1已经重启恢复,并再次成为了Leader。那么,Server1将发送还没有被deliver的Proposal—P2和P3。由于Server2中P2'的Zxid为10,而Leader-Server1中P2P3的Zxid分别为0203P2'的epoch位高于P2和P3。所以此时Leader-Server1的P2和P3都会被拒绝,那么我们Zab的第二条保证也就实现了。如图3.12所示。

图 3.12 Server1再次成为Leader

好像没啥了,第一次写文章,别怪我太烂,哈哈哈哈

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,069评论 4 358
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,212评论 1 287
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 105,912评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,424评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,741评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,194评论 1 206
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,553评论 2 307
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,289评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,923评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,251评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,775评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,144评论 2 249
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,698评论 3 228
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,936评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,658评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,214评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,159评论 2 258

推荐阅读更多精彩内容

  • ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,它包含一个简单的原语集,分布式应用程序可以基于...
    Prize阅读 226评论 0 1
  • 【转自】http://www.cnblogs.com/leesf456/p/6107600.html 一、前言 前...
    lxqfirst阅读 805评论 0 0
  • 概述 ZAB (Zookeeper Atomic Broadcast)协议是为分布式协调服务 ZooKeeper ...
    jiangmo阅读 2,890评论 0 3
  • 本文将从系统模型、序列化与协议、客户端工作原理、会话、服务端工作原理以及数据存储等方面来揭示ZooKeeper的技...
    端木轩阅读 3,723评论 0 42
  • ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,它包含一个简单的原语集,分布式应用程序可以基于...
    蓝色的咖啡阅读 446评论 0 2