zookeeper 学习

1 zookeeper介绍

1.1 应用场景

  • 分布式协调组件
    协调分布系统状态
  • 分布式锁
    zk可以做到强一致性(顺序一致)
  • 无状态话的实现
    类似于分布式session

1.2 zk配置

# 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=/opt/zookeeper/zkdata
# 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

2 zk内部数据模型

2.1 zk是如何保存数据的

  • 采用树形结构,其节点称之为zNode
  • 引用方式为路径引用
[zk: localhost:2181(CONNECTED) 6] create /test2 abc
Created /test2
[zk: localhost:2181(CONNECTED) 7] get /test2
abc

2.2 zk中znode的结构

  • data 保存数据
  • acl:权限
    – c:create创建权限,允许在该节点下创建子节点
    – w:write更新权限
    – r:read读权限
    – d:delete删除权限
    – a:admin管理权限,允许对该节点进行acl权限设置
  • stat:描述当前znode的元数据
  • child:当前节点的子节点

2.3 zk中znode的类型

  • 持久节点:创建出的节点在会话结束后依然存在保存数据
  • 持久序号节点:创建出的节点根据先后顺序会在节点之后带上一个数值。数值越大越后执行,适用于分布式锁的场景
[zk: localhost:2181(CONNECTED) 12] create -s /test3
Created /test30000000003
  • 临时节点
[zk: localhost:2181(CONNECTED) 14] create -e /test5
Created /test5

– 随着会话结束会被删掉
– 应用场景
实现服务注册与发现

  • 临时序号节点
    – 跟持久序号节点相同、适用于临时的分布式锁
  • container节点
    – 当容器中没有任何节点,该容器会在60s后被删掉
[zk: localhost:2181(CONNECTED) 15] create -c /myContainer
Created /myContainer

2.4 zk的持久化

  • 事务日志
    zk把执行的命令以日志的形式保存在dataLogDir的指定路径文件中
  • 数据快照
    zk会在一定时间内内做一次内存数据的快照,把该时刻数据保存在快照文件中
    zk通过两种形式的持久化,再回复时先回复快照文件中的数据到内存,再用日志文件中的数据做增量恢复,这样恢复速度更快

3 zk客户端(zkCli)的使用

3.1 创建

  • 持久节点
  • 持久顺序节点 -s
  • 子节点
  • 临时节点 -e
  • 临时序号节点 -e -s
  • 容器节点 -c

3.2 查询节点

  • 普通查询 ls
  • 递归查询 ls -R
  • 查询数据 get
  • 详细信息 -s
[zk: localhost:2181(CONNECTED) 27] get -s /test1
null
//当前节点事务ID
cZxid = 0x2
//创建时间
ctime = Mon Apr 11 19:25:18 CST 2022
//修改事务ID
mZxid = 0x2
//修改事务时间
mtime = Mon Apr 11 19:25:18 CST 2022
//子节点ID
pZxid = 0x3
//版本号
cversion = 1
//节点数据版本
dataVersion = 0
//节点权限版本
aclVersion = 0
//临时节点的SessionId
ephemeralOwner = 0x0
//当前节点的数据长度
dataLength = 0
//子节点个数
numChildren = 1

3.3 删除节点

  • 删除空节点 delete
  • 删除非空节点 deleteall
  • 乐观锁 delete -v [版本号]

3.4 权限设置

对当前session添加权限

[zk: localhost:2181(CONNECTED) 28] addauth digest xiaoming:123456
[zk: localhost:2181(CONNECTED) 29] create /test-node abc auth:xiaoming:123456:cdrwa 
Created /test-node
[zk: localhost:2181(CONNECTED) 30] get /test-node
abc

无权限时访问

[zk: localhost:2181(CONNECTED) 0] get /test-node
Insufficient permission : /test-node

添加权限后访问

[zk: localhost:2181(CONNECTED) 2] addauth digest xiaoming:123456
[zk: localhost:2181(CONNECTED) 3] get /test-node
abc

4 Curator客户端的使用

4.1 介绍

  • Curator是对zk最好的支持框架

4.2 使用步骤

1、引入依赖

<!--Curator-->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>5.2.1</version>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>5.2.1</version>
</dependency>
<!--zooKeeper-->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.8.0</version>
</dependency>

2、application文件配置

curator:
retryCount: 5
elapsedTimeMs: 5000
connectString: 172.16.253.35:2181
sessionTimeoutMs: 60000
connectionTimeoutMs: 5000

