提到ZooKeeper,相信你们都不会陌生。Dubbo,Kafka,Hadoop等等项目里都能看到它的影子。可是你真的了解 ZooKeeper 吗?若是面试官让你给他讲讲 ZooKeeper 是个什么东西,你能回答到什么地步呢?html
我会用两个篇幅介绍ZooKeeper ,第一篇是概念性的认识,这篇你会获得 ZooKeeper 是什么,ZooKeeper 设计的目标,ZooKeeper 能作什么和ZooKeeper 基本的概念。第二篇我会从实战出发,安装ZooKeeper,写一些ZooKeeper 具体应用场景的代码实现。node
ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。mysql
官网:http://zookeeper.apache.org/git
源码:https://github.com/apache/zoo...github
下面这段内容摘自《从Paxos到Zookeeper 》 ,本文中不少的名词介绍也来自本书。面试
Zookeeper 最先起源于雅虎研究院的一个研究小组。在当时,研究人员发现,在雅虎内部不少大型系统基本都须要依赖一个相似的系统来进行分布式协调,可是这些系统每每都存在分布式单点问题。因此,雅虎的开发人员就试图开发一个通用的无单点问题的分布式协调框架,以便让开发人员将精力集中在处理业务逻辑上。
关于“ZooKeeper”这个项目的名字,其实也有一段趣闻。在立项初期,考虑到以前内部不少项目都是使用动物的名字来命名的(例如著名的Pig项目),雅虎的工程师但愿给这个项目也取一个动物的名字。时任研究院的首席科学家 RaghuRamakrishnan 开玩笑地说:“在这样下去,咱们这儿就变成动物园了!”此话一出,你们纷纷表示就叫动物园管理员吧一一一由于各个以动物命名的分布式组件放在一块儿,雅虎的整个分布式系统看上去就像一个大型的动物园了,而 Zookeeper 正好要用来进行分布式环境的协调一一因而,Zookeeper 的名字也就由此诞生了。
对于来自客户端的每一个更新请求,Zookeeper 都会分配一个全局惟一的递增编号,这个编号反映了全部事务操做的前后顺序。算法
Zookeeper 和Redis同样全量数据存储在内存中,100%读请求压测QPS 12-13W。sql
Zookeeper 是一个由多个 server 组成的集群,一个 leader,多个 follower。(这个不一样于咱们常见的Master/Slave模式)leader 为客户端服务器提供读写服务,除了leader外其余的机器只能提供读服务。
每一个 server 保存一份数据副本全数据一致,分布式读 follower,写由 leader 实施更新请求转发,由 leader 实施更新请求顺序进行,来自同一个 client 的更新请求按其发送顺序依次执行数据更新原子性,一次数据更新要么成功,要么失败。全局惟一数据视图,client 不管链接到哪一个 server,数据视图都是一致的实时性,在必定事件范围内,client 能读到最新数据。apache
Leader:是整个 Zookeeper 集群工做机制中的核心 。Leader 做为整个 ZooKeeper 集群的主节点,负责响应全部对 ZooKeeper 状态变动的请求。
主要工做:安全
Leader 选举是 Zookeeper 最重要的技术之一,也是保障分布式数据一致性的关键所在。咱们以三台机器为例,在服务器集群初始化阶段,当有一台服务器Server1启动时候是没法完成选举的,当第二台机器 Server2 启动后两台机器能互相通讯,每台机器都试图找到一个leader,因而便进入了 leader 选举流程.
投票的最基本元素是(SID-服务器id,ZXID-事物id)
统计投票
这里有个**过半**的概念,大于集群机器数量的一半,即大于或等于(n/2+1),咱们这里的由三台,大于等于2即为达到“过半”的要求。 这里也有引伸到为何 Zookeeper 集群推荐是单数。
集群数量 | 至少正常运行数量 | 容许挂掉的数量 |
---|---|---|
2 | 2的半数为1,半数以上最少为2 | 0 |
3 | 3的半数为1.5,半数以上最少为2 | 1 |
4 | 4的半数为2,半数以上最少为3 | 1 |
5 | 5的半数为2.5,半数以上最少为3 | 2 |
6 | 6的半数为3,半数以上最少为4 | 2 |
经过以上能够发现,3台服务器和4台服务器都最多容许1台服务器挂掉,5台服务器和6台服务器都最多容许2台服务器挂掉,明显4台服务器成本高于3台服务器成本,6台服务器成本高于5服务器成本。这是因为半数以上投票经过决定的。
一旦肯定了 leader,服务器就会更改本身的状态,且一半不会再发生变化,好比新机器加入集群、非 leader 挂掉一台。
Follower :是 Zookeeper 集群状态的跟随者。他的逻辑就比较简单。除了响应本服务器上的读请求外,follower 还要处理leader 的提议,并在 leader 提交该提议时在本地也进行提交。另外须要注意的是,leader 和 follower 构成ZooKeeper 集群的法定人数,也就是说,只有他们才参与新 leader的选举、响应 leader 的提议。
Observer :服务器充当一个观察者的角色。若是 ZooKeeper 集群的读取负载很高,或者客户端多到跨机房,能够设置一些 observer 服务器,以提升读取的吞吐量。Observer 和 Follower 比较类似,只有一些小区别:首先 observer 不属于法定人数,即不参加选举也不响应提议,也不参与写操做的“过半写成功”策略;其次是 observer 不须要将事务持久化到磁盘,一旦 observer 被重启,须要从 leader 从新同步整个名字空间。
Session 指的是 ZooKeeper 服务器与客户端会话。在 ZooKeeper 中,一个客户端链接是指客户端和服务器之间的一个 TCP 长链接。客户端启动的时候,首先会与服务器创建一个 TCP 链接,从第一次链接创建开始,客户端会话的生命周期也开始了。经过这个链接,客户端可以经过心跳检测与服务器保持有效的会话,也可以向Zookeeper 服务器发送请求并接受响应,同时还可以经过该链接接收来自服务器的Watch事件通知。 Session 的 sessionTimeout 值用来设置一个客户端会话的超时时间。当因为服务器压力太大、网络故障或是客户端主动断开链接等各类缘由致使客户端链接断开时,只要在sessionTimeout规定的时间内可以从新链接上集群中任意一台服务器,那么以前建立的会话仍然有效。在为客户端建立会话以前,服务端首先会为每一个客户端都分配一个sessionID。因为 sessionID 是 Zookeeper 会话的一个重要标识,许多与会话相关的运行机制都是基于这个 sessionID 的,所以,不管是哪台服务器为客户端分配的 sessionID,都务必保证全局惟一。
在Zookeeper客户端与服务端成功完成链接建立后,就建立了一个会话,Zookeeper会话在整个运行期间的生命周期中,会在不一样的会话状态中之间进行切换,这些状态能够分为CONNECTING、CONNECTED、RECONNECTING、RECONNECTED、CLOSE等。
一旦客户端开始建立Zookeeper对象,那么客户端状态就会变成CONNECTING状态,同时客户端开始尝试链接服务端,链接成功后,客户端状态变为CONNECTED,一般状况下,因为断网或其余缘由,客户端与服务端之间会出现断开状况,一旦碰到这种状况,Zookeeper客户端会自动进行重连服务,同时客户端状态再次变成CONNCTING,直到从新连上服务端后,状态又变为CONNECTED,在一般状况下,客户端的状态老是介于CONNECTING 和CONNECTED 之间。可是,若是出现诸如会话超时、权限检查或是客户端主动退出程序等状况,客户端的状态就会直接变动为CLOSE状态。
Session是Zookeeper中的会话实体,表明了一个客户端会话,其包含了以下四个属性
Zookeeper为了保证请求会话的全局惟一性,在SessionTracker初始化时,调用initializeNextSession方法生成一个sessionID,以后在Zookeeper运行过程当中,会在该sessionID的基础上为每一个会话进行分配,初始化算法以下
``` public static long initializeNextSession(long id) { long nextSid = 0; // 无符号右移8位使为了不左移24后,再右移8位出现负数而没法经过高8位肯定sid值 nextSid = (System.currentTimeMillis() << 24) >>> 8; nextSid = nextSid | (id << 56); return nextSid; } ```
Zookeeper的会话管理主要是经过SessionTracker来负责,其采用了分桶策略(将相似的会话放在同一区块中进行管理)进行管理,以便Zookeeper对会话进行不一样区块的隔离处理以及同一区块的统一处理。

