ZooKeeper入门教程一简介与核心概念

目录
  • 1、ZooKeeper介绍与核心概念
    • 1.1 简介
    • 1.2分布式系统面临的问题
      • 1、通过网络进行信息共享
      • 2、通过共享存储
    • 1.3 ZooKeeper如何解决分布式系统面临的问题
    • 1.4 zookeeper概念介绍
      • 1.4.1 znode
      • 1.4.2 观察与通知
      • 1.4.3 版本
      • 1.4.4 法定人数
      • 1.4.5 会话
      • 1.4.6 会话状态和生命周期
  • 回顾总结

本章是后续学习的基石,只有充分理解了分布式系统的概念和面临的问题,以及ZooKeeper内部的概念,才能懂得ZooKeeper是如何对分布式系统进行协调,为后续学习打下坚实的基础。

1、ZooKeeper介绍与核心概念

1.1 简介

ZooKeeper最为主要的使用场景,是作为分布式系统的分布式协同服务。在学习zookeeper之前,先要对分布式系统的概念有所了解,否则你将完全不知道zookeeper在分布式系统中起到了什么作用,解决了什么问题。

1.2分布式系统面临的问题

我们将分布式系统定义为:分布式系统是同时跨越多个物理主机,独立运行的多个软件所组成系统。类比一下,分布式系统就是一群人一起干活。人多力量大,每个服务器的算力是有限的,但是通过分布式系统,由n个服务器组成起来的集群,算力是可以无限扩张的。

优点显而易见,人多干活快,并且互为备份。但是缺点也很明显。我们可以想象一下,以一个小研发团队开发软件为例,假设我们有一个5人的项目组,要开始一个系统的开发,项目组将面临如下问题:

你一定在想,以上这些问题很简单啊,在我的日常工作中天天都在发生,并没感觉有什么复杂。是的,这是因为我们人类的大脑是个超级计算机,能够灵活应对这些问题,而且现实中信息的交换不依赖网络,不会因网络延迟或者中断,出现信息不对等。而且现实中对以上问题的处理其实并不严谨,从而也引发了很多问题。

想一想,项目中是不是出现过沟通不畅造成任务分配有歧义?是否由于人员离职造成任务进行不下去,甚至要联系离职人员协助?是不是出现过任务分配不合理?类似这样的各种问题,肯定会发生于你的项目组中。

在现实世界,我们可以人为去协调,即使出错了,人工去补错,加加班搞定就好。但在计算机的世界,这样做是行不通的,一切都要保证严谨,以上问题要做到尽可能不要发生。因此,分布式系统必须采用合理的方式解决掉以上的问题。

实际上要想解决这些问题并没有那么复杂,我们仅需要做一件事就可以万事无忧---让信息在项目组成员中同步。如果能做到信息同步,那么每个人在干什么,大家都是清楚的,干到什么程度也是清晰的,无论谁离职也不会产生问题。分配的工作,能够及时清晰的同步给每个组员,确保每个组员收到的任务分配没有冲突。

分布式系统的协调工作就是通过某种方式,让每个节点的信息能够同步和共享。这依赖于服务进程之间的通信。通信方式有两种:

1、通过网络进行信息共享

这就像现实世界,开发leader在会上把任务传达下去,组员通过听leader命令或者看leader的邮件知道自己要干什么。当任务分配有变化时,leader会单独告诉组员,或者再次召开会议。信息通过人与人之间的直接沟通,完成传递。

2、通过共享存储

这就好比开发leader按照约定的时间和路径,把任务分配表放到了svn上,组员每天去svn上拉取最新的任务分配表,然后干活。其中svn就是共享存储。更好一点的做法是,当svn文件版本更新时,触发邮件通知,每个组员再去拉取最新的任务分配表。这样做更好,因为每次更新,组员都能第一时间得到消息,从而让自己手中的任务分配表永远是最新的。此种方式依赖于中央存储。整个过程如下图所示:

1.3 ZooKeeper如何解决分布式系统面临的问题