3、注入配置bean

@Configuration
public class CuratorConfig {
    @Autowired
    WrapperZK wrapperZk;

    @Bean(initMethod = "start")
    public CuratorFramework curatorFramework() {
        return CuratorFrameworkFactory.newClient(
                wrapperZk.getConnectString(),
                wrapperZk.getSessionTimeoutMs(),
                wrapperZk.getConnectionTimeoutMs(),
                new RetryNTimes(wrapperZk.getRetryCount(),
                        wrapperZk.getElapsedTimeMs()));
    }
}

4.创建节点

@Test
void contextLoads() throws Exception {
    //添加持久节点
    String path1 = curatorFramework.create().forPath("/curator-node1");
    //持久顺序节点
    String path2 = curatorFramework.create().withMode(CreateMode.PERSISTENT).forPath("/curator-node2", "some-data".getBytes());
    //临时节点
    String path3 = curatorFramework.create().withMode(CreateMode.EPHEMERAL).forPath("/curator-node3", "some-data".getBytes());
    //临时序号节点
    String path4 = curatorFramework.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/curator-node4", "some-data".getBytes());
    //子节点
    String path5 = curatorFramework.create().creatingParentsIfNeeded().forPath("/curator-node4/sonNode");
    //容器节点
    String path6 = curatorFramework.create().withMode(CreateMode.CONTAINER).forPath("/curator-node6", "some-data".getBytes());
}

5.获得节点数据

@Test
public void testGetData() throws Exception {
		byte[] bytes = curatorFramework.getData().forPath("/curator-node");
		System.out.println(new String(bytes));
}

6.修改节点数据

@Test
public void testSetData() throws Exception {
		curatorFramework.setData().forPath("/curatornode","changed!".getBytes());
		byte[] bytes = curatorFramework.getData().forPath("/curator-node");
		System.out.println(new String(bytes));
}

7.删除节点

@Test
public void testDelete() throws Exception {
   		String pathWithParent="/node-parent";
   		curatorFramework.delete().guaranteed().deletingChildrenIfNeeded().forPa
   		th(pathWithParent);
}

5 zk实现分布式锁

5.1 zk中锁的种类

  • 读锁(共享锁):大家都可以读,前提是之前没上过写锁
  • 写锁(排它锁):只有得到写锁才能写,之前没有上过任何锁

5.2 zk如何上读锁

  • 创建⼀个临时序号节点,节点的数据是read,表示是读锁
  • 获取当前zk中序号⽐⾃⼰⼩的所有节点
  • 判断最⼩节点是否是读锁:
    – 如果不是读锁的话,则上锁失败,为最⼩节点设置监听。阻塞等待,zk的watch机制
    会当最⼩节点发⽣变化时通知当前节点,于是再执⾏第⼆步的流程(不是读锁则后续节点一定都在阻塞)
    – 如果是读锁的话,则上锁成功(后续节点不能上写锁,所以写读锁一定成功)

5.3 zk如何上写锁

  • 创建一个临时序号节点,节点额数据是write
  • 获得zk中所有子节点
  • 判断自己是否是最小节点
    – 是则写锁成功
    – 不是,则说明前面还有锁,上锁失败,监听最小节点

5.4 羊群效应

  • 利用上诉上锁方式,若有大量节点监听最小节点时,最小节点释放会触发其他节点的监听事件,对zk压力非常大
  • 解决方法:链式监听

6 watch机制

6.1 zkCli客户端使用watch

create /test xxx
get -w /test #⼀次性监听节点
ls -w /test #监听⽬录,创建和删除⼦节点会收到通知。⼦节点中新增节点不会收到通知
ls -R -w /test #对于⼦节点中⼦节点的变化,但内容的变化不会收到通知

6.2Curator实现watch

@Test
public void addNodeListener() throws Exception {

    NodeCache nodeCache = new NodeCache(curatorFramework, "/curatornode");
    nodeCache.getListenable().addListener(new NodeCacheListener() {
        @Override
        public void nodeChanged() throws Exception {
            log.info("{} path nodeChanged: ", "/curator-node");
            printNodeData();
        }
    });
    nodeCache.start();
    System.in.read();
}
public void printNodeData() throws Exception {
    byte[] bytes = curatorFramework.getData().forPath("/curator-node");
    log.info("data: {}", new String(bytes));
}

7 zookeeper集群

7.1 集群角色

  • Leader:处理集群的所有事务请求,集群中只有一个leader
  • Follower:只能处理读请求,参与leader选举
  • Observer:只能处理读请求,提升集群读的能力,但不参与leader选举

