zookeeper 快速入门

分布式系统简介

在分布式系统中另外一个须要解决的重要问题就是数据的复制。咱们平常开发中,不少人会碰到一个问题:客户端C1更新了一个值K1由V1更新到V2.可是客户端C2没法当即读取到K的最新值。上面的例子就是常见的数据库之间复制的延时问题。html

分布式系统对于数据的复制通常因为:java

  1. 为了增长系统的可用性,以防止单点故障引发的系统不可用。
  2. 提升系统的总体性能,经过负载均衡,可以让分布在不一样地方的数据副本都可以为用户提供服务。

为了解决复制延时的问题,能够等待全部复制都完成后,在进行下一次更新,但这会带来性能问题。
为了保证数据一致性,同时又不能影响系统运行的性能,因而,一致性级别由此诞生。node

  • 强一致性: 系统写入什么,读出来就是什么,对系统的性能影响比较大。
  • 弱一致性: 系统在写入后,不承诺当即能够读取写入的值,但会尽量的保证在某个时间级别后,达到一致性状态。
    • 会话一致性: 对于写入的值,同一个客户端会话中能够读取到一致的值。
    • 用户一致性: 对于写入的值,在同一个用户中能够读取到一致性的值,其余用户不能保证。
  • 最终一致性:跟弱一致性中很是重要的一种一致性模型,也是业界在大型分布式系统的数据一致性上比较推崇的模型。

zookeeper 产生的缘由

Zookeeper是Hadoop分布式调度服务,用来构建分布式应用系统。构建一个分布式应用是一个很复杂的事情,主要的缘由是咱们须要合理有效的处理分布式集群中的部分失败的问题。例如,集群中的节点在相互通讯时,A节点向B节点发送消息。A节点若是想知道消息是否发送成功,只能由B节点告诉A节点。那么若是B节点关机或者因为其余的缘由脱离集群网络,问题就出现了。A节点不断的向B发送消息,而且没法得到B的响应。B也没有办法通知A节点已经离线或者关机。集群中其余的节点彻底不知道B发生了什么状况,还在不断的向B发送消息。这时,你的整个集群就发生了部分失败的故障。git

Zookeeper不能让部分失败的问题完全消失,可是它提供了一些工具可以让你的分布式应用安全合理的处理部分失败的问题。github

zookeeper工做原理

Zookeeper 的核心是广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫作Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播 模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步之后, 恢复模式就结束了。状态同步保证了leader和Server具备相同的系统状态。为了保证事务的顺序一致性,zookeeper采用了递增的事务id号 (zxid)来标识事务。全部的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用 来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递 增计数。算法

zab协议核心内容

zab协议的核心是定义了对于那些会改变zookeeper服务器数据状态的事务请求的处理方式,即:全部事务请求必须由一个全局惟一的服务器来协调处理,这样的服务器被称为Leader服务器,而余下的其余服务器则成为Follower服务器。Leader服务器负责将一个客户端事务请求转换成一个事务Proposal(提倡),并将该Proposal分发给集群中全部的Follower 服务器。以后Leader服务器须要等待全部Follower服务器的反馈,一旦超过半数的Follower服务器进行了正确的反馈后,那么Leader就会再次向全部的Follower服务器分发Commit消息,要求将其前一个Proposal进行提交。

每一个Server在工做过程当中有三种状态:

  • LOOKING:当前Server不知道leader是谁,正在搜寻。
  • LEADING:当前Server即为选举出来的leader。
  • FOLLOWING:leader已经选举出来,当前Server与之同步。

每一个集群中的三种状态

  • Leader : 为客户端提供读和写服务。
  • Follower: 为客户端提供读服务。
  • observer: 为客户端提供读服务,可是不参与Leader选举,也不参与写操做的“过办写成功”策略。因此 observer能够在不影响写性能的状况下提高集群的读性能。

zookeeper 特性

  1. 顺序一致性:从同一个客户端发起的事务请求,最终将严格按照其发起顺序被应用到ZooKeeper中。
  2. 原子性:更新操做要么成功要么失败,没有中间状态。
  3. 单一视图(Single system image):无论客户端链接哪个服务器,客户端看到服务端的数据模型都是一致的(the same view of service)。
  4. 可靠性(Reliability): 一旦一个更新成功,那么那就会被持久化,直到客户端用新的更新覆盖这个更新。
  5. 实时性(Timeliness):Zookeeper仅保证在必定时间内,客户端最终必定可以从服务端读到最新的数据状态。

基本概念

zookeeper数据模型

Zookeeper 会维护一个具备层次关系的数据结构,它很是相似于一个标准的文件系统. 名称叫作zNode。shell

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 的不少功能都是基于这个特性实现的。

