Zookeeper学习基础内容

1,349 阅读14分钟

[TOC]

一、Zookeeper简介

ZooKeeper致力于提供一个高性能、高可用,且具备严格的顺序访问控制能力的分布式协调服务,是雅虎公司创建,是Google的Chubby一个开源的实现,也是Hadoop和Hbase的重要组件.

Zookeeper

设计目标:

  • 简单的数据结构:共享的树形结构,类似文件系统,存储于内存
  • 可以构建集群:避免单点故障,3-5台机器就可以组成集群,超过半数正常工作就能对外提供服务;
  • 顺序访问:对于每个读请求,zk会分配一个全局唯一的递增编号,利用这个特性可以实现高级协调服务
  • 高性能:基于内存操作,服务于非事务请求,适用于读操作为主的业务场景。3台zk集群能达到13w QPS

二、分布式系统协调“方法论”

1.CAP理论

  • C 一致性:数据在分布式环境下的多个副本之间能否保持一致性,这里的一致性更多是指强一致性;
  • A 可用性:分布式系统一直处于可用状态,对于请求总是能在有限的时间 内返回结果致性;
  • P 分区容错性:除非整个网络故障,分布式系统在任何网络或者单点故障时,仍能对外提供满足一致性和可用性的服务;

CAP理论:一个分布式系统不可能同时满足一致性、可用性和分区容错性这三个 基本需求,最多只能同时满足其中的两项;

CAP

TIPS:架构师的精力往往就花在怎么样根据业务场景在A和C直接寻求平衡;

2.BASE理论

  • Basically Avaliable 基本可用:当分布式系统出现不可预见的故障时,允许损失部分可用性,保障系统的“基本可用”;体现在“时间上的损失”和“功能上的损失”;e.g:部分用户双十一高峰期淘宝页面卡顿或 降级处理;
  • Soft state 软状态:允许系统中的数据存在中间状态,既系统的不同节点的数据副本之间的数据同步过程存在延时,并认为这种延时不会影响系统可用性;e.g:12306网站卖火车票,请求会进入排队队列;
  • Eventually consistent 最终一致性:所有的数据在经过一段时间的数据同步后,最终能够达到一个一致的状态;e.g:理财产品首页充值总金额 短时不一致;

BASE理论:即使无法做到强一致性,但分布式系统可以根据自己的业务特点,采 用适当的方式来使系统达到最终的一致性

三、分布式环境协调通信应用场景

Zookeeper常应用以下场景:

  • 数据发布订阅
  • 负载均衡
  • 命名服务
  • Master选举
  • 集群管理
  • 配置管理
  • 分布式队列
  • 分布式锁

四、Zookeeper配置文件详解

