Zookeeper(一)概览,安装,zkCli.sh使用

概览

https://zookeeper.apache.org/
前面用redis实现分布式锁的时候,会显得很复杂;用zookeeper实现会简单很多
当然,zookeeper不只用来实现分布式锁,还有很多其他的功能.

ZooKeeper是用于分布式应用程序的分布式,开放源代码协调服务。
它公开了一组简单的原语,分布式应用程序可以基于这些原语来实现用于同步,配置维护以及组和命名的更高级别的服务。
使用了按照文件系统熟悉的目录树结构样式设置的数据模型。
zk也是二进制安全的,按byte[]存储.

  • ZooKeeper很简单。
    ZooKeeper允许分布式进程通过共享的分层名称空间相互协调,该命名空间的组织方式类似于标准文件系统。名称空间由数据寄存器(在ZooKeeper中称为znodes)组成,它们类似于文件和目录。
    与设计用于存储的典型文件系统不同,ZooKeeper数据保留在内存中,这意味着ZooKeeper可以实现高吞吐量和低延迟数。
  • 以主从复制的形式实现高可用集群,一个leader,多个follower,读写分离,leader读写,follower读.
    如果leader挂了,进入无主状态,它可以快速的重新选一个leader(官方压测不到200ms)
  • 每个client连接到zk时,都会产生一个session作为身份标识,每个session对应一个临时节点,当client挂了或者断开连接时,session就消失了
    之前我们用redis实现分布式锁时,要设置过期时间,还要再起个线程监听它挂没挂;
    如果用zk,客户端连接到zk,建立了session会话,在zk里创建了一把锁,客户端挂掉后锁就释放了,也可以手动释放锁;依靠session这把锁可以很简单的实现.
  • 目录树结构,类似与文件系统,每个节点都可以存1M内的数据(二进制安全);
    节点分为持久节点和临时节点,临时节点依托于session
    只要创建znode的会话处于活动状态,这些znode就会存在。会话结束时,将删除znode.
    ZK旨在分布式协调,不要把它当数据库用,即不要频繁的写,因为ZK的优势在于读
    曾经的Spark消费Kafka里的数据,会把消费的offset记录到zk里, 以做到分布式协调;但这其实是把ZK当数据库用了,频繁的修改数据,不能发挥ZK的优势.
  • 节点支持序列化,
  • 特点:
    顺序一致性,客户端的更新将按发送顺序应用(写操作转交给leader)
    原子性,写操作会写到每一个节点上(最终一致性)
    单系统镜像,无论客户端连接到哪个服务器,客户端都将看到相同的服务视图(包括session,也统一)。
    可靠性(持久性)-应用更新后,此更新将一直持续到客户端覆盖更新为止。
    及时性-确保系统的客户视图在特定时间范围内是最新的(最终一致性)。

性能测试图:
this is a throughput graph of ZooKeeper release 3.2 running on servers with dual 2Ghz Xeon and two SATA 15K RPM drives.
在这里插入图片描述

安装

需要安装JDK>=1.7
官网下载解压zookeeper后,进入conf文件夹,
复制出一份配置文件cp zoo_sample.cfg zoo.cfg,
然后编辑 zoo.cfg,常用配置说明:

  • tickTime=2000 心跳间隔,单位时毫秒
  • initLimit=10 节点间日常同步时,超过多少个心跳后就认为该节点有问题
  • syncLimit=5 写操作时,follower响应,超过多少个心跳后就认为该follower有问题
  • dataDir=/data/data/zookeeper 快照的存储路径
  • clientPort=2181 客户端连接时的端口号
  • #maxClientCnxns=60 最大客户端连接数

当leader挂掉后,需要投票选出新leader,“过半通过”;在redis的哨兵主从模式下,我们不需要配置所有节点,需要手动配置一个"票数",不一定非得过半;
在zookeeper中,需要配置所有节点,"票数"不能配置,而是通过n/2 + 1 计算得到;
这样配置节点:
(3888是选leader时投票用的端口,follower之间通信,第一次启动没有leader或者leader挂了时用)
(2888是leader开启的端口,后续leader和follower之间用这个端口通信,当有写请求时交给leader)
(server.后面的数字是id,选leader时 给id大的投票;其实还会根据事务id判断)

server.1=node1:2888:3888
server.2=node2:2888:3888
server.3=node3:2888:3888