Node能够分为持久节点(PERSISTENT)和临时节点(EPHEMERAL)两类。所谓持久节点是指一旦这个 ZNode被建立了,除非主动进行移除操做,不然这个节点将一直保存在 Zookeeper上。而临时节点的生命周期,是与客户端会话绑定的,一旦客户端会话失效,那么这个客户端建立的全部临时节点都会被移除。
另外,Zookeeper还有一种 顺序节点(SEQUENTIAL)。该节点被建立的时候,Zookeeper会自动在其子节点名上,加一个由父节点维护的、自增整数的后缀 (上限: Integer.MAX_VALUE)。该节点的特性,还能够应用到 持久/临时节点 上,组合成 持久顺序节点 (PERSISTENT_SEQUENTIAL) 和 临时顺序节点 ( EPHEMERAL_SEQUENTIAL)apache

会话

Session指客户端会话。在 Zookeeper中,一个客户端会话是指 客户端和服务器之间的一个TCP长链接。客户端启动的时候,会与服务端创建一个TCP链接,客户端会话的生命周期,则是从第一次链接创建开始算起。经过这个链接,客户端可以经过心跳检测与服务器保持有效的会话,并向 Zookeeper服务器发送请求并接收响应,以及接收来自服务端的 Watch事件通知。vim

Session的 sessionTimeout参数,用来控制一个客户端会话的超时时间。当服务器压力太大 或者是网络故障等各类缘由致使客户端链接断开时,Client会自动从 Zookeeper地址列表中逐一尝试重连 (重试策略可以使用 Curator来实现)。只要在 sessionTimeout规定的时间内可以从新链接上集群中任意一台服务器,那么以前建立的会话仍然有效。若是,在 sessionTimeout时间外重连了,就会由于 session已经被清除了,而被告知 SESSION_EXPIRED,此时须要程序去恢复临时数据;还有一种 Session重建后的在新节点上的数据,被以前节点上因网络延迟晚来的写请求所覆盖的状况,在 ZOOKEEPER-417中被提出,并在该 JIRA中新加入的 SessionMovedException,使得 用同一个sessionld/sessionPasswd 重建 Session的客户端能感知到,可是这个问题到 ZOOKEEPER-2219仍然没有获得很好的解决。

版本

Zookeeper的每一个 ZNode上都会存储数据,对应于每一个 ZNode,Zookeeper都会为其维护一个叫作 Stat的数据结构,Stat中记录了这个 ZNode的三个数据版本,分别是 version(当前 ZNode数据内容的版本),cversion(当前 ZNode子节点的版本)和 aversion (当前 ZNode的 ACL变动版本)。这里的版本起到了控制 Zookeeper操做原子性的做用 (详见 “源码分析 - 落脚点 - Zookeeper乐观锁”)

watch

Watcher(事件监听器)是 Zookeeper提供的一种 发布/订阅的机制。Zookeeper容许用户在指定节点上注册一些 Watcher,而且在一些特定事件触发的时候,Zookeeper服务端会将事件通知给订阅的客户端。该机制是 Zookeeper实现分布式协调的重要特性

ACL

相似于 Unix文件系统,Zookeeper采用 ACL(Access Control Lists)策略来进行权限控制 (使用格式
setAcl <path> <acl: scheme + id + permissions>)。
例子:

setAcl /zk world:anyone:cdrw
  • CREATE (c): 建立子节点的权限。
  • READ (r): 获取节点数据和子节点列表的权限。
  • WRITE (w): 更新节点数据的权限。
  • DELETE (d): 删除当前节点的权限。
  • ADMIN (a): 管理权限,能够设置当前节点的permission。
scheme ID comment
world anyone Zookeeper中对全部人有权限的结点就是属于 world:anyone
auth 不须要id 经过 authentication的 user都有权限
digest username:BASE64 (SHA1(password)) 须要先经过 username:password形式的 authentication
ip id为客户机的IP地址(或者 IP地址段) ip:192.168.1.0/14,表示匹配前 14个bit的 IP段
super 对应的 id拥有超级权限 (CRWDA)

Zookeeper支持经过 kerberos来进行 authencation,也支持 username/password形式的 authentication。

ZooKeeper 典型的应用场景

Zookeeper 做为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题,它能提供基于相似于文件系统的目录节点树方式的数据存储,可是 Zookeeper 并非用来专门存储数据的,它的做用主要是用来维护和监控你存储的数据的状态变化。经过监控这些数据状态的变化,从而能够达到基于数据的集群管理。

Zookeeper 从设计模式角度来看,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理你们都关心的数据,而后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper 就将负责通知已经在 Zookeeper 上注册的那些观察者作出相应的反应,从而实现集群中相似 Master/Slave 管理模式,关于 Zookeeper 的详细架构等内部细节能够阅读 Zookeeper 的源码

统一命名服务(Name Service)