序号 参数名 说明
1 clientPort 客户端连接server的端口,即对外服务端口,一般设置为2181
2 dataDir 存储快照文件snapshot的目录。默认情况下,事务日志也会存储在这里。建议同时配置参数dataLogDir, 事务日志的写性能直接影响zk性能。
3 tickTime ZK中的一个时间单元。ZK中所有时间都是以这个时间单元为基础,进行整数倍配置的。例如,session的最小超时时间是2*tickTime
4 dataLogDir 事务日志输出目录。尽量给事务日志的输出配置单独的磁盘或是挂载点,这将极大的提升ZK性能
5 globalOutstandingLimit 最大请求堆积数。默认是1000。ZK运行的时候, 尽管server已经 没有空闲来处理更多的客户端请求了,但是还是允许客户端将请求提交到服务器上来,以提高吞吐性能。当然,为了防止Server内存 溢出,这个请求堆积数还是需要限制下的。(Java system property: zookeeper.globalOutstandingLimit.)
6 preAllocSize 预先开辟磁盘空间,用于后续写入事务日志。默认是64M,每个事务日志大小就是64M。如果ZK的快照频率较大的话,建议适当减小 这个参数。(Java system property: zookeeper.preAllocSize)
7 snapCount 每进行snapCount次事务日志输出后,触发一次快照(snapshot),此时,ZK会生成一个snapshot.文件,同时创建一个新的事务日志文件log.。 默认是100000.(真正的代码实现中,会进行一定的随机数处理,以避 免 所 有 服 务 器 在 同 一 时 间 进 行 快 照 而 影 响 性 能 )(Java system property: zookeeper.snapCount)
8 traceFile 用于记录所有请求的log,一般调试过程中可以使用,但是生产环境不建 议使用,会严重影响性能。(Java system property:? requestTraceFile)
9 maxClientCnxns 单个客户端与单台服务器之间的连接数的限制,是ip级别的,默认是60如果设置为0,那么表明不作任何限制。请注意这个限制的使用范围,仅仅是单台客户端机器与单台ZK服务器之间的连接数限制,不是针对指定客户端IP,也不是ZK集群的连接数限制,也不是单台ZK对所有客户端的 连接数限制。
10 clientPortAddress 对于多网卡的机器,可以为每个IP指定不同的监听端口。默认情况是所 有IP都监听 clientPort指定的端口。 New in 3.3.0
11 minSessionTimeou tmaxSessionTimeout Session超时时间限制,如果客户端设置的超时时间不在这个范围,那么会被强制设置为最大或最小时间。默认的Session超时时间是在2* tickTime ~ 20 * tickTime 这 个 范 围 New in 3.3.0
12 fsync.warningthresholdms 事务日志输出时,如果调用fsync方法超过指定的超时时间,那么会在日志中输出警告信息,默认是1000ms
13 autopurge.purgeInterval 清理任务的时间间隔,单位为hours
14 autopurge.snapRetainCount zkserver启动时会开启一个org.apache.zookeeper.server.DatadirCleanupManager的线程,用于清理"过期"的snapshot文件和其相应的txn log file,此参数用于设定需要被retain保留的文件个数(从QuorumPeerMain跟踪代码)
15 electionAlg 选举算法,默认为3,可以选择(0,1,2,3),    0表示使用原生的UDP(LeaderElection), 1表示使用费授权的UDP 2表示使用授权的UDP(AuthFastLeaderElection)  3基于TCP的快速选举(FastLeaderElection)
16 initLimit Leader与learner建立连接中 socket通讯read所阻塞的时间(initLimit * tickTime) 如果是Leaner数量较多或者leader的数量很大, 可以增加此值
17 SyncLimit learner与leader建立连接中,socket通讯read阻塞的时间.其中包括数据同步/数据提交等
18 peerType zkserver 类型 observer 观察者, participant参与者 ,默认为参与者
19 leaderServes 系统属性 zookeeper.leaderServes leader是否接受client请求,默认为yes即leader可以接受client的连接,在zk cluster 环境中,当节点数为>3时,建议关闭
20 cnxTimeout 系统属性:zookeeper.cnxTimeout leader选举时socket连接打开的时长,只有在electionAlg=3有效
21 skipACL 系统属性:zookeeper.skipACL 默认为no,是否跳过ACL检查
22 forceSync 系统属性:zookeeper.forceSync 默认yes 在update执行之前,是否强制对操作立即持久写入txn log文件.关闭此选项,会造成服务器失效后,尚未持久化的数据丢失
23 jute.maxbuffer 每个节点最大数据量,是默认是1M。这个限制必须在server和client 端都进行设置才会生效。

五、Zookeeper特性

1.会话(Session)

客户端与服务端的一次会话连接,本质是TCP长连接,通过会话可以进行心跳检测和数据传输;

会话

2.数据节点(znode)

ZooKeeper的视图结构和标准的Unix文件系统类似,其中每个节点称为“数据节点”或ZNode,每个znode可以存储数据,还可以挂载子节点,因此可以称之为“树”

特性:

  • 在Zookeeper中,znode是一个跟Unix文件系统路径相似的节点,可以往这个节点存储或获取数据。
  • 通过客户端可对znode进行增删改 查的操作,还可以注册watcher监 控znode的变化。

Zookeeper节点类型

  • 持久节点(Persistent)
  • 持久顺序节点(Persistent_Sequential)
  • 临时节点(Ephemeral)
  • 临时顺序节点(Ephemeral_Sequential)

对于持久接地啊和临时节点,同一个Znode下,节点的名称是唯一的 -实现分布式锁的基础

Znode

Zookeeper节点状态属性

Zookeeper节点属性

3.版本

4.Watcher

事件监听器,客户端可以在节点上注册监听器,当特定的事件发生后,zk会通知到感兴趣的客户 端;eventType: NodeCreated、NodeDeleted、NodeDataChanged、NodeChildrenChange

5.ACL

Zk采用ACL(access control lists)策略来控制权限,5种权限:create、read,write,delete,admin。

ACL机制,表示为scheme:id:permissions,第一个字段表示采用哪一种机制,第二个id表示用户,permissions表示相关权限(如只读,读写,管理等)。zookeeper提供了如下几种机制( scheme):

  • world: 它下面只有一个id, 叫anyone, world:anyone代表任何人,zookeeper中对所有人有权限的结点就是属于world:anyone的

  • auth: 它不需要id, 只要是通过authentication的user都有权限(zookeeper支持通过kerberos来进行authencation, 也支持username/password形式的authentication)

  • digest: 它对应的id为username:BASE64(SHA1(password)),它需要先通过username:password形式的authentication

  • ip: 它对应的id为客户机的IP地址,设置的时候可以设置一个ip段,比如ip:192.168.1. 0/16, 表示匹配前16个bit的IP段

  • super: 在这种scheme情况下,对应的id拥有超级权限,可以做任何事情(cdrwa)