集群搭建

1、创建4个节点的myid,并设值

/opt/zookeeper/zkdata/zk1# echo 1 > myid
/opt/zookeeper/zkdata/zk2# echo 2 > myid
/opt/zookeeper/zkdata/zk3# echo 3 > myid
/opt/zookeeper/zkdata/zk4# echo 4 > myid

2、编写四个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
# 修改对应的zk1 zk2 zk3 zk4
dataDir=/opt/zookeeper/zkdata/zk1
# 修改对应的端⼝ 2181 2182 2183 2184
clientPort=2181
# 2001为集群通信端⼝,3001为集群选举端⼝,observer表示不参与集群选举
server.1=127.0.0.1:2001:3001
server.2=127.0.0.1:2002:3002
server.3=127.0.0.1:2003:3003
server.4=127.0.0.1:2004:3004:observer

3、启动四台zookeeper服务器

./bin/zkServer.sh status ./conf/zoo1.cfg
./bin/zkServer.sh status ./conf/zoo2.cfg
./bin/zkServer.sh status ./conf/zoo3.cfg
./bin/zkServer.sh status ./conf/zoo4.cfg

4、连接zookeeper集群

./bin/zkCli.sh -server
127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183

8 ZAB协议

8.1 什么是ZAB协议

  • Zookeeper Atomic Broadcast:用于解决zookeeper的崩溃恢复和主从数据同步的问题。

8.2 ZAB协议定义的四种节点状态

  • Looking :选举状态。
  • Following :Follower 节点(从节点)所处的状态。
  • Leading :Leader 节点(主节点)所处状态。
  • Observing:观察者节点所处的状态

集群上线时的Leader选举过程

在这里插入图片描述

8.3 崩溃恢复时的Leader选举

Leader建⽴完后,Leader周期性地不断向Follower发送⼼跳(ping命令,没有内容的
socket)。当Leader崩溃后,Follower发现socket通道已关闭,于是Follower开始进⼊到
Looking状态,重新回到上⼀节中的Leader选举过程,此时集群不能对外提供服务。

8.4 主从同步

在这里插入图片描述

9 CAP理论

9.1 CAP定理

CAP 理论:⼀个分布式系统最多只能同时满⾜⼀致性(Consistency)、可⽤性
(Availability)和分区容错性(Partition tolerance)这三项中的两项

  • ⼀致性(Consistency): “all nodes see the same data at the same time”,即更新操作成功并返回客户端完成后,所有节点在同⼀时间的数据完全⼀致。
  • 可⽤性(Availability):“Reads and writes always succeed”,即服务⼀直可⽤,⽽且是正常响应时间。
  • 分区容错性指:“the system continues to operate despite arbitrary message loss or failure
    of part of the system”,即分布式系统在遇到某节点或⽹络分区故障的时候,仍然能够对外
    提供满⾜⼀致性或可⽤性的服务。(分布式存储)

9.2 BASE定理

BASE 理论是对 CAP 理论的延伸,核⼼思想是即使⽆法做到强⼀致性(Strong Consistency,CAP 的⼀致性就是强⼀致性),但应⽤可以采⽤适合的⽅式达到最终⼀致性(Eventual Consitency)。

  • 基本可⽤(Basically Available):基本可⽤是指分布式系统在出现故障的时候,允许损失部分可⽤性,即保证核⼼可⽤。电商⼤促时,为了应对访问量激增,部分⽤户可能会被引导到降级⻚⾯,服务层也可能只提供降级服务。这就是损失部分可⽤性的体现。
  • 软状态(Soft State):软状态是指允许系统存在中间状态,⽽该中间状态不会影响系统整体可⽤性。分布式存储中⼀般⼀份数据⾄少会有三个副本,允许不同节点间副本同步的延时就是软状态的体现。mySql replication 的异步复制也是⼀种体现。(eg:zk中leader收到半数以上的ack即可提交commit,允许客户端访问)
  • 最终⼀致性(Eventual Consistency):最终⼀致性是指系统中的所有数据副本经过⼀定时间后,最终能够达到⼀致的状态。弱⼀致性和强⼀致性相反,最终⼀致性是弱⼀致性的⼀种特殊情况。

9.3 Zookeeper追求的⼀致性

Zookeeper在数据同步时,追求的并不是强⼀致性,⽽是顺序⼀致性(事务id的单调递增)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值