分布式应用中,一般须要有一套完整的命名规则,既可以产生惟一的名称又便于人识别和记住,一般状况下用树形的名称结构是一个理想的选择,树形的名称结构是一个有层次的目录结构,既对人友好又不会重复。说到这里你可能想到了 JNDI,没错 Zookeeper 的 Name Service 与 JNDI 可以完成的功能是差很少的,它们都是将有层次的目录结构关联到必定资源上,可是 Zookeeper 的 Name Service 更加是普遍意义上的关联,也许你并不须要将名称关联到特定资源上,你可能只须要一个不会重复名称,就像数据库中产生一个惟一的数字主键同样。
Name Service 已是 Zookeeper 内置的功能,你只要调用 Zookeeper 的 API 就能实现。如调用 create 接口就能够很容易建立一个目录节点。

配置管理(Configuration Management)

配置的管理在分布式应用环境中很常见,例如同一个应用系统须要多台 PC Server 运行,可是它们运行的应用系统的某些配置项是相同的,若是要修改这些相同的配置项,那么就必须同时修改每台运行这个应用系统的 PC Server,这样很是麻烦并且容易出错。
像这样的配置信息彻底能够交给 Zookeeper 来管理,将配置信息保存在 Zookeeper 的某个目录节点中,而后将全部须要修改的应用机器监控配置信息的状态,一旦配置信息发生变化,每台应用机器就会收到 Zookeeper 的通知,而后从 Zookeeper 获取新的配置信息应用到系统中。

集群管理(Group Membership)

Zookeeper 可以很容易的实现集群管理的功能,若有多台 Server 组成一个服务集群,那么必需要一个“总管”知道当前集群中每台机器的服务状态,一旦有机器不能提供服务,集群中其它集群必须知道,从而作出调整从新分配服务策略。一样当增长集群的服务能力时,就会增长一台或多台 Server,一样也必须让“总管”知道。
Zookeeper 不只可以帮你维护当前的集群中机器的服务状态,并且可以帮你选出一个“总管”,让这个总管来管理集群,这就是 Zookeeper 的另外一个功能 Leader Election。
它们的实现方式都是在 Zookeeper 上建立一个 EPHEMERAL 类型的目录节点,而后每一个 Server 在它们建立目录节点的父目录节点上调用 getChildren(String path, boolean watch) 方法并设置 watch 为 true,因为是 EPHEMERAL 目录节点,当建立它的 Server 死去,这个目录节点也随之被删除,因此 Children 将会变化,这时 getChildren上的 Watch 将会被调用,因此其它 Server 就知道已经有某台 Server 死去了。新增 Server 也是一样的原理。
Zookeeper 如何实现 Leader Election,也就是选出一个 Master Server。和前面的同样每台 Server 建立一个 EPHEMERAL 目录节点,不一样的是它仍是一个 SEQUENTIAL 目录节点,因此它是个 EPHEMERAL_SEQUENTIAL 目录节点。之因此它是 EPHEMERAL_SEQUENTIAL 目录节点,是由于咱们能够给每台 Server 编号,咱们能够选择当前是最小编号的 Server 为 Master,假如这个最小编号的 Server 死去,因为是 EPHEMERAL 节点,死去的 Server 对应的节点也被删除,因此当前的节点列表中又出现一个最小编号的节点,咱们就选择这个节点为当前 Master。这样就实现了动态选择 Master,避免了传统意义上单 Master 容易出现单点故障的问题。

集群管理结构图

共享锁(Locks)

共享锁在同一个进程中很容易实现,可是在跨进程或者在不一样 Server 之间就很差实现了。Zookeeper 却很容易实现这个功能,实现方式也是须要得到锁的 Server 建立一个 EPHEMERAL_SEQUENTIAL 目录节点,而后调用 getChildren方法获取当前的目录节点列表中最小的目录节点是否是就是本身建立的目录节点,若是正是本身建立的,那么它就得到了这个锁,若是不是那么它就调用 exists(String path, boolean watch) 方法并监控 Zookeeper 上目录节点列表的变化,一直到本身建立的节点是列表中最小编号的目录节点,从而得到锁,释放锁很简单,只要删除前面它本身所建立的目录节点就好了。

Zookeeper 实现 Locks 的流程图

队列管理

Zookeeper 能够处理两种类型的队列:
当一个队列的成员都聚齐时,这个队列才可用,不然一直等待全部成员到达,这种是同步队列。
队列按照 FIFO 方式进行入队和出队操做,例如实现生产者和消费者模型。
同步队列用 Zookeeper 实现的实现思路以下:
建立一个父目录 /synchronizing,每一个成员都监控标志(Set Watch)位目录 /synchronizing/start 是否存在,而后每一个成员都加入这个队列,加入队列的方式就是建立 /synchronizing/member_i 的临时目录节点,而后每一个成员获取 / synchronizing 目录的全部目录节点,也就是 member_i。判断 i 的值是否已是成员的个数,若是小于成员个数等待 /synchronizing/start 的出现,若是已经相等就建立 /synchronizing/start。
用下面的流程图更容易理解:

同步队列流程图
FIFO 队列用 Zookeeper 实现思路以下:
实现的思路也很是简单,就是在特定的目录下建立 SEQUENTIAL 类型的子目录 /queue_i,这样就能保证全部成员加入队列时都是有编号的,出队列时经过 getChildren( ) 方法能够返回当前全部的队列中的元素,而后消费其中最小的一个,这样就能保证 FIFO。