ZooKeeper对分布式系统的协调,使用的是第二种方式,共享存储。其实共享存储,分布式应用也需要和存储进行网络通信。网络通信是分布式系统并发设计的基础。

实际上,通过ZooKeeper实现分布式协同的原理,和项目组通过SVN同步工作任务的例子是一样的。ZooKeeper就像是svn,存储了任务的分配、完成情况等共享信息。每个分布式应用的节点就是组员,订阅这些共享信息。当主节点(组leader),对某个从节点的分工信息作出改变时,相关订阅的从节点得到zookeeper的通知,取得自己最新的任务分配。完成工作后,把完成情况存储到zookeeper。主节点订阅了该任务的完成情况信息,所以将得到zookeeper的完工的通知。参考下图,回味一下,是不是和前面项目组通过svn分配工作的例子一模一样?仅仅是把svn和邮件系统合二为一,以ZooKeeper代替。

注:Slave节点要想获取ZooKeeper的更新通知,需事先在关心的数据节点上设置观察点。

大多数分布式系统中出现的问题,都源于信息的共享出了问题。如果各个节点间信息不能及时共享和同步,那么就会在协作过程中产生各种问题。ZooKeeper解决协同问题的关键,在于保证分布式系统信息的一致性。

通过以上章节的讲解,我们应该已经理解分布式系统以及其面临的问题。了解了ZooKeeper通过什么样的机制去解决这些问题。从宏观上对ZooKeeper已经有了认知,接下来我们先切入到zookeeper自身,讲解zookeeper的概念,这些概念很重要,所有zookeeper的应用都会围绕这些概念来实现。

1.4 zookeeper概念介绍

ZooKeeper并不直接暴露分布式服务所需要的原语及原语的调用方法。什么是原语?举个例子,比如说分布式锁机制是一个原语,它会暴露出创建、获取、释放三个调用方法。ZooKeeper以类似文件系统的方式存储数据,暴漏出调用这些数据的API。让应用通过ZooKeeper的机制和API,自己来实现分布式相关原语。

我们若想让应用能够通过ZooKeeper实现分布式协同,那么第一件事就是了解ZooKeeper的特性及相关概念,另外熟悉它给我们提供了哪些API。

1.4.1 znode

Zookeeper会保存任务的分配、完成情况,等共享信息,那么ZooKeeper是如何保存的呢?在ZooKeeper中,这些信息被保存在一个个数据节点上,这些节点被称为znode。它采用了类似文件系统的层级树状结构进行管理。见下图示例:

根节点/包含4个子节点,其中三个拥有下一级节点。有的叶子节点存储了信息。

节点上没有存储数据,也有着重要的含义。比如在主从模式中,当/master节点没有数据时,代表分布式应用的主节点还没有选举出来。

znode节点存储的数据为字节数组。存储数据的格式zookeeper不做限制,也不提供解析,需要应用自己实现。

实际上图就是主从模式存储数据的示例,这里先简单讲解:

  • /master,存储了当前主节点的信息
  • /workers,下面的每个子znode代表一个从节点,子znode上存储的数据,如“foo.com:2181”,代表从节点的信息。
  • /tasks,下面的每个子znode代表一个任务,子znode上存储的信息如“run cmd”,代表该内务内容
  • /assign,下面每个子znode代表一个从节点的任务集合。如/assign/worker-1,代表worker-1这个从节点的任务集合。/assign/worker-1下的每个子znode代表分配给worker-1的一个任务。
持久节点(persistent)和临时节点(ephemeral)

持久节点只能通过delete删除。临时节点在创建该节点的客户端崩溃或关闭时,自动被删除。

前面例子中的/master应该使用临时节点,这样当主节点失效或者退出时,该znode被删除,其他节点知道主节点崩溃了,开始进行选举的逻辑。另外/works/worker-1也应该是临时节点,在此从节点失效的时候,该临时节点自动删除。

在目前的版本,由于临时znode会因为创建者会话过期被删除,所以不允许临时节点拥有子节点。

