一、简介
分布式系统的本质是分布在不同网络或计算机上的程序组件,彼此通过信息传递来协同工作的系统,而Zookeeper是一个分布式应用协调框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。
二、核心概念
1.文件系统数据结构
每个子目录项都被称作为 znode(目录节点),和文件系统类似。有以下几种节点:
1、PERSISTENT-持久化目录节点:客户端与zookeeper断开连接后,该节点依旧存在
2、 PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点:同1,另Zookeeper给该节点名称进行顺序编号
3、EPHEMERAL-临时目录节点:客户端与zookeeper断开连接后,该节点被删除
zookeeper是C/S架构,客户端每一次操作/请求都与sessionid关联。临时节点会与sessionid绑定,包括生命周期。建立连接时客户端还会携带session的超时时间,服务端会对其进行维护。客户端任意一次命令(ping命令或其他命令),只要sessionid没有超时,服务端会对其进行保活机制,延长过期时间。一旦客户端断开连接,无法发送请求,服务端通过心跳检测发现该session在超时时间内没有发送请求,会删除sessionid对应的临时节点。
4、EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点:同3,另Zookeeper给该节点名称进行顺序编号
3.5.X 版本新增
5、Container -容器节点:容器节点主要用来容纳字节点,如果没有给其创建子节点,容器节点表现和持久化节点一样,如果给容器节点创建了子节点,后续又把子节点清空,容器节点也会被zookeeper删除
6、TTL 节点:给节点设置过期时间。默认禁用,只能通过系统配置 zookeeper.extendedTypesEnabled=true 开启,不稳定
2.监听通知机制
-
如果注册的是对某个节点的监听,则当这个节点被删除,或者被修改时,对应的客户端将被通知
-
如果注册的是对某个目录的监听,则当这个目录有子节点被创建,或者有子节点被删除,对应的客户端将被通知
-
如果注册的是对某个目录的递归子节点进行监听,则当这个目录下面的任意子节点有目录结构的变化(有子节点被创建,或被删除)或者根节点有数据变化时,对应的客户端将被通知。
注意:所有的通知都是一次性的,及无论是对节点还是对目录进行的监听,一旦触发,对应的监听即被移除。递归子节点,监听是对所有子节点的,所以,每个子节点下面的事件同样只会被触发一次。
三、安装使用
1.安装
-
安装jdk,配置java环境
-
下载解压 zookeeper
wget https://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.5.8/apache-zookeeper-3.5.8-bin.tar.gz tar -zxvf apache-zookeeper-3.5.8-bin.tar.gz cd apache-zookeeper-3.5.8-bin
-
重命名配置文件 zoo_sample.cfg 为zoo.cfg(非必须)
cp zoo_sample.cfg zoo.cfg
# The number of milliseconds of each tick tickTime=2000 # The number of ticks that the initial # synchronization phase can take initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. dataDir=/tmp/zookeeper # the port at which the clients will connect clientPort=2181 # the maximum number of client connections. # increase this if you need to handle more clients #maxClientCnxns=60 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature #autopurge.purgeInterval=1
-
启动zookeeper,指定配置文件
bin/zkServer.sh start conf/zoo.cfg
-
客户端连接
bin/zkCli.sh ‐server ip:port
2.使用
-
创建zookeeper节点
-
默认就是创建持久化节点,不需要参数
create /persistent data #其他命令 get /persistent #查看节点 set /persistent data-changed #修改节点数据 stat /persistent #查看节点状态信息 get -s /persistent #查看节点状态信息同时查看数据 create /persistent/persistent-sub #创建子节点,zookeeper是以节点组织数据的,没有相对路径这么一说,所有的节点一定是以 / 开头。 ls -R / #查看子节点信息,-R可以查看递归子节点列表 delete /persistent #删除节点
-
创建临时节点,临时节点不能创建子节点
create ‐e /ephemeral data
-
创建顺序节点,前缀可加可不加
create -s /前缀-
-
创建临时顺序节点
create -s -e /前缀-
-
创建容器节点
create -c /container
-
创建TTL节点
create -t /ttl
-
-
事件监听机制
在get、stat、ls命令中加-w,可以对节点、目录等添加事件监听。事件监听是一次性的,一旦事件触发,对应的注册立刻被移除。
get -w /path #注册监听的同时获取数据 stat -w /path #对节点进行监听,且获取元数据信息 ls -w /path #针对目录的监听 ls -R -w /path #针对递归子目录的监听
Zookeeper事件类型:
None: 连接建立事件
NodeCreated: 节点创建
NodeDeleted: 节点删除
NodeDataChanged:节点数据变化
NodeChildrenChanged:子节点列表变化
DataWatchRemoved:节点监听被移除
ChildWatchRemoved:子节点监听被移除
四、Zookeeper分布式锁
单机的锁都是基于进程的锁,如java中的synchronized和lock,在单个JVM进程中是有效的。 但是分布式中,服务部署在不同的物理机器上,或者同一物理机器上的不同JVM进程中,此时单机锁会失效。
锁要有独占性,比如redis的setnx,一个请求setnx成功,那么另一个请求就会失败。那么在zookeeper中,每一个路径或节点也都是唯一的,如果一个请求创建成功,那么其他请求再创建就会失败。
1.非公平锁
通过临时节点可以实现非公平锁,过程如下:
- 先获取锁,判断当前锁是否已经被其他事务创建,如果已经被创建,那么就监听该锁(get -w /lock)并等待释放锁;
- 如果锁还没有被创建,那么当前事务创建锁(create -e /lock),创建成功则获取到锁,创建失败则监听该锁(get -w /lock)并等待释放锁;
- 获取到锁的事务完成业务处理之后,就会释放锁(delete /lock),其他事务开始获取锁。
这种方式创建的锁是非公平锁,没有办法控制先到先得的顺序。
2.公平锁
通过临时顺序节点实现公平锁,
- 首先在业务/资源id节点下(如/lock)创建临时顺序节点;
- 然后判断自己是不是/lock下最小的节点,如果是,那么就获得锁,如果不是,就对前一个节点进行监听;
- 获得锁的请求处理完业务之后释放掉锁,也就是删除节点,那么后一个监听了该节点的节点就会接到通知,重复判断自己是不是最小节点等2操作。
3.共享锁
有时候并不是所有的请求都需要加锁,针对读、写操作,有不同的处理方式:
- 读操作,如果前面的节点都是读锁,直接获取锁;如果前面有写请求,则不能获取锁,需要对前面的写请求的节点进行监听;如果是多个写操作,则只对最后一个写操作的节点进行监听。
- 写操作,对前面的节点进行监听,与互斥锁处理机制相同。