zookeeper安装

zookeeper 集群分为:单机模式,伪集群,集群模式。

zookeeper配置文件解释

单机模式下须要修改的配置

tickTime=2000  
dataDir=/data/zk 
dataLogDir=/var/log/zookeeper/logs  
clientPort=2181
  • tickTime(CS通讯心跳数): Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每一个 tickTime 时间就会发送一个心跳。tickTime以毫秒为单位。
  • dataDir(数据文件目录):Zookeeper保存数据的目录,默认状况下,Zookeeper将写数据的日志文件也保存在这个目录里。
  • dataLogDir(日志文件目录):Zookeeper保存事务日志文件的目录。若是没有配置则存放在dataDir目录下。
  • clientPort(客户端链接端口):客户端链接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。

集群模式下须要增长的配置

initLimit=5  
syncLimit=2  
server.N=YYY:A:B
  • initLimit(LF初始通讯时限): 集群中的follower服务器(F)与leader服务器(L)之间初始链接时能容忍的最多心跳数(tickTime的数量)。
  • syncLimit(LF同步通讯时限): 集群中的follower服务器与leader服务器之间请求和应答之间能容忍的最多心跳数(tickTime的数量)。
  • server.N=YYY:A:B(服务器名称与地址:集群信息(服务器编号,服务器地址,LF通讯端口,选举端口): 这个配置项的书写格式比较特殊,规则以下:

其中N表示服务器编号,YYY表示服务器的IP地址,A为LF通讯端口,表示该服务器与集群中的leader交换的信息的端口。B为选举端口,表示选举新leader时服务器间相互通讯的端口(当leader挂掉时,其他服务器会相互通讯,选择出新的leader)。通常来讲,集群中每一个服务器的A端口都是同样,每一个服务器的B端口也是同样。可是当所采用的为伪集群时,IP地址都同样,只能时A端口和B端口不同。

正常集群的例子:

server.1=192.168.56.11:2181:2182
server.2=192.168.56.12:2181:2182
server.3=192.168.56.13:2181:2182

伪集群的例子:

server.1=192.168.56.11:2181:3181
server.2=192.168.56.11:2182:3182
server.3=192.168.56.11:2183:3183

单实例安装

安装zookeeper服务

cd /usr/local/src/
tar -zxf zookeeper-3.4.7.tar.gz 
mv zookeeper-3.4.7 /usr/local/
ln -s /usr/local/zookeeper-3.4.7/ /usr/local/zookeeper
cd /usr/local/zookeeper
cd conf/
cp zoo_sample.cfg zoo.cfg

编辑配置文件

vim zoo.cfg 
tickTime=2000
dataDir=/data/zk
clientPort=2181

启动zookeeper服务

/usr/local/zookeeper/bin/zkServer.sh start

检查服务是否正常启动

bin/zkCli.sh -server 127.0.0.1:2181

伪集群配置

cd /usr/local/src
wget http://mirrors.cnnic.cn/apache/zookeeper/stable/zookeeper-3.4.6.tar.gz
tar zxf zookeeper-3.4.6.tar.gz
mv zookeeper-3.4.6 /usr/local/
ln -s /usr/local/zookeeper-3.4.6/ /usr/local/zookeeper
cd /usr/local/zookeeper/conf/
mv zoo_sample.cfg zoo.cfg
vim zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zk1
clientPort=2181
server.1=192.168.56.11:3181:4181
server.2=192.168.56.11:3182:4182
server.3=192.168.56.11:3183:4183

建立三个目录用来存放zookeeper数据

mkdir /data/{zk1,zk2,zk3} -p
echo "1" >/data/zk1/myid
echo "2" >/data/zk2/myid
echo "3" >/data/zk3/myid

生成三份zookeeper配置文件

cp zoo.cfg zk1.cfg
cp zoo.cfg zk2.cfg
cp zoo.cfg zk3.cfg

修改zk2和zk3的配置,使用对应的数据目录和端口。

sed -i 's/zk1/zk2/g' zk2.cfg
sed -i 's/2181/2182/g' zk2.cfg
sed -i 's/zk1/zk3/g' zk3.cfg
sed -i 's/2181/2183/g' zk3.cfg

启动Zookeeper

/usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/zk1.cfg
/usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/zk2.cfg
/usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/zk3.cfg

查看Zookeeper角色

/usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/zk1.cfg
#JMX enabled by default
#Using config: /usr/local/zookeeper/conf/zk1.cfg
#Mode: follower
/usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/zk2.cfg
#JMX enabled by default
#Using config: /usr/local/zookeeper/conf/zk2.cfg
#Mode: `leader`
/usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/zk3.cfg
#JMX enabled by default
#Using config: /usr/local/zookeeper/conf/zk3.cfg
#Mode: follower

链接Zookeeper

/usr/local/zookeeper/bin/zkCli.sh -server192.168.56.11:2181

经过上面的例子能够看到,目前zk2是leader,其它两个节点是follower。
本文因为实验环境局限使用的是伪分布式。
生产环境不建议使用。

集群模式

集群模式的配置和伪集群基本一致.
因为集群模式下, 各server部署在不一样的机器上, 所以各server的conf/zoo.cfg文件能够彻底同样.

下面是一个示例:

tickTime=2000 
initLimit=5 
syncLimit=2 
dataDir=/home/zookeeper/data 
dataLogDir=/home/zookeeper/logs 
clientPort=4180 
server.1=192.168.56.11:3181:4182
server.2=192.168.56.12:3181:4182
server.3=192.168.56.13:3181:4182

示例中部署了3台zookeeper server, 分别部署在192.168.56.11, 192.168.56.12, 1192.168.56.13上. 须要注意的是, 各server的dataDir目录下的myid文件中的数字必须不一样,192.168.56.11 server的myid为1, 192.168.56.12 server的myid为2, 192.168.56.13server的myid为3。

java优化

看了你的问题, 我还特地的查看了ZooKeeper的启动脚本代码。ZooKeeper启动脚本没有加任何参数,也就是使用jvm默认的。
若是想要加大ZooKeeper的JVM使用内存。能够在更改{ZK_HOME}/bin/zkServer.sh,大约在109-110行。
nohup $JAVA "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \
    -cp "$CLASSPATH" $JVMFLAGS $ZOOMAIN "$ZOOCFG" > "$_ZOO_DAEMON_OUT" 2>&1 < /dev/null &
改成
nohup $JAVA "-Xmx1G -Xms1G -Dzookeeper.log.dir=${ZOO_LOG_DIR}"...

jmap -heap 查看设置是否成功

zookeeper 运维

zookeeper高级配置参数

系统属性方式配置:即在Java中,能够经过在启动的命令行参数中添加-D参数来达到配置系统属性的目的,例如-Djava.library.path=/home/admin/jdk/lib, 就是经过系统属性来配置java.library.path的。

  • dataLogDir: 该参数有默认值:dataDir,能够不配置,不支持系统属性方式配置。参数dataLogDir用于配置Zookeeper服务器存储事务日志文件的目录。默认状况下,Zookeeper会将事务日志文件和快照数据存储在同一个目录中,使用者应尽可能将这二者的目录区分开来。另外,若是条件容许,能够将事务日志的存储配置在一个单独的磁盘上。事务日志记录对于磁盘的性能要求很是高,为了保证数据的一致性,Zookeeper在返回客户端事务请求响应以前,必须将本次请求对应的事务日志写入到磁盘中。所以事务日志写入的性能直接决定了Zookeeper在处理事务请求时的吞吐。针对同一块磁盘的其余并发读写操做(例如Zookeeper运行时日志输出和操做系统自身的读写等),尤为是数据快照操做,会极大的影响事务日志的写性能。所以尽可能给事务日志的输出配置一个单独的磁盘或是挂载点,将极大地提高Zookeeper的总体性能
  • initLimit: 该参数有默认值:10,即表示是参数tickTime值的10倍,必须配置,且须要配置一个正整数,不支持系统属性方式配置。该参数用于配置Leader服务器等待Follower启动,并完成数据同步的时间。Follower服务器在启动过程当中,会与Leader创建链接并完成对数据的同步,从而肯定本身对外提供服务的起始状态。一般状况下,运维人员不用太在乎这个参数的配置,使用期默认值便可。但若是随着Zookeeper集群管理的数据量增大,Follower服务器在启动的时候,从Leader上进行同步数据的时间也会相应变长,因而没法在较短的时间完成数据同步。所以,在这种状况下,有必要适当调大这个参数。
  • syncLimit: 该参数有默认值:5,即表示是参数tickTime值的5倍,必须配置,且须要配置一个正整数,不支持系统属性当时配置。该参数用于配置Leader服务器和Follower之间进行心跳检测的最大延时事件。在Zookeeper集群运行过程当中,Leader服务器会与全部的Follower进行心跳检测来肯定该服务器是否存活。若是Leader服务器在syncLimit时间内没法获取到Follower的心跳检测响应,那么Leader就会认为该Follower已经脱离了和本身的同步。一般状况下,运维人员使用该参数的默认值便可,但若是部署Zookeeper集群的网络环境质量较低(例如网络延时较大或丢包严重),那么能够适当调大这个参数。
  • snapCount: 该参数有默认值:100000,能够不配置,仅支持系统属性方式配置:zookeeper.snapCount。参数snapCount用于配置相邻两次数据快照之间的事务操做次数,即Zookeeper会在snapCount次事务操做以后进行一次数据快照。
  • preAllocSize: 该参数有默认值:65536,单位是KB,即64MB,能够不配置,仅支持系统属性方式配置:zookeeper.preAllocSize。参数preAlloSize用于配置Zookeeper事务日志文件预分配的磁盘空间大小。一般状况下,咱们使用Zookeeper的默认配置65536KB便可,可是若是咱们将参数snapCount设置得比默认值更小或更大,那么preAllocSize参数也要随之作出变动。举例来讲:若是咱们将snapCount的值设置为500,同时预估每次事务操做的数据量大小至多1KB,那么参数preAllocSize设置为500就足够了。
  • maxClientCnxns: 该参数有默认值:60,能够不配置,不支持系统属性方式配置。从Socket层面限制单个客户端与单台服务器之间的并发链接数,即以IP地址粒度来进行链接数的限制。若是将该参数设置为0,则表示对链接数不作任何限制。须要注意该链接数限制选项的适用范围,其仅仅是对单台客户端机器与单台Zookeeper服务器之间的链接数限制,并不能控制全部客户端的链接数总和。另外,在3.4.0版本之前该参数的默认值都是10,从3.4.0版本开始变成了60,所以运维人员尤为须要注意这个变化,以防Zookeeper版本变化带来服务器链接数限制变化的隐患。
  • clientPortAddress: 该参数没有默认值:能够不配置,不支持系统属性方式配置。针对那些多网卡的机器,该参数容许为每一个IP地址制定不一样的监听端口。
  • forceSync: 该参数有默认值:yes,能够不配置,可选配置项为yes和no,仅支持系统属性方式配置:zookeeper.forceSync。该参数用于配置Zookeeper服务器是否在事务提交的时候,将日志写入操做强制刷入磁盘(即调用java.nio.channels.FileChannel.force接口),默认状况下是yes,即每次事务日志写入操做都会实时刷入磁盘。若是将其设置为no。则能必定程度的提升Zookeeper的写性能,但同事也会存在相似于机器断电这样的安全风险。
  • globalOutstandingLimit: 该参数有默认值:1000,能够不配置,仅支持系统属性方式配置:zookeeper.globalOutstandingLimit。参数globalOutstandingLimit用于配置Zookeeper服务器最大请求堆积数量。在Zookeeper服务器运行的过程当中,客户端会源源不断的将请求发送到服务端,为了防止服务端资源(包括CPU,内存和网络等)耗尽,服务端必须限制同时处理的请求数,即最大请求堆积数量。
  • leaderServes: 该参数有默认值:yes,能够不配置,可选配置项为yes和no,仅支持系统属性方式配置:zookeeper.leaderServes。该参数用于配置Leader服务器是否可以接受客户端的链接,便是否容许Leader向客户端提供服务,默认状况下,Leader服务器可以接受并处理客户端的全部读写请求。在Zookeeper的架构设计中,Leader服务器主要用来进行对事务更新请求的协调以及集群自己的运行时协调,所以,能够设置让Leader服务器不接受客户端的链接,以使其专一于进行分布式协调。
  • SkipAcl: 该参数有默认值:no,能够不配置,可选配置项为yes和no,仅支持系统属性方式配置:zookeeper.skipACL。该参数用于配置Zookeeper服务器是否跳过ACL权限检查,默认状况下是no,即会对每个客户端请求进行权限检查。若是将其设置为yes,则能必定程度的提升Zookeeper的读写性能,但同时也会向全部客户端开放Zookeeper的数据,包括那些以前设置过ACL权限的数据节点,也将再也不接收权限控制。
  • xncTimeout: 该参数有默认值:5000,单位是毫秒,能够不配置,仅支持系统属性方式配置:zookeeper.cnxTimeout。该参数用于配置在Leader选举过程当中,各服务器之间进行TCP链接建立的超时时间。
  • electionAlg: 在以前的版本中,可使用该参数来配置选择Zookeeper进行Leader选举时所使用的算法,但从3.4.0版本开始,Zookeeper废弃了其余选举算法,只留下了FastLeaderElection算法,所以该参数目前看来没有用了。
  • jute.maxbuffer: 该参数有默认值:1048575,单位是字节,能够不配置,仅支持系统属性方式配置:jute.maxbuffer。该参数用于配置单个数据节点(ZNode)上能够存储的最大数据量大小。一般状况下,运维人员不须要改动该参数,同时考虑到Zookeeper上不适宜存储太多的数据,每每还须要将该参数设置得更小。须要注意的是,在变动该参数的时候,须要在Zookeeper集群的全部机器以及全部的客户端上均设置才能生效。
  • minSessionTimeout/maxSessionTimeout: 这两个参数有默认值,分别是参数tickTime值的2倍和20倍,即默认的会话超时时间在2tickTime~20tickTime范围内,单位毫秒,能够不配置,不支持系统属性方式配置。这两个参数用于服务端对客户端会话的超时时间进行限制,若是客户端设置的超时事件再也不该范围内,那么会被服务端强制设置为最大或最小超时时间
  • autopurge.snapRetainCount: 该参数有默认值:3,能够不配置,不支持系统属性方式配置。从3.4.0版本开始,Zookeeper提供了对历史事务日志和快照数据自动清理的支持。参数autopurge.snapRetainCount用于配置Zookeeper在自动清理的时候须要保留的快照数据文件数量和对应的事务日志万能键。须要注意的是,并非磁盘上的全部事务日志和快照数据文件均可以被清理掉–那样的话将没法恢复数据。所以参数autopurge.snapRetainCount的最小值是3,若是配置的autopurge.snapRetainCount值小于3的话,那么会被自动调整到3,即至少须要保留3个快照数据文件和对应的事务日志文件
  • autopurge.purgeInteval: 该参数有默认值:0,单位是小时,能够不配置,不支持系统属性方式配置。参数autopurge.purgeInterval和参数autopurge.snapRetainCount配套使用,用于配置Zookeeper进行历史文件自动清理的频率。若是配置该值为0或者负数,那么就代表不须要开启定时清理功能。Zookeeper默认不开启这项功能。
  • fsync.warningthresholdms: 该参数有默认值:1000,单位是毫秒,能够不配置,仅支持系统属性方式配置:fsync.warningthresholdms。参数fsync.warningthresholdms用于配置Zookeeper进行事务日志fsync操做时消耗时间的报警阈值。一旦进行一个fsync操做消耗的事件大于参数fsync.warningthresholdms指定的值,那么就在日志中打印出报警日志。

zookeeper经常使用四字命令

  • echo conf|nc 192.168.56.12 2181: 输出相关服务配置的详细信息。
  • echo cons|nc 192.168.56.12 2181: 列出全部链接到服务器的客户端会话的详细信息。客户端IP,会话ID和最后一次与服务器交互的操做类型等。
  • echo crst|nc 192.168.56.12 2181: 功能性命令,用于重置全部的客户端链接统计信息。
  • echo dump|nc 192.168.56.12 2181: 用于输出当前集群的全部会话信息,包括未经处理的会话和临时节点。
  • echo envi|nc 192.168.56.12 2181: 输出关于服务环境的详细信息(区别于 conf 命令)包括:os.version,java.version,user.home等。
  • echo ruok|nc 192.168.56.12 2181: 测试是否启动了该Server,若回复imok表示已经启动。
  • echo stat|nc 192.168.56.12 2181: 来查看哪一个节点被选择做为follower或者leader。
  • echo srvr|nc 192.168.56.12 2181: 和stat命令的功能一致,惟一的区别是srvr不会将客户端的链接状况输出。
  • echo reqs|nc 192.168.56.12 2181: 列出未经处理的请求。
  • echo srst|nc 192.168.56.12 2181: 功能性,用于重置全部服务器的统计信息。
  • echo wchs|nc 192.168.56.12 2181: 列出服务器 watch 的详细信息。
  • echo wchc|nc 192.168.56.12 2181: 经过 session 列出服务器 watch 的详细信息,它的输出是一个与 watch 相关的会话的列表。
  • echo wchp|nc 192.168.56.12 2181: 经过路径列出服务器 watch 的详细信息。它输出一个与 session 相关的路径。
  • echo mntr|nc 192.168.56.12 2181: 用于输出比stat命令更为详细的服务器统计信息,包括请求处理的延迟状况,服务器内存数据库大小和集群同步状况,每一行都是一个kv结构。能够用于监控。
  • echo kill|nc 192.168.56.12 2181: 关掉server

zookeeper 使用JMX监控

`vim bin/zkServer.sh`

#修改前
#ZOOMAIN="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=$JMXLOCALONLY org.apache.zookeeper.server.quorum.QuorumPeerMa
in"

#修改后
ZOOMAIN="-Dcom.sun.management.jmxremote  -Dcom.sun.management.jmxremote.local.only=false  
 -Djava.rmi.server.hostname=192.168.56.22  
 -Dcom.sun.management.jmxremote.port=9991  
 -Dcom.sun.management.jmxremote.ssl=false
 -Dcom.sun.management.jmxremote.authenticate=false  
 -Dzookeeper.jmx.log4j.disable=true  
 org.apache.zookeeper.server.quorum.QuorumPeerMain"

更改完之后重启zookeeper服务器,使用JMX客户端链接服务器:

Mbean标签页,能够看到org.apache.Zookeeper节点,能够看到服务器的基本信息,当前使用的选举算法(ElectionType),单个客户的最大链接数(MaxClientCnxnsPerHost),会话的超时时间和启动时间等。

阿里使用taokafka进行监控。

集群数量的补充

zookeeper任意集群数量均可以成功。官方之因此说奇数是对zookeeper的过半数存活便可用有误解。
好比:咱们想要搭建容许F台服务down掉的集群,那么就要部署一个有2xF+1台服务器构成的zookeeper集群。所以一个3台机器构成的zookeeper集群,可以在挂掉1台机器后依然正常工做,而对于一个由5台服务器构成的zookeeper集群,可以对2台机器挂掉的状况下进行容灾,可是若是是一个由6台机器构成的zookeeper集群,一样只能挂掉2台机器,若是挂掉3台,剩下的机器就没法实现过半了。
可是6台跟5台容灾能力没有任何显著的优点,全部官方建议奇数。

扩容和缩容

因为zookeeper对于水平扩容的支持不是特别好,全部,水平扩容只能经过总体集群重启,或逐台进行重启。

总体集群重启前创建的客户端会话,并不会由于重启而失效。也就是说总体重启期间花费的时间将不计入会话超时时间的计算中。

数据和日志管理

zookeeper会不断写入数据快照和事务日志,zookeeper自己不会本身删除过时的数据,须要本身手动清除。

方法一:写shell脚本

datalogdir=//data/app/zookeeper/zk_log/version-2
datadir=/data/app/zookeeper/zk_data/version-2
logdir=/var/log/zookeeper
count=60
count=$[$count+1]
ls -t $datalogdir/log.* |tail -n _$count |xargs rm -f 
ls -t $datadir/snapshot.* |tail -n _$count |xargs rm -f 
ls -t $logdir/zookeeper.log.* |tail -n _$count |xargs rm -f

方法二:使用官方提供的日志清理jar包
PurgeTxnLog 它的实现了一种简单的历史文件清理策略,能够在这里看一下他的使用方法:http://zookeeper.apache.org/doc/r3.4.3/api/index.html,能够指定要清理的目录和须要保留的文件数目

java -cp zookeeper.jar:lib/slf4j-api-1.6.1.jar:lib/slf4j-log4j12-1.6.1.jar:lib/log4j-1.2.15.jar:conf org.apache.zookeeper.server.PurgeTxnLog <dataDir><snapDir> -n <count>

方法三:使用自带的cleanup.sh脚本

zkCleanup.sh -n 15

方法四:配置文件中增长自动删除的参数。
3.4 之后增长了自动清空历史快照数据和事务日志文件的机制,参考:autopurge.snapRetainCount 和 autopurge.purgeInterval 。

  • autopurge.purgeInterval 这个参数指定了清理频率,单位是小时,须要填写一个1或更大的整数,默认是0,表示不开启本身清理功能。
  • autopurge.snapRetainCount 这个参数和上面的参数搭配使用,这个参数指定了须要保留的文件数目。默认是保留3个。

磁盘选择

使用单独的磁盘做为事务日志的输出目录。一方面事务日志的写性能对zookeeper处理客户端请求,尤为是更新操做的出来性能影响很大。另外一方面,zookeeper事务日志输出是一个顺序写文件的过程,所以自己性能是很是高的,全部尽可能保证不要和应用程序共享一块磁盘,以免对磁盘的竞争。通常zookeeper事务日志和快照数据分别配置在两块单独挂载的硬盘上。
尽可能避免内存与磁盘空间的交换。若是但愿zookeeper可以提供彻底实时的服务,那么就不能出现此类内存与磁盘空间交换的现象。所以在分配JVM堆大小的时候必定要很是当心。

zookeeper client 命令

建立

create 能够建立一个zookeeper节点

create [-s] [-e] path data acl
  • -s 或 -e 分别指定节点特性:顺序和临时节点。默认状况下不添加-s或-e参数的,建立的是持久节点。
create /zk-book 123

读取

读取能够用ls或set命令。
ls 能够列出zookeeper指定节点下的全部子节点。固然,这个命令只能看到指定节点下第一级的全部子节点。

ls path [watch]
  • path表示的是指定节点数据的节点路径。
ls /

第一次不是的zookeeper集群,默认在根节点下面有一个叫作zookeeper的保留节点。

get命令能够获取zookeeper指定节点的数据内容和属性信息。

get path [watch]
get /zk-book

第一行是节点/zk-book的数据内容,其余机会则是建立改节点的事务id(cZxid),最后一次更新改节点的事务ID(mZxid)和最后一次更新改节点的时间(mtime)等属性信息。

更新

使用set命令能够更新指定节点的数据内容。

set path data [version]

data 就是要更新的新内容。set命令后面还有一个version参数,在zookeeper中,节点的数据是有版本概念的,这个参数用于指定本次更新操做是基于ZNode的哪个数据版本进行的。

set /zk-book 456
  • 更新完毕后,dataVersion的值由原来的0变成1,这是由于更新操做致使该节点的数据版本也发生了变动。

删除

使用delete 命令,能够删除zookeeper上的指定节点

delete path [version]

此命令中的version参数跟set命令中的version参数的做用是一致的。

delete /zk-book

要想删除某一个指定节点,改节点必须没有子节点存在,能够经过执行以下命令来进行验证

create /zk-book 123
create /zk-book/child 12345
delete /zk-book

参考文档

分布式服务框架 Zookeeper -- 管理分布式环境中的数据
zookeeper深刻浅出
从PAXOS到ZOOKEEPER分布式一致性原理与实践
Zookeeper原理与优化
zookeeper 可视化管理工具

相关文章
相关标签/搜索