6.集群角色

六、常用客户端命令

1.服务端常用命令

在准备好相应的配置之后可以直接通过zkServer.sh 这个脚本进行服务的相关操作:

  • 启动ZK服务: sh bin/zkServer.sh start
  • 查看ZK服务状态: sh bin/zkServer.sh status
  • 停止Zk服务: sh bin/zkServer.sh stop
  • 重启ZK服务: sh bin/zkServer.sh restart

2.客户端常用命令

使用zkCli.sh -server 127.0.0.1:2181 连接到Zookeeper服务

  • 显示根目录下文件、文件
ls/
  • 显示根目录下、文件
ls2 /

查看当前节点数据并能看到更新次数等数据

  • 创建文件并设置初始内容
create /zk "test"

创建一个新的znode节点“zk" 以及与它关联的字符串

  • 获取文件
get /zk

确认znode是否包含创建的字符串

  • 修改文件内容
set /zk "zkbak"

对zk所关联的字符串进行设置和修改

  • 删除文件
delete /zk

将创建的znode节点进行删除,如果存在子节点则删除会失败

  • 递归删除
rmr /zk

将刚才创建的znode删除,同时删除子节点

  • 退出客户端
quit
  • 帮助命令
help

七、ACL 常用命令

1. getAcl

获取指定节点的ACL信息

2.setACL

设置指定节点的ACL信息

3.addauth

注册会话授权信息

八、Zookeeper常用命令

  • 查看哪个节点被选择作为follower或者leader
echo stat|nc 127.0.0.1 2181 
  • 测试是否启动了该Server,若回复imok表示已经启动
echo ruok|nc 127.0.0.1 2181
  • 列出未经处理的会话和临时节点
echo kill | nc 127.0.0.1 2181 
  • 输出相关服务配置的详细信息
echo conf | nc 127.0.0.1 2181 
  • 列出所有连接到服务器的客户端的完全的连接 / 会话的详细信息
echo cons | nc 127.0.0.1 2181
  • 输出关于服务环境的详细信息(区别于 conf 命令)
echo envi |nc 127.0.0.1 2181 
  • 列出未经处理的请求
echo reqs | nc 127.0.0.1 2181 
  • 列出服务器 watch 的详细信息
echo wchs | nc 127.0.0.1 2181 
  • 通过 session 列出服务器 watch 的详细信息,它的输出是一个与 watch相关的会话的列表
echo wchc | nc 127.0.0.1 2181 
  • 通过路径列出服务器 watch 的详细信息。它输出一个与 session 相关的路 径
echo wchp | nc 127.0.0.1 2181 

九、Zookeeper 日志可视化

  • 事务日志可视化(LogFormatter)
java -cp ../../zookeeper-3.4.6.jar;../../lib/slf4j-api-1.6.1.jar  org.apache.zookeeper.server.LogFormatter log.xxxx

  • 数据快照可视化( SnapshotFormatter)
java -cp ../../zookeeper-3.4.6.jar;../../lib/slf4j-api-1.6.1.jar org.apache.zookeeper.server.SnapshotFormatter	snapshot.xxxx

十、Zookeeper客户端简介

1.Zookeeper 客户端

zookeeper官方提供的java客户端API;

核心API

  • 创建会话
public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher,  long sessionId, byte[] sessionPasswd, boolean canBeReadOnly)

  • 创建节点
public String void create(final String path, byte data[], List<ACL> acl,  CreateMode  createMode,	StringCallback cb, Object ctx)

  • 读取数据
public List<String> void getChildren(final String path, Watcher watcher,  Stat stat, Children2Callback cb, Object ctx)

public List<String>  void getData(final String path, Watcher watcher,  Stat stat, DataCallback cb, Object ctx)

  • 更新数据
public Static void setData(final String path, byte data[], int version,  StatCallback cb, Object ctx)

  • 检测节点是否存在
public Static void exists(final String path, Watcher watcher,  StatCallback cb, Object ctx)

  • 权限控制
public void addAuthInfo(String scheme, byte auth[])

  • Watch

org.apache.zookeeper.Watcher(KeeperState、EventType)

(1)没有专门的API去注册watcher,依附于增删改查API;

(2)watch是一次性产品

(3)watch的process方法中,可对不同事件进行处理;