然后在dataDir=/data/data/zookeeper 目录下,创建一个myid文件,每台机器写自己的id号
然后依次启动就完事了

可以查看端口:
netstat -natp | egrep ‘(2888|3888)’

zkCli shell 使用

随便进入一台机器,zkCli.sh 连接本机的ZK
连接后会打印sessionid:

Session establishment complete on server localhost/127.0.0.1:2181, session id = 0x200004489b40000, negotiated timeout = 30000

输入help查看帮助

ZooKeeper -server host:port -client-configuration properties-file cmd args
	addWatch [-m mode] path # optional mode is one of [PERSISTENT, PERSISTENT_RECURSIVE] - default is PERSISTENT_RECURSIVE
	addauth scheme auth
	close 
	config [-c] [-w] [-s]
	connect host:port
	create [-s] [-e] [-c] [-t ttl] path [data] [acl]
	delete [-v version] path
	deleteall path [-b batch size]
	delquota [-n|-b] path
	get [-s] [-w] path
	getAcl [-s] path
	getAllChildrenNumber path
	getEphemerals path
	history 
	listquota path
	ls [-s] [-w] [-R] path
	printwatches on|off
	quit 
	reconfig [-s] [-v version] [[-file path] | [-members serverID=host:port1:port2;port3[,...]*]] | [-add serverId=host:port1:port2;port3[,...]]* [-remove serverId[,...]*]
	redo cmdno
	removewatches path [-c|-d|-a] [-l]
	set [-s] [-v version] path data
	setAcl [-s] [-v version] [-R] path acl
	setquota -n|-b val path
	stat [-w] path
	sync path
	version 

create

创建临时节点/永久节点

create -e 创建一个临时节点
不指定参数,默认创建永久节点

create /hi 创建永久节点,新版本ZK可以不指定值,老版本必须指定,不能为空
create -e /hi/tmp 创建个临时节点;
当客户端断开连接(quit)时,它创建的临时节点就自动消失.

session占用全局事务id

假设客户端a使用API连接了ZK集群中的 F1,客户端会把sessionID保存一份, 客户端创建一些临时节点
这时如果F1挂了,客户端可能会连接到F2,那么客户端创建的临时节点会丢失吗?
不会,因为客户端保存了sessionID,并且ZK服务端会统一视图,每个节点都有该sessionID

序列 create -s

假设两个客户端同时想要创建一个路径的节点,如果不指定序列(-s),就会覆盖;
而指定-s后,会规避这个覆盖的问题,创建节点使会在path后面加上序列号
这个序列号类似于数据库的"自增id",是个全局性id
相当于zk帮我们重命名了,会返回真正的path.
第一个客户端:

[zk: localhost:2181(CONNECTED) 14] create -s /qwe
Created /qwe0000000006

第二个客户端:

[zk: localhost:2181(CONNECTED) 7] create -s /qwe
Created /qwe0000000007

get -s /path

get时 加上 -s 参数,会打印额外信息:
这些ID都分为两部分,高32位是leader的纪元号;低32位是事务id;
客户端的连接和断开也会全局的事务id+1

world	获取到的节点值
cZxid = 0x100000007		该节点创建时的事务id
ctime = Fri Jun 19 08:27:31 CST 2020
mZxid = 0x100000009		该节点最后的修改的事务id
mtime = Fri Jun 19 08:34:52 CST 2020
pZxid = 0x100000008		?整个ZK中,最后一次创建的事务id
cversion = 1
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0	临时持有者,0x0表示永久节点;如果是临时节点,这里就是创建它的客户端的sessionid
dataLength = 5
numChildren = 1

本节总结

上面那些ZK的功能,可以做哪些事呢:

  1. 统一配置管理 - 节点中可以存储不到1M的数据
  2. 分组管理 - path结构
  3. 统一命名 - sequence (create -s)
  4. 同步,分布式锁 - 临时节点

千万不要把ZK当数据库用;
更多的用于分布式协调.

实现分布式锁

  1. 临时节点(-e)
    客户端借此可实现简单的分布式锁;可用于高可用选主
  2. 依托一个父节点,创建临时子节点时 带上序列( -s); 这样相当于一个父节点下可以有多把锁
    客户端借此可实现 队列式的,或者事务的锁

版权声明:本文为weixin_42008012原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。