有序节点

znode可以被设置为有序(sequential)节点。有序znode节点被分配唯一一个单调递增的证书。如果创建了个一有序节点为/workers/worker-,zookeeper会自动分配一个序号1,追加在名字后面,znode名称为/workers/worker-1。通过这种方式,可以创建唯一名称znode,并且可以直观的看到创建的顺序。

znode支持的操作及暴露的API:

create /path data

创建一个名为/path的znode,数据为data。

delete /path

删除名为/path的znode。

exists /path

检查是否存在名为/path的znode

setData /path data

设置名为/path的znode的数据为data

getData /path

返回名为/path的znode的数据

getChildren /path

返回所有/path节点的所有子节点列表

1.4.2 观察与通知

分布式应用需要及时知道zookeeper中znode的变化,从而了解到分布式应用整体的状况,如果采用轮询方式,代价太大,绝大多数查询都是无效的。因此,zookeeper采用了通知的机制。客户端向zookeeper请求,在特定的znode设置观察点(watch)。当该znode发生变化时,会触发zookeeper的通知,客户端收到通知后进行业务处理。观察点触发后立即失效。所以一旦观察点触发,需要再次设置新的观察点。

我们使用Zookeeper不能期望能够监控到节点每次的变化。思考如下场景:

  • 1、客户端C1设置观察点在/tasks
  • 2、观察点触发,C1处理自己的逻辑
  • 3、C1设置新的观察点前,C2更新了/tasks
  • 4、C1处理完逻辑,再次设置了观察点。

此时C1不会得到第三步的通知,因此错过了C2更新/tasks这次操作。要想不错过这次更新,C1需要在设置监视点前读取/tasks的数据,进行对比,发现更新。

再如下面的场景:

  • 1、客户端C1设置观察点在/tasks
  • 2、/tasks上发生了连续两次更新
  • 3、C1在得到第一次更新的通知后就读取了/tasks的数据
  • 4、此时第二次更新也已经发生,C1用第一次的通知,读取到两次更新后的数据

此时C1虽然错过了第二次通知,但是C1最终还是读取到了最新的数据。

因此Zookeeper只能保证最终的一致性,而无法保证强一致性。

zookeeper可以定义不同的观察类型。例如观察znode数据变化,观察znode子节点变化,观察znode创建或者删除。

1.4.3 版本

每个znode都有版本号,随着每次数据变化自增。setData和delete,以版本号作为参数,当传入的版本号和服务器上不一致时,调用失败。当多个zookeeper客户端同时对一个znode操作时,版本将会起到作用,假设c1,c2同时往一个znode写数据,c1先写完后版本从1升为2,但是c2写的时候携带版本号1,c2会写入失败。

1.4.4 法定人数

zookeeper服务器运行于两种模式:独立模式和仲裁模式(集群)。仲裁模式下,会复制所有服务器的数据树。但如果让客户端等待所有复制完成,延迟太高。这里引入法定人数概念,指为了使zookeeper集群正常工作,必须有效运行的服务器数量。同时也是服务器通知客户端保存成功前,必须保存数据的服务器最小数。例如我们有一个5台服务器的zookeeper集群,法定人数为3,只要任何3个服务器保存了数据,客户端就会收到确认。只要有3台服务器存活,整个zookeeper集群就是可用的。

下图展示了客户端提交请求到收到回复的过程:

法定人数需要大于服务器数量的一半。也称为多数原则。举个例子说明,假如集群有5台服务器,法定人数为2,那么有2台服务器参与复制即可,若这2台server刚刚复制完/z这个znode,就挂掉了。此时剩下了3台server,大于法定人数2,所以zookeeper认为集群正常,但这三台服务器是无法发现/z这个znode的。如果法定人数大于服务器数量一半,那么法定人数复制完成,就可以确保集群存活时,至少有一台服务器有最新的znode,否则集群认为自己已经崩溃。

下面两个例子阐明了,为何要遵循多数原则。

