zookeeper介绍
什么是zookeeper?
zookpeeper是一个高可用的分布式管理与协调框架,基于ZAB算法也就是原子消息广播协议的实现。它能够很好的保证分布式环境中数据的一致性。也正是基于这样的特性,使得它成为了解决分布式一致性问题的利器。 它暴露了一些公共服务,比如配置维护、域名服务、分布式同步、组服务。我们可以使用zookeeper来实现比如集群管理、选举、分布式锁、分布式队列等功能。
zookeeper在hadoop生态系统中的地位:
zookeeper的特性:
- 顺序一致性,从一个客户端发起的事务请求最终将会严格地按照其发起的顺序被应用到zookeeper中去。
- 原子性,所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的。也就是说要么整个集群所有的机器都成功应用了某一事务。要么全部都没有应用,一定不会出现部分机器应用了该事务,而另一部分没有应用的情况。
- 单一视图,无论客户端连接的是哪一个zookeeper服务器。其看到的服务器端数据模型都是一致的。
- 可靠性,一旦服务器成功地应用了一个事务并完成了对客户端的响应。那么该事务所引起的服务器端状态将会被一直保留下来。除非有另外一个事务对其更改。
- 实时性,通常所说的实时性,就是指一旦事务被成功应用。那么客户端就能立即从服务器上获取变更后的新数据。zookeeper仅仅能保证在一段时间内客户端最终一定能从服务器端读取最新的数据状态。
zookeeper设计目标
- 目标1:简单的数据结构。zookeeper就是以简单的树形结构来进行相互协调的。
- 目标2:可以构建集群。一般 zookeeper集群通常由一组机器构成,一般3-5台机器就可以组成一个 zookeeper集群了。只要集群中超过半数以上的机器能够正常工作,那么整个集群就能够正常对外提供服务。
- 目标3:顺序访问。对于来自每户端的每一个请求,zookeeper都会分配一个全局唯一的递增编号,这个编号反应了所有事务操作的先后顺序。应用程序可以使用 zookeeper的这个特性来实现更高层次的同步。
- 目标4:高性能。由于 zookeeper将全量数据存储在内存中,并直接服务于所有的非事务请求,因此尤其是在读操作为主的场景下性能非常突出。在JMater压力测试下(100%读请求场景下),其结果大约在12~13W的QPS。
ZooKeeper的体系结构
ZooKeeper 所有组件:
领导者(leader),负责进行投票的发起和决议,更新系统状态
学习者(learner),包括跟随者(follower)和观察者(observer),follower用于接受客户端请求并想客户端返回结果,在选主过程中参与投票Observer可以接受客户端连接,将写请求转发给leader,但observer不参加投票过程,只同步leader的状态,observer的目的是为了扩展系统,提高读取速度
客户端(client),请求发起方,也就是我们自己的java程序
zookeeper的数据结构
ZooKeeper会维护一个具有层次关系的数据结构,非常类似于一个标准的文件系统,如下图所示:
ZooKeeper这种数据结构有如下这些特点:
- 每个子目录项如NameService都被称作znode,这个znode是被它所在的路径唯一标识,如Server1这个znode的标识为/NameService/Server1
- znode可以有子节点目录,并且每个znode可以存储数据,注意EPHEMERAL类型的目录节点不能有子节点目录
- znode是有版本的,每个znode中存储的数据可以有多个版本,也就是一个访问路径中可以存储多份数据
- znode可以是临时节点,一旦创建这个znode的客户端与服务器失去联系,这个znode也将自动删除,ZooKeeper的客户端和服务器通信采用长连接方式,每个客户端和服务器通过心跳来保持连接,这个连接状态成为session,如果znode是临时节点,这个session失效,znode也就被删除.
- znode的目录名可以自动编号,如App1已经存在,再创建的话,将会自动命名为App2.
- znode可以被监控,包括这个目录节点中存储的数据被修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个是ZooKeeper的核心特性.
ZooKeeper的典型应用场景
Zookeeper从设计模式角度来看,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应,从而实现集群中类似:Master/Slave管理模式、配置管理、集群管理、发布与订阅、数据库切换、分布式日志的收集、分布式环境、队列管理等等
- 配置管理:配置的管理在分布式应用环境中很常见,比如我们在平常的应用系统
中经常会碰到这样的需求:如机器的配置列表、运行时的开关配置、数据库配置信
息等。这些全局配置信息通常具备以下3个特性
1.数据量比较小
2.数据内容在运行时动态发生变化
3.集群中各个节点共享信息,配置一致 - 集群管理: Zookeeper不仅能够帮你维护当前的集群中机器的服务状态,而且能够帮你选出一个“总管”,让这个总管来管理集群,这就是 Zookeeper的另一个功能Leader,它能实现集群容错功能
1.知道当前集群中究竟有多少机器工作
2.对集群中每台机器的运行时状态进行数据收集
3.对集群中每台机器进行上下线操作 - 数据库切换:比如我们初始化zookeeper的时候读取其节点上的数据库配置文件,当配置发生变更时,zookeeper就能帮助我们把变更的通知发送到各个客户端,每个客户端在收到这个通知的时候就可以重新获取最新的数据
- 分布式日志收集:我们可以做一个日志系统收集集群中所有的日志信息,进行统一管理
- zookeeper的特性就是在分布式场景下高可用但是原生的API实现分布式功能非常困难,团队去实现太浪费时间,即使实现了也未必稳定那么可以采用第三方的客户端的完美实现,比如Apache的顶级项目 Curator框架。
Zookeeper选举
在zookeeper的选举过程中,为了保证选举过程最后能选出leader,就一定不能出现两台机器得票相同的僵局,所以一般的,要求zk集群的server数量一定要是奇数,也就是2n+1台,并且,如果集群出现问题,其中存活的机器必须大于n+1台,否则leader无法获得多数server的支持,系统就自动挂掉。所以一般是3个或者5个或者7个节点以此类推。
三台主机的选举过程:
A提案说,我要选自己,B你同意吗?C你同意吗?B说,我同意选A;C说,我同意选A。(注意,这里超过半数了,其实在现实世界选举已经成功了。但是计算机世界是很严格,另外要理解算法,要继续模拟下去。 接着B提案说,我要选自己,A你同意吗;A说,我已经超半数同意当选,你的提案无效;C说,A已经超半数同意当选,B提案无效。接着C提案说,我要选自己,A你同意吗;A说,我已经超半数同意当选,你的提案无效;B说,A已经超半数同意当选,C的提案无效。选举已经产生了Leader,后面的都是follower,只能服从Leader的命令。而且这里还有个小细节,就是其实谁先启动谁当头。
Zookeeper安装配置
1、结构:一共三个节点(zk服务器集群规模不小于3个节点),要求服务器之间系统时间保持一致。
2、上传zk
进行解压:tar -zxvf zookeeper-3.4.5.tar.gz
重命名:mv zookeeper-3.4.5 zookeeper1
修改环境变量:vim /etc/profile
export ZOOKEEPER_HOME=/usr/local/zookeeper1
export PATH=.:$ZOOKEEPER_HOME/bin:$JAVA_HOME/...
刷新环境变量: source /etc/profile
到zookeeper下修改配置文件
cd /usr/local/zookeeper1/conf
mv zoo_sample.cfg zoo.cfg
修改conf: vim zoo.cfg 修改两处
(1)dataDir=/usr/local/zookeeper1/data
(2)最后面添加
server.1=127.0.0.1:20881:30881
server.2=127.0.0.1:20882:30882
server.3=127.0.0.1:20883:30883
服务器标识配置:
创建文件夹:mkdir data
创建文件myid并填写内容为1:vi myid (内容为服务器标识 : 1)
进行复制zookeeper1目录到zookeeper2和zookeeper3
还有/etc/profile文件
把zookeeper2、zookeeper3中的myid文件里的值修改为2和3
启动zookeeper:
路径:/usr/local/zookeeper1/bin
执行:zkServer.sh start
(注意这里3台机器都要进行启动)
状态:zkServer.sh status(在三个节点上检验zk的mode,一个leader和两个follower)
zoo.cfg详解:
tickTime: 基本事件单元,以毫秒为单位。这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每隔 tickTime时间就会发送一个心跳。默认2000毫秒
*dataDir:存储内存中数据库快照的位置,顾名思义就是 Zookeeper 保存数据的目录,默认情况下,Zookeeper将写数据的日志文件也保存在这个目录里。
clientPort: 这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper会监听这个端口,接受客户端的访问请求。
initLimit:这个配置项是用来配置 Zookeeper接受客户端初始化连接时最长能忍受多少个心跳时间间隔数,当已经超过 10 个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 10*2000=20 秒。
syncLimit:这个配置项标识 Leader 与 Follower之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 5*2000=10 秒
server.A = B:C:D : A表示这个是第几号服务器, B 是这个服务器的 ip 地址;C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader
Zookeeper CLI
ZooKeeper 命令行界面(CLI)是用来与 ZooKeeper 集成作开发进行交互的。这是在调试和使用不同的选项时的工作有用。
为了执行ZooKeeper的CLI操作, ZooKeeper服务器首先要启动 (“bin/zkServer.sh start”) , 然后使用 ZooKeeper 客户端 (“bin/zkCli.sh”). 当客户端启动后,可以执行以下操作 -
创建Znode
由一个给定的路径来创建znode。flag参数指定了创建的 znode 是否为短暂的,持久的,或连续的。默认情况下,所有的 znodes是持久的。
短暂 znode(flag: e)当会话过期或当客户端断开连接将被自动删除。
连续 znode 保证 znode 路径是唯一的。
语法:create /path data
要创建一个连续znode,如下图所示添加 -s 标志。
语法:create -s /path data
要创建一个临时Znode,添加-e标志,如下图所示。
语法:create -e /path data
记住,当丢失一个客户端连接,在临时 znode 将被删除。可以通过退出 ZooKeeper CLI 尝试,然后重新打开命令行。获取数据
它返回 znode 的相关数据和指定 znode 元数据。这里将得到信息,例如当数据最后一次修改,在那里它被修改和有关数据的信息。此外 CLI 还用于分配监视显示通知有关的数据。
语法:get /path设置数据
设置指定znode的数据。当你完成设置操作,就可以使用get CLI命令检查数据。
语法
set /path data创建子znode
创建子znode类似于创建新的znodes。唯一的区别在于,子 znode 的路径将包含有父路径。
语法:create /parent/path/subnode/path data列出子znode
该命令用于列出和显示子 znode 。
语法:ls /path检查状态
状态描述了指定znode的元数据。它包含详细信息,如时间戳,版本号,访问控制列表,数据长度和子znode。
语法:stat /path删除Znode
删除指定znode和递归删除所有的子znode。这只有在znode可用时发生。
语法:rmr /path
删除(删除/路径)命令类似remove命令,但它仅适用于无子znode的znode。
语法:delete /path
Zookeeper API
ZooKeeper有一个Java和C绑定的官方API。ZooKeeper社区提供了对于大多数语言(.NET,Python等)的非官方API。使用ZooKeeper的API,应用程序可以连接,互动,操作数据,协调,以及从ZooKeeper集成断开。
ZooKeeper API有一组丰富的功能,在一个简单而安全的方式在ZooKeeper集成获得所有功能。ZooKeeper API提供同步和异步方法。
ZooKeeper的集成和ZooKeeper API 在各个方面完全互补,它有利于开发商在一个简便的方式。 在本章讨论Java绑定。
ZooKeeper的API基础知识
应用程序使用 ZooKeeper 集成的交互称为 ZooKeeper 客户端。
Znode 是 ZooKeeper 集成的核心组件,ZooKeeper API提供一个方法来处理znode所有使用ZooKeeper 集成。
客户端应遵循下面给出带 ZooKeeper 集成一个清晰的交互步骤。
连接到ZooKeeper 。ZooKeeper 集成分配客户端的会话ID。
定期发送心跳到服务器。否则,ZooKeeper 集成过期的会话ID,那么客户端需要重新连接。
获得/设置只要znodes会话ID是活动的。
从 ZooKeeper 集成断开,当所有的任务都完成后。如果客户端处于非活动状态较长时间,那么 ZooKeeper 集成会自动断开客户机。
Java代码
ZooKeeper API的中心部分是ZooKeeper 类。它提供了一些选项来连接 ZooKeeper 集成在其构造,有以下几种方法
connect − 连接到 ZooKeeper 的集成
create − 创建一个 znode
exists − 检查znode是否存在及其信息
getData − 从一个特定的znode获取数据
setData − 设置数据在特定znode
getChildren − 得到一个特定 znode 的所有可用子节点
delete − 删除一个特定的 znode 及其所有子节点
close − 关闭连接
连接到 ZooKeeper 集合
ZooKeeper类通过它的构造函数提供了连接功能。构造函数的签名如下:
ZooKeeper(String connectionString, int sessionTimeout, Watcher watcher)
在这里,
connectionString − ZooKeeper集合主机。
sessionTimeout − 以毫秒为单位会话超时。
watcher − 一个执行对象“观察者”的接口。ZooKeeper 集合返回通过监控器对象的连接状态。