在Zookeeper中,“节点"分为两类,第一类一样是指构成集群的机器,咱们称之为机器节点;第二类则是指数据模型中的数据单元,咱们称之为数据节点一一ZNode。
Zookeeper将全部数据存储在内存中,数据模型是一棵树(Znode Tree),由斜杠(/)的进行分割的路径,就是一个Znode,例如/foo/path1。每一个上都会保存本身的数据内容,同时还会保存一系列属性信息。

在Zookeeper中,node能够分为持久节点和临时节点和顺序节点三大类。
能够经过组合生成以下四种类型节点 1. PERSISTENT
持久节点,节点建立后便一直存在于Zookeeper服务器上,直到有删除操做来主动清楚该节点。
2. PERSISTENT_SEQUENTIAL
持久顺序节点,相比持久节点,其新增了顺序特性,每一个父节点都会为它的第一级子节点维护一份顺序,用于记录每一个子节点建立的前后顺序。在建立节点时,会自动添加一个数字后缀,做为新的节点名,该数字后缀的上限是整形的最大值。
3.EPEMERAL
临时节点,临时节点的生命周期与客户端会话绑定,客户端失效,节点会被自动清理。同时,Zookeeper规定不能基于临时节点来建立子节点,即临时节点只能做为叶子节点。
4.EPEMERAL_SEQUENTIAL
临时顺序节点,在临时节点的基础添加了顺序特性。
每一个数据节点都具备三种类型的版本信息,对数据节点的任何更新操做都会引发版本号的变化。
version– 当前数据节点数据内容的版本号
cversion– 当前数据子节点的版本号
aversion– 当前数据节点ACL变动版本号
上述各版本号都是表示修改次数,如version为1表示对数据节点的内容变动了一次。即便先后两次变动并无改变数据内容,version的值仍然会改变。version能够用于写入验证,相似于CAS。
ZooKeeper容许用户在指定节点上注册一些Watcher,当数据节点发生变化的时候,ZooKeeper服务器会把这个变化的通知发送给感兴趣的客户端
ACL是Access Control Lists 的简写, ZooKeeper采用ACL策略来进行权限控制,有如下权限:
CREATE:建立子节点的权限
READ:获取节点数据和子节点列表的权限
WRITE:更新节点数据的权限
DELETE:删除子节点的权限
ADMIN:设置节点ACL的权限
Paxos算法是基于消息传递且具备高度容错特性的一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一。(其余算法有二阶段提交、三阶段提交等)
篇幅较长 能够参考https://www.cnblogs.com/linbi...
在分布式环境中,为了保证高可用性,一般同一个应用或同一个服务的提供方都会部署多份,达到对等服务。而消费者就需要在这些对等的服务器中选择一个来执行相关的业务逻辑,比较典型的服务注册与订阅,表明:dubbo。
github:https://github.com/knightliao...
命名服务
在分布式系统中,经过使用命名服务,客户端应用可以根据指定名字来获取资源或服务的地址,提供者等信息。被命名的实体一般能够是集群中的机器,提供的服务地址,进程对象等等——这些咱们均可以统称他们为名字(Name)。其中较为常见的就是一些分布式服务框架中的服务地址列表。经过调用ZK提供的建立节点的API,可以很容易建立一个全局惟一的path,这个path就能够做为一个名称。
分布式锁,这个主要得益于ZooKeeper为咱们保证了数据的强一致性。锁服务能够分为两类,一个是保持独占,另外一个是控制时序。
所谓保持独占,就是全部试图来获取这个锁的客户端,最终只有一个能够成功得到这把锁。一般的作法是把zk上的一个znode看做是一把锁,经过create znode的方式来实现。全部客户端都去建立 /distribute_lock 节点,最终成功建立的那个客户端也即拥有了这把锁。
控制时序,就是全部视图来获取这个锁的客户端,最终都是会被安排执行,只是有个全局时序了。作法和上面基本相似,只是这里 /distribute_lock 已绊预先存在,客户端在它下面建立临时有序节点(这个能够经过节点的属性控制:CreateMode.EPHEMERAL_SEQUENTIAL来指定)。Zk的父节点(/distribute_lock)维持一份sequence,保证子节点建立的时序性,从而也造成了每一个客户端的全局时序
推荐阅读
最近,我组建了个群聊。学习Java进阶技术干货、实践分享,职位内推,一块儿聊聊理想。志同道合的朋友,欢迎你的加入。