下图展示了5台server,法定人数为3,在确保zookeeper集群存活的前提下,最坏的情况挂了2台server(剩余及器数量3>=法定人数3),zookeeper是如何能确保数据完备,集群继续工作的。

接下来两张图展示了5台server,未遵循多数原则,法定人数设为2。同样挂了两台server时,为什么zookeeper集群会出问题。

首先,客户端发起请求,2个server复制数据后即返回客户端接收成功。

就在此刻,很不幸,在继续同步更新给其他节点前,刚刚两个复制了数据的节点挂了。

此时会怎样呢?如下图:

可以看到创建/z的操作在zookeeper集群中丢失了。

相信通过以上讲解,你已经能够理解为什么法定人数一定要多于一半服务器的数量。

此外,我们要尽量选用奇数个服务器,这样集群能容忍崩溃服务器占比更大,性价比更高。例如4台服务器的集群,法定人数最少为3,那么只能允许1台服务器崩溃,也就是仅允许25%的机器崩溃。而5台服务器的集群,法定人数最少也是3,但是此时允许2台服务器崩溃。换句话讲,40%的机器崩溃后还能工作。

仲裁模式下,负载均衡通过客户端随机选择连接串中的某个服务器来实现。

1.4.5 会话

客户端对zookeeper集群发送任何请求前,需要和zookeeper集群建立会话。客户端提交给zookeeper的所有操作均关联在一个会话上。当一个会话因某种原因终止时,会话期间创建的临时节点将会消失。而当当前服务器的问题,无法继续通信时,会话将被透明的转移到另外一台zookeeper集群的服务器上。

会话提供了顺序保障。同一个会话中的请求以FIFO顺序执行。并发会话的FIFO顺序无法保证。

1.4.6 会话状态和生命周期

会话状态有:

connecting、connected、closed、not_connected

创建会话时,需要设置会话超时这个重要的参数。如果经过时间t后服务接受不到这个会话的任何消息,服务就会声明会话过期。客户端侧,t/3时间未收到任何消息,客户端向服务器发送心跳消息,2t/3时间后,客户端开始寻找其他服务器。此时他有t/3的时间去寻找,找不到的话,会话失效。

重连服务器时,只有更新大于客户端的服务器才能被连接,以免连接到落后的服务器。zookeeper中通过更新建立的顺序,分配事务标识符。只有服务器的事物标识符大于客户端携带的标识符时,才可连接。

回顾总结

本章首先介绍了分布式系统及分布式系统面临的问题,随后介绍了zookeeper是以何机制来解决这些问题的。最后介绍了zookeeper中的重要概念,在开始后续学习前,一定要确保自己理解了这些重要的概念,本章知识是后面章节学习的重要基石,希望大家以后多多支持我们!

(0)