原生客户端开发弊端

  • 会话的链接是异步的
  • 序列化支持不透明
  • Watch需要重复注册
  • Session 重连机制
  • 开发复杂性较高

2.ZkClient

开源的zk客户端,在原生API基础上封装,是一个更易于使用的zookeeper客户端; 引入Maven依赖

<!-- zkclient依赖 -->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>

核心API

  • 创建会话(同步,重试)
public ZkClient(final String zkServers, final int sessionTimeout,final int connectionTimeout, final ZkSerializer zkSerializer,  final long operationRetryTimeout)

  • 创建节点(同步、递归创建)
String create(final String path, Object data, final CreateMode mode)
public void createPersistent(String path,boolean createParents,List<ACL> acl)  
public void createPersistent(String path, Object data, List<ACL> acl)

public String createPersistentSequential(String path,Object data,List<ACL> acl) 
public String createPersistentSequential(String path,Object data,List<ACL> acl  
public String createEphemeralSequential(String path,Object data,List<ACL> acl)

  • 删除节点(同步,递归调用)
public boolean delete(String path,int version) 
public boolean deleteRecursive(String path)
  • 获取节点(同步,避免不存在异常)
public List<String> getChildren(String path)

public <T> T readData(String path, boolean returnNullIfPathNotExists) 
public <T> T readData(String path, Stat stat)

  • 更新节点(同步、实现CAS、状态返回)
public void writeData(String path, Object datat, int expectedVersion)

public Stat writeDataReturnStat(String path,Object datat,int expectedVersion)

  • 检测节点存在(同步)
public boolean exists(String path)

  • 权限控制(同步)
public void addAuthInfo(String scheme, final byte[] auth);  
public void setAcl(final String path, final List<ACL> acl);
  • 监听器
    监听器

3.Cuator

开源的zk客户端,在原生API基础上封装,apache顶级项目;

  • Curator采用Fluent风格API
<!-- curator依赖 -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.0.0</version>
</dependency>

序列化支持不好

Curator 核心API

  • 创建会话(同步、重试)
CuratorFrameworkFactory.newClient(String connectString, int sessionTimeoutM int connectionTimeoutMs, RetryPolicy retryPolicy)

CuratorFrameworkFactory.builder().connectString("192.168.11.56:2180")
.sessionTimeoutMs(30000).connectionTimeoutMs(30000)
.canBeReadOnly(false)
.retryPolicy(new ExponentialBackoffRetry(1000, Integer.MAX_VALUE))
.build();

retryPolicy 连接策略:
RetryOneTime: 只重连一次.
RetryNTime: 指定重连的次数N.
RetryUtilElapsed: 指定最大重连超时时间和重连时间间隔,间歇性重连直到超时或者链接成功.
ExponentialBackoffRetry: 基于"backoff"方式重连,和RetryUtilElapsed的区别是重连的时间间隔是动态
BoundedExponentialBackoffRetry: 同ExponentialBackoffRetry,增加了最大重试次数的控制.
  • 创建节点
client.create().creatingParentIfNeeded()
.withMode(CreateMode.PERSISTENT)
.withACL(aclList)
.forPath(path, "hello, zk".getBytes());

  • 删除节点
client.delete().guaranteed().deletingChildrenIfNeeded()
.withVersion(version).forPath(path)

  • 获取节点
client.getData().storingStatIn(stat).forPath(path);
client.getChildren().forPath(path);

  • 更新节点
client.setData().withVersion(version).forPath(path, data)

  • 判断节点是否存在
client.checkExists().forPath(path);

  • 设置权限
Build.authorization(String scheme, byte[] auth)

client.setACL().withVersion(version)
.withACL(ZooDefs.Ids.CREATOR_ALL_ACL)
.forPath(path);

  • 监听器(避免重复监听)
Cache是curator中对事件监听的包装,对事件的监听可以近似看做是本地缓存视图和远程zk视图的对比过程

- NodeCache 节点缓存用于处理节点本身的变化 ,回调接口NodeCacheListener
- PathChildrenCache	子节点缓存用于处理节点的子节点变化,回调接口 PathChildrenCacheListener
- TreeCache	NodeCache和PathChildrenCache的结合体,回调接口TreeCacheListener
  • 事务支持(保证一组操作的原子性)
Collection<CuratorTransactionResult> results =  client.transaction().forOperations(operations);

  • 异步支持 引入BackgroundCallback接口,用于处理异步接口调用之后服务端返回的结果信息
public void processResult(CuratorFramework client, CuratorEvent event)

CuratorEventType 事件类型
org.apache.zookeeper.KeeperException.Code