Apache Zookeeper -- 分布式协调服务
官网:http://zookeeper.apache.org/
历史:Yahoo基于Google Chubby开发出了Zookeeper,并于2009年在Apache将其开源
概念
脑裂:split-brain,由于网络分区错误,集群中一部分节点与另一部分节点失去联系,分别形成主从关系,导致整体不一致
Paxos算法:Leslie Lamport 提出的保证分布式一致性的三阶段提交算法,即确保一个操作能执行成功,且执行时独占资源
znode树:zookeeper服务器上,维护的一个树状数据结构(小文件存储系统)
znode:znode树上的节点,用于存储数据
临时节点:与客户端的会话结束时,会自动删除这个客户端创建的临时节点,临时节点下不能有子节点
有序节点:已存在一个有序节点,可以继续创建同路径节点,节点名后会带上序列号
根节点:/
原理
1、客户端监听特定的znode
2、znode发生变化话,客户端会得到通知
3、写操作都会转发给zk主节点
选举原理
1、每台zk的配置文件里,都有全部节点的信息,节点编号越大的,获票权重越高
2、zk一台台启动时,票都会投给权重最高的节点,启动台数超过配置台数时,选出主节点
3、后续启动的节点,都作为从节点
4、主节点失效时,会选举新的主节点
安装
1、/usr下wget tar.gz,解压 tar -zxvf
2、将conf/zoo_sample.cfg 改名为 zoo.cfg
3、启动zk:bin/zkServer.sh start
4、检查:jps;bin/zkServer.sh status
5、停止和重启:bin/zkServer.sh stop;bin/zkServer.sh restart
配置
1、主配置文件 zoo.cfg
tickTime=2000 # 2000毫秒一次心跳
initLimit=10 # 初始化时间最长为10个心跳,否则初始化失败
syncLimit=5 # 数据同步时间 最长为5个心跳
dataDir=/temp/zookeeper # 数据目录
clientPort=2181 # 供客户端访问的端口
# 集群配置,zk集群里,每个节点的配置都要是一样的
server.1=ip:2888:3888 # 1为集群中其中一个节点的编号
server.2=ip:2888:3888 # 节点ip:数据同步端口:选举端口
server.3=ip:2888:3888
2、节点ID配置
在每个zk节点的数据目录下,新建文件 myid
1
节点属性
dataVersion:数据版本
cversion:子节点版本,即子节点变化时,本节点的cversion加一
ctime:节点创建时间
mtime:最晚更新时间
ephemeralOwner:临时节点 对应的 session id
客户端
启动客户端:bin/zkCli.sh # 连接的是本地zk
指定目标连接:bin/zkCli.sh -server IP:2181
查看可用命令:help
创建节点:create -s -e 节点路径 数据 # -s 表示有序节点,-e表示临时节点
查看节点数据和节点属性:get 节点路径 ; ls2 节点路径
查看子节点:ls 节点路径;getChildren 节点路径
节点设值:set 节点路径 数据
删除节点:delete 节点路径
递归删除节点:rmr 节点路径
是否存在:exists 节点路径
查看监听器:printwatches on
限制子节点数量:setquota -n 5 节点路径 # 可以超出限制,但是超出时会打一条WARN日志
查看quata:listquota 节点路径
取消限制:delquota -n 节点路径
查看操作历史:history
订阅(监听) / 发布(通知)
订阅:get /my watch
通知消息格式:WatchedEvent state:SyncConnected type:NodeDataChanged path:/my
state:连接状态
连接状态:Disconnected、Expired
type:事件类型,同一类型的事件发生多次,只会通知第一次
事件类型:NodeCreated、NodeDeleted、NodeDataChanged、NodeChildChanged
客户端得到通知后,需要去查询znode,才能得到具体信息
zookeeper应用
一、配置中心
1、应用节点启动时(Spring容器装载Bean时),从zk查询配置,并订阅znode数据变化;
2、配置变化时,重新从zk查询,并继续订阅
二、服务注册中心(命名服务)
即指定path 与 注册服务地址的对应关系
三、分布式锁
自旋锁:
1、客户端A在zk上创建一个临时节点 /lock,得到锁
2、客户端B在zk上创建同名节点,结果失败;监听该节点,接收到节点删除事件通知时,再次尝试创建
3、客户端A奔溃时,临时节点被自动删除
顺序锁:
1、客户端A在zk上创建一个临时有序节点 /lock,得到锁
2、客户端B在zk上创建同名节点,得到一个编号;监听该节点,当自己的编号是最小编号时,即得到锁
3、客户端A奔溃时,临时节点被自动删除
四、分布式ID
利用顺序锁,一个机子可知自己的编号,进而(结合Snowflake)生成全局唯一的ID
日志
日志配置:conf/log4j.properties
二进制事务日志:数据目录/version-1/log.1
标准输出日志:zookeeper.out
JAVA 调用
1、配置Maven依赖
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.12</version> <!-- 要与zookeeper版本一致 -->
</dependency>
2、使用
ZooKeeper zk = new ZooKeeper("ip_1:2181,ip_2:2181",3000, new Watcher(){
@Override
public void process(WatchedEvent event) {
System.out.println(event.getState()); // 连接状态
System.out.println(event.getType()); // 事件类型
System.out.println(event.getPath()); // 事件源
}
});
// 第二个参数为节点版本,-1表示最小版本
zk.delete("/myNode",-1);
// 后两个参数分别为权限控制模式 和 节点类型
zk.create("/myNode", "数据0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
// 第二个参数表示是否监听该节点
zk.getData("/myNode", true, null);
// 两次设值,只会通知一次
zk.setData("/myNode","数据1".getBytes(),-1);
zk.setData("/myNode","数据2".getBytes(),-1);
zk.close();
Curator 框架
Curator 是 Netflix公司开源的一套Zookeeper客户端框架
不同版本的Curator支持对应版本的Zookeeper,其中Curator 2.x.x兼容Zookeeper的3.4.x和3.5.x
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
curator-client:Zookeeper API的封装
curator-framework:Zookeeper API的高层封装
curator-recipes:Zookeeper典型应用场景的实现,基于curator-framework
阿里云
微服务引擎 MSE - Zookeeper版(选用按量付费、设置IP白名单)