ZooKeeper 的原理浅析和单机环境搭建
- ZooKeeper基本概念
- Zookeeper是什么?
Zookeeper官网地址:http://zookeeper.apache.org/
ZooKeeper官网文档地址:http://zookeeper.apache.org/doc/r3.4.10/
ZooKeeper是Hadoop下的一个子项目,它是一个针对大型分布式系统的可靠协调系统;
它提供的功能包括:配置维护、名字服务、分布式同步、组服务等;它的目标就是封装好复杂出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
ZooKeeper一个最常用的使用场景就是用于担任服务生产者和服务消费者的注册中心,服务生产者将自己提供的服务注册到ZooKeeper中心,服务的消费者在进行服务调用的时候先到ZooKeeper中查找服务,获取到服务生产者的详细信息之后,再去调用服务生产者的内容与数据,见到那的示例图如下:
2.ZooKeeper设计目标:
ZooKeeper允许分布式进程通过共享的层次结构命名空间进行相互协调,这与标准文件系统类似。名称空间由ZooKeeper中的数据寄存器组成--称为znode,这些类似于文件和目录。与为存储设计的典型文件系统不同,ZooKeeper数据保存在内存中,者意味着ZooKeeper可以实现高吞吐量和低延迟。
ZooKeeper层次结构图为树形结构图,通过这种树形结构图的数据模型,很容易查找到具体的某一个服务。
- ZooKeeper主要特点:
- 最终一致性:为客户端展示同一试图,这是ZooKeeper最重要的性能。
- 可靠性:如果消息被一台服务器接受,那么它将被所有的服务器接受。
- 实时性:ZooKeeper不能保证两个客户端同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。
- 等待无关(wait-free): 慢的或者失效的client不干预快速的client的请求。
- 原子性:更新只能成功或者失败,没有中间其他的状态。
- 顺序性:对于所有的Server,同一消息发布顺序一致。
- ZooKeeper 基本原理
- ZooKeeper 系统架构
首先看一下ZooKeeper的架构图
ZooKeeper 的架构图中我们需要了解和掌握的主要有:
- ZooKeeper分为服务端(Server)和客户端(Client),客户端可以连接到整个ZooKeeper 服务的任意服务器上(除非LeaderServers参数被显示设置,Leader不允许接受客户端连接)。
- 客户端使用并维护一个TCP连接,通过这个连接发送请求、接受响应、获取观察的事件以及发送心跳。如果这个TCP连接中断,客户端将自动尝试连接到另外的ZooKeeper服务器。客户端第一次连接到ZooKeeper服务时,接受这个连接的ZooKeeper服务器会为这个客户端建立一个会话。当这个客户端连接到另外的服务器时,这个会话会被新的服务器重新建立。
- 上图中的每一个Server代表一个安装ZooKeeper服务的机器,即是整个提供ZooKeeper服务的集群(或者是由伪集群组成);
- 组成ZooKeeper服务的服务器必须彼此了解。它们维护一个内存中的状态图像,以及持久存储中的事务日志和快照,只要大多数服务器可用,ZooKeeper服务就可用;
- ZooKeeper启动时,将从实例中选举一个Leader,Leader负责处理数据更新操作,一个更新操作成功的标志当且仅当大多数Server在内存中成功修改数据。每个Server在内存中存储了一份数据。
- ZooKeeper是可以集群复制的,集群间通过Zab协议(ZooKeeper Atomic Broadcast)来保持数据的一致性;
- Zab协议包含两个阶段:Leader election阶段和Atomic Brodcast阶段。
- 集群中将选举出一个Leader,其他的机器则称为follower,所有的写操作都被传送给Leader,并通过brodcast将所有的更新告诉给follower。
- 当Leader崩溃或者Leader失去大多数的follower时,需要重新选举一个新的Leader,让所有的服务器都恢复到一个正确的状态。
- 当Leader被选举出来,且大多数服务器完成了和Leader的状态同步后,Leader election的过程就结束了,就将会进入到Atomic Brodcast的过程。
- Atomic Brodcast同步Leader和Follower之间的信息,保证Leader和Follower具有相同的系统状态。
- ZooKeeper 角色
启动ZooKeeper服务器集群环境后,多个ZooKeeper服务器在工作前会选举出一个Leader。选举出Leader前,所有server不区分角色,都需要平等参数投票(obServe除外,不参与投票);
选举过程完成后,存在以下几种角色:
角色 | 描述 |
领导者(Leader) | 领导者负责进行投票的发起和决议,更新系统状态 |
学习者(Leader)或跟随者(Follower) |
Follower用于接收客户请求并向客户端返回结果,在选举的过程中参与投票。 Follower可以接收client请求,如果是写请求将转发给leader来更新系统状态。 |
观察者(ObServer) | ObServer可以接收客户端连接,将写请求转发给leader节点。但ObServer不参与投票过程,只同步leader的状态。ObServer的目的是为了扩展系统,提高读取速度。 |
- ZooKeeper 写数据流程
ZooKeeper 的写数据流程主要分为以下几个步骤:
- 比如Client向ZooKeeper 的Server1 上写数据,发送一个写请求。
- 如果Server1不是Leader,那么Server1 会把接受到的请求进一步转发给Leader,因为每个ZooKeeper的Server里面有一个是Leader。这个Leader会将写请求广播给各个Server,比如Server1和Server2,各个Server写成功后就会通知Leader。
- 当Leader收到大多数Server数据写成功了,那么就说明数据写成功了。如果这里三个节点的话,只要有两个节点数据写成功了,那么就认为数据写成功了。写成功之后,Leader会告诉Server1数据写成功了。
- Server1会进一步通知Client数据写成功了,这时就认为整个写操作成功。
- 三、ZooKeeper 应用场景总结
- 统一命名服务
- 在分布式环境下,经常需要对应用服务器进行统一命名,便于识别不同服务。
- 类似于域名与IP之间对应关系,IP不容易记住,而域名容易记住。
- 通过名称来获取资源或服务的地址,提供者等信息。
- 按照层次结构组织服务/应用名称。
- 可将服务名称以及地址信息写到ZooKeeper上,客户端通过ZooKeeper获取可用服务列表类。
- 配置管理
- 分布式环境下,配置文件管理和同步是一个常见问题。
- 一个集群中,所有节点的配置信息是一致的,比如Hadoop集群
- 对配置文件修改后,希望能够快速同步到各个节点上。
- 配置管理可交由ZooKeeper实现。
- 可将配置信息写入ZooKeeper上的一个Znode。
- 各个节点监听这个Znode。
- 一旦Znode中的数据被修改,ZooKeeper将通知各个节点。
- 集群管理
- 分布式环境中,实时掌握每个节点的状态是必要的。
- 可根据节点实时状态做出一些调整。
- 可交由ZooKeeper实现。
- 可将节点信息写入ZooKeeper上的一个Znode。
- 监听这个Znode可获取它的实时状态变化。
- 典型应用
- HBase中Master状态监控与选举。
- 分布式通知与协调
- 分布式环境中,经常存在一个服务器需要它所管理的子服务器的状态。
- NameNode需知道各个Datanode的状态。
- JobTracker需知道各个TaskTracker的状态。
- 心跳检测机制可通过ZooKeeper来实现。
- 信息推送可由ZooKeeper来实现,ZooKeeper相当于一个发布/订阅系统。
5、分布式锁
处于不同节点上不同的服务,它们可能需要顺序的访问一些资源,这里需要一把分布式的锁。
分布式锁具有以下的特性:
- ZooKeeper是强一致的。比如各个节点上运行一个ZooKeeper客户端,它们同时创建相同的Znode,但是只有一个客户端创建成功。
- 实现锁的独占性。创建Znode成功的那个客户端才能得到锁,其他客户端只能等待。当前客户端用完这个锁后,会删除这个Znode,其他客户端再尝试创建Znode,获取分布式锁。
- 控制锁的时序。各个客户端在某个Znode下创建临时Znode,这个类型必须为
CreateMode.EPHEMERAL_SEQUENTIAL,这样该Znode可掌握全局访问时许。
6、分布式队列
分布式队列分为两种:
- 当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达,这种是同步队列。
- 一个Job由多个task组成,只有所有任务完成后,Job才运行完成。
- 可为Job创建一个Job目录,然后在该目录下,为每个完成的task创建一个临时的Znode,一旦临时节点数目达到task总数,则表明Job运行完成。
- 队列按照FIFO方式进行入队和出队操作,例如实现生产者和消费者模型。
搭建ZooKeeper环境
tar -zxvf zookeeper-3.4.10.tar.gz -C ~/training/
配置环境变量 vi ~/.bash_profile
ZOOKEEPER_HOME=/root/training/zookeeper-3.4.10
export ZOOKEEPER_HOME
PATH=$ZOOKEEPER_HOME/bin:$PATH
export PATH
环境变量
source ~/.bash_profile
配置文件:cd /root/training/zookeeper-3.4.10/conf
cp zoo_sample.cfg zoo.cfg
vi zoo.cfg
在12行 dataDir=/root/training/zookeeper-3.4.10/tmp
1、单节点的ZK(standalone): bigdata11
31行 server.1=bigdata11:2888:3888
在/root/training/zookeeper-3.4.10/tmp上创建文件: vi myid 输入一个1
启动:zkServer.sh start
客户端: zkCli.sh (localhost:2181)
配置参数解读
解读zoo.cfg文件中参数含义
1)tickTime=2000:通信心跳数,Zookeeper服务器心跳时间,单位毫秒
Zookeeper使用的基本时间,服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个tickTime时间就会发送一个心跳,时间单位为毫秒。
它用于心跳机制,并且设置最小的session超时时间为两倍心跳时间。(session的最小超时时间是2*tickTime)
2)initLimit=10:Leader和Follower初始通信时限
集群中的follower跟随者服务器与leader领导者服务器之间初始连接时能容忍的最多心跳数(tickTime的数量),用它来限定集群中的Zookeeper服务器连接到Leader的时限。
投票选举新leader的初始化时间
Follower在启动过程中,会从Leader同步所有最新数据,然后确定自己能够对外服务的起始状态。
Leader允许Follower在initLimit时间内完成这个工作。
3)syncLimit=5:Leader和Follower同步通信时限
集群中Leader与Follower之间的最大响应时间单位,假如响应超过syncLimit * tickTime,Leader认为Follwer死掉,从服务器列表中删除Follwer。
在运行过程中,Leader负责与ZK集群中所有机器进行通信,例如通过一些心跳检测机制,来检测机器的存活状态。
如果L发出心跳包在syncLimit之后,还没有从F那收到响应,那么就认为这个F已经不在线了。
4)dataDir:数据文件目录+数据持久化路径
保存内存数据库快照信息的位置,如果没有其他说明,更新的事务日志也保存到数据库。
5)clientPort=2181:客户端连接端口
监听客户端连接的端口
启动
查看状态
查看zookeeper 的根目录
get 命令详解
hahaha为节点数据信息
cZxid节点创建时的zxid
ctime节点创建时间
mZxid节点最近一次更新时的zxid
mtime节点最近一次更新的时间
cversion子节点数据更新次数
dataVersion本节点数据更新次数
aclVersion节点ACL(授权信息)的更新次数
ephemeralOwner如果该节点为临时节点,ephemeralOwner值表示与该节点绑定的session id. 如果该节点不是临时节点,ephemeralOwner值为0
dataLength节点数据长度,本例中为hahaha的长度
numChildren子节点个数
set 命令
设置节点的数据
set /node1 “hello world”
rmr 命令
删除节点命令,此命令与delete命令不同的是delete不可删除有子节点的节点,但是rmr命令可以删除,注意路径为绝对路径。
rmr /node1
delquota 命令
删除配额,-n为子节点个数,-b为节点数据长度。
如: delquota -n 2,
quit命令
退出ZooKeeper客户端
printwatches命令
设置和显示监视状态,on或者off
create 命令
创建节点,其中-s为顺序节点,-e为临时节点
创建永久节点 create /node1 he
创建临时节点 create -e /node1/node2 hahha 退出会话数据消失
创建顺序节点
create -s /node1/node2 hehehe
在node1节点下创建node2节点,返回的是node20000000001(序列)
继续执行这一条命令,发现***加一了,这就是顺序节点
stat命令
查看节点的状态信息,sata与get命令的区别是get多了一行节点的值信息。
close 命令
断开客户端与服务端的连接。
ls2命令
ls2为ls命令的扩展,比ls命令多输出本节点信息。
history 命令
列出最近的历史命令,相当于Linux下的history命令
listquota 命令
显示配额
如: listquota /node1
setAcl命令
设置节点Acl
acl由大部分组成:1为scheme,2为user,3为permission,一般情况下表示为scheme:id:permissions
其中scheme和id是相关的。
scheme和id
word:它下面只有一个id,叫anyone,world:anyone代表任何人,zookeeper中对所有人有权限的结点就是属于world:anyone的
auth: 它不需要id,只要是通过authenticcation的user都有权限(zookeeper支持通过kerberos来进行authencation,也支持username/password形式的authentication)
digest: 它对应的id为username:BASE64(SHA1(password)),它需要先通过username:password形式的authentication
ip:它对应的id为客户机的IP地址,设置的时候可以设置一个ip段,比如ip:192.168.100.0/16,
表示匹配前16个bit的IP段
super:在这种scheem情况下,对应的id拥有超级权限,可以做任何事情(cdrwa)
Permissions
CREATE(c): 创建权限,可以在在当前node下创建child node
DELETE(d): 删除权限,可以删除当前的node
READ(r): 读权限,可以获取当前node的数据,可以list当前node所有的child nodes
WRITE(w): 写权限,可以向当前node写数据
ADMIN(a): 管理权限,可以设置当前node的permission
综上,一个简单使用setAcl命令,则可以为:
setAcl /node1/node2 world:anyone:cdrw
getAcl命令
获取节点Acl
如:getAcl /node1/node2
sync 命令
强制同步
如:sync /node1
由于请求在半数以上的zk server上生效就表示此请求生效,那么就会有一些zk server上的数据是旧的。sync命令就是强制同步所有的更新操作。
redo命令
再次执行某命令。
如:redo 22
其中22为命令ID,需与history配合使用。
addauth命令
节点认证。
如addauth digest username:password,可参见setAcl命令digest
使用方法:
- 通过setAcl设置用户名和密码
setAcl pathdigest:username:base64(sha1(password)):crwda
- 认证
addauth digest username:password
delete命令
删除节点
如delete /node1
setquota命令
设置子节点个数和数据长度配额。
如:
setquota -n 4 /node1/node2 设置/node1/node2子节点个数最大为4
setquota -b 100 /node1/node2 设置/node1/node2节点长度最大字节数为100
注意:这个只能对同一个节点设置一种配额方式
listquota命令
显示配额。
如listquota /zookeeper/quota/node3
解释:
/zookeeper节点个数限额为5,长度无限额。