相关推荐

  • ZooKeeper框架教程Curator分布式锁实现及源码分析

    目录 如何使用InterProcessMutex 实现思路 代码实现概述 InterProcessMutex源码分析 实现接口 属性 构造方法 方法 获得锁 释放锁 LockInternals源码分析 获取锁 释放锁 总结 ZooKeeper入门教程一简介与核心概念 ZooKeeper入门教程二在单机和集群环境下的安装搭建及使用 ZooKeeper入门教程三分布式锁实现及完整运行源码 上一篇文章中,我们使用zookeeper的java api实现了分布式排他锁. Curator中有着更为标准.规

  • ZooKeeper开发实际应用案例实战

    目录 项目背景介绍 面临问题 如何解决 代码讲解 数据服务器 检索服务器 总结 附:完整代码 数据服务端代码 检索服务端代码 项目背景介绍 首先给大家介绍一下本文描述项目的情况.这是一个检索网站,它让你能在几千万份复杂文档数据中检索出你所需要的文档数据.为了加快检索速度,项目的数据分布在100台机器的内存里,我们称之为数据服务器.除了数据,这100台机器上均部署着检索程序.这些server之外,还有数台给前端提供接口的搜索server,这些机器属一个集群,我们称之为检索服务器.当搜索请求过来时,

  • 微服务架构之服务注册与发现功能详解

    目录 微服务的注册与发现 1.服务注册 2.服务发现 3.注册中心 4.现下的主流注册中心 4.1 Eureka 4.1.1 介绍 4.1.2 整体架构 4.1.3 接入Spring Cloud 4.2 ZooKeeper 4.2.1 介绍 4.2.2 整体架构 4.2.3 接入Dubbo生态 4.3 Consul 4.3.1 介绍 4.3.2 整体架构 4.3.3 生态对接 4.4 总结对比 详解微服务架构及其演进史 微服务全景架构全面瓦解 微服务架构拆分策略详解 微服务的注册与发现 我们前面

  • ZooKeeper入门教程三分布式锁实现及完整运行源码

    目录 1.0版本 2.0版本 LockSample类 构造方法 获取锁实现 createLock() attemptLock() 释放锁实现 TicketSeller类 sell() sellTicketWithLock() 测试入口 测试方法 代码清单如下: 1.LockSample 2.TicketSeller ZooKeeper入门教程一简介与核心概念 ZooKeeper入门教程二在单机和集群环境下的安装搭建及使用 1.0版本 首先我们先介绍一个简单的zookeeper实现分布式锁的思路:

  • ZooKeeper的安装及部署教程

    一.Zookeeper介绍 •是一个针对大型分布式系统的可靠协调系统: •提供的功能包括:配置维护.名字服务.分布式同步.组服务等: •目标就是封装好复杂易出错的关键职务,将简单易用的接口和性能高效.功能稳定的系统提供给用户: •Zookeeper已经成为Hadoop生态系统中的基础组件. 二.Zookeeper特点 •最终一致性:为客户端展示同一视图,这是Zookeeper最重要的性能: •可靠性:如果消息被一台服务器接受,那么它将被所有的服务器接受: •原子性:更新只能成功或失败,没有中间状

  • zookeeper服务优化的一些建议

    1.快照文件和事务日志文件分别挂在不同磁盘.zoo.cfg文件中,dataDir是存放快照数据的,dataLogDir是存放事务日志的.zookeeper更新操作过程:先写事务日志,再写内存,周期性落到磁盘(刷新内存到快照文件).事务日志的对写请求的性能影响很大,保证dataLogDir所在磁盘性能良好.没有竞争者. 2. 默认jvm没有配置Xmx.Xms等信息,可以在conf目录下创建java.env文件(内存堆空间一定要小于机器内存,避免使用swap) export JVMFLAGS="-X

  • zookeeper概述图文详解

    1.1 概述 分布式系统:分布式系统指由很多台计算机组成的一个整体!这个整体一致对外,并且处理同一请求!系统对内透明,对外不透明!内部的每台计算机,都可以相互通信,例如使用RPC/REST或者是WebService!客户端向一个分布式系统发送的一次请求到接受到响应,有可能会经历多台计算机! Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目,多用作为集群提供服务的中间件! Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责

  • ZooKeeper入门教程一简介与核心概念

    目录 1.ZooKeeper介绍与核心概念 1.1 简介 1.2分布式系统面临的问题 1.通过网络进行信息共享 2.通过共享存储 1.3 ZooKeeper如何解决分布式系统面临的问题 1.4 zookeeper概念介绍 1.4.1 znode 1.4.2 观察与通知 1.4.3 版本 1.4.4 法定人数 1.4.5 会话 1.4.6 会话状态和生命周期 回顾总结 本章是后续学习的基石,只有充分理解了分布式系统的概念和面临的问题,以及ZooKeeper内部的概念,才能懂得ZooKeeper是如

  • Go语言七篇入门教程一简介初识

    目录 简介 为什么是Go Go应用 Web Cloud 云 BlockChain 区块链 如何学习Go 其实我自己接触Go语言也还不到一年,20年的10月我才开始学Go的. 我自己也并不是很懂,但是我希望我能帮助到你学习Go语言,我们可以一起学习交流~ Go语言的吉祥物-金花鼠我一直以为是土拨鼠 在某搜索引擎上一搜golang一堆表情包. 简介 Go语言亦叫Golong语言,是由谷歌Goggle公司推出.Go语言的主要开发者有:肯.汤姆逊(Ken Thompson).罗布.派克(Rob Pike

  • ZooKeeper入门教程二在单机和集群环境下的安装搭建及使用

    目录 1.下载 2.解压 3.创建配置文件 4.单机启动ZooKeeper 5.通过客户端连接ZooKeeper 6.通过客户端执行基本命令 7.集群配置和启动 小结: 通过本篇学习掌握zookeeper环境的搭建,为后续学习做好准备 1.下载 首先我们下载最新稳定版本的zookeeper https://www.jb51.net/softs/578345.html 2.解压 下载完成后,我们解开压缩包 3.创建配置文件 解压后的路径下找到conf文件夹,进入conf文件夹复制zoo_sampl

  • 基于Bootstrap框架菜鸟入门教程(推荐)

    Bootstrap菜鸟入门教程 Bootstrap简介 Bootstrap,来自 Twitter,是目前最受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的,它简洁灵活,使得 Web 开发更加快捷. 一.栅格系统 栅格系统的工作原理: "行(row)"必须包含在 .container (固定宽度)或 .container-fluid (100% 宽度)中,以便为其赋予合适的排列(aligment)和内补(padding). 通过"行(ro

  • ZooKeeper分布式协调服务设计核心概念及安装配置

    目录 一.ZooKeeper 简介 1.ZooKeeper 设计目标 2.核心概念 1)Session 会话 2)数据节点 3)Watcher 4)ACL 3.Zab 协议介绍 二.ZooKeeper Cluster 安装 1.安装 ZooKeeper 2.使用 Golang 连接 ZooKeeper 的 API 接口 3.配置 ZooKeeper Cluster 一.ZooKeeper 简介 ZooKeeper 是一个开源的分布式协调服务,目前由 Apache 进行维护.ZooKeeper 可

  • OpenStack云计算快速入门教程(1)之OpenStack及其构成简介

    该教程基于Ubuntu12.04版,它将帮助读者建立起一份OpenStack最小化安装.我是五岳之巅,翻译中多采用意译法,所以个别词与原版有出入,请大家谅解.我不是英语专业,我觉着搞技术最重要的就是理解,而不是四级和考研中那烦人的英译汉,所以我的目标是忠于原意.通俗表达,Over.英文原文在这里(http://docs.openstack.org/es@***/openstack-compute/starter/content/ ,请将ex@***中的@去掉,CU屏蔽的F词),下面步入正题: 第

  • PHP入门教程之面向对象基本概念实例分析

    本文实例讲述了PHP面向对象基本概念.分享给大家供大家参考,具体如下: Demo1.php <?php //怎样去创建一个类 格式:修饰符 class 类名{} //我们去创建一个电脑的类,这类可以创建出对象(生产出电脑) class Computer { //类名第一个字母大写 } //创建一台电脑出来,也就是对象的声明 //格式:变量 = new 类名(); //new Compuer() 表示实例化的过程(意思是创建一个对象) //$compuer1 = new Compuer() 这个过

  • MongoDB 简单入门教程(安装、基本概念、创建用户)

    工作方向上的原因,不得不接触部分MongoDB的运维工作,之前有接触过一些MongoDB的内容,基本的运维操作没有什么问题,包括MongoDB的集群搭建.数据分片功能等都测试过.但是时间久了,很多东西不用就忘记了,最近准备出一个系列的MongoDB的运维操作文章,希望把这块儿内容重新拾起来.网上查了查,MongDB讲得好的书也就是<MongoDB权威指南>这本了,但是它引用的MongoDB版本比较旧,所以最好结合着官方文档看,这样收获会更快.MongoDB中文论坛里面也有不少前人总结的好文档,

随机推荐