0


zookeeper随堂笔记

学习目标:

  1. 什么是zookeeper
  2. 应用场景
  3. 基本的操作1. 安装部署2. shell客户端3. java端
  4. 基本原理 1. 选举机制2. 数据一致性3. 数据的读写流程

1 zookeeper简介

zookeeper是一个底层的集群协调工具,(比如:NN和DN之间的状态感应;监控 通知)!

具备基本的功能有 ,记录用户的状态数据 (写), 返回用户的数据(读) ,监控和通知。zookeeper为了高可用和安全性是一个集群! 3台(每个节点的数据完全一致)!

2 应用场景

  • 写数据
  • 读取数据
  • 监控通知

2.1 服务状态感知

2.2 分布式锁

2.3 分布式配置同步

2.4 统一域名

分布式中统一CMD指令

分布式中服务器的状态感知

3 操作

3.1 安装

zookeeper在部署的时候选择奇数台!要求zk集群半数以上的机器在线才能正常工作!

**上传解压 **

配置

  1. 在zk安装目录下 创建文件夹 zkData mkdir zkData /opt/apps/zookeeper-3.4.6/zkData
  2. 修改conf/下的配置模板配置文件名 mv zoo_sample.cfg zoo.cfg
  3. vi zoo.cfg dataDir=/opt/apps/zookeeper-3.4.6/zkData# Set to "0" to disable auto purge feature#autopurge.purgeInterval=1server.1=linux01:2888:3888server.2=linux02:2888:3888server.3=linux03:2888:3888
  4. 在zkData文件夹下创建myid文件 echo 1 > zkData/myid

**同步安装包 **

  1. scp -r zookeeper-3.4.6/ linux02:$PWD
  2. scp -r zookeeper-3.4.6/ linux03:$PWD

修改各个节点myid的值 linux02【2】 linux03【3】

**启动集群 **

在各个节点上启动ZK服务

  1. /opt/apps/zookeeper-3.4.6/bin/zkServer.sh start

查看进程 jps

  1. [root@linux01 bin]# jps
  2. 1697 QuorumPeerMain
  3. 1720 Jps

查看集群状态 在每个节点执行

  1. /opt/apps/zookeeper-3.4.6/bin/zkServer.sh status
  2. -------------------------------------------------------
  3. Mode: follower
  4. Mode: leader
  5. Mode: follower

3.2 编写一键启动脚本

  1. #!/bin/bash
  2. # zk启停脚本
  3. for hostname in linux01 linux02 linux03
  4. do
  5. echo "连接${hostname}... ...正在执行 $1"
  6. ssh ${hostname} "source /etc/profile ;/opt/apps/zookeeper-3.4.6/bin/zkServer.sh $1 ;exit"
  7. done

3.3 shell操作

zookeeper中记录数据以Tree节点的形式存储数据的/类似于目录树!

目录叫znode : 节点的组织数据是 K V

基本操作指令

  1. # 客户端连接
  2. bin/zkCli.sh 连接到本地zk服务
  3. bin/zkCli.sh -server linux02:2181 连接到执行节点的服务
  4. quit 退出客户端 ctrl+c
  5. -------------------------------------------
  6. help 帮助命令 查看系统支持的所有的命令
  7. ZooKeeper -server host:port cmd args
  8. stat path [watch]
  9. set path data [version]
  10. ls path [watch] *
  11. delquota [-n|-b] path
  12. ls2 path [watch] *
  13. setAcl path acl
  14. setquota -n|-b val path
  15. history
  16. redo cmdno
  17. printwatches on|off
  18. delete path [version] *
  19. sync path
  20. listquota path
  21. rmr path *
  22. get path [watch]
  23. create [-s] [-e] path data acl *
  24. addauth scheme auth
  25. quit *
  26. getAcl path
  27. close *
  28. connect host:port
  29. -------------------------------------------------------------------
  30. 创建节点 节点必须以/开头 (路径必须是绝对路径)
  31. -- create [-s] [-e] path data acl
  32. create /a 1
  33. create /b 2
  34. create /a/a1 11
  35. create /a/a2 22
  36. create /a/a3 33
  37. [-s] 在节点后面添加一个自增的id 防止节点名重复而创建失败
  38. [-e] 创建的节点是临时节点 , 只在当前连接中有效
  39. ------节点分类-----
  40. --临时节点
  41. 临时有序 -e
  42. 临时无序 -e -s
  43. --永久节点
  44. 永久有序 -s
  45. 永久无序 默认
  46. 注意: 节点的创建不能层级创建
  47. 查看节点列表
  48. ls /a
  49. ls2 /a 显示数据版本 , 事务id 创建时间等信息
  50. 修改数据
  51. set /a 123
  52. 获取数据
  53. get /a
  54. 删除节点
  55. delete /a 只能删除空节点
  56. rmr /a 可以删除任意节点

监听和通知

事件 : 触发了某种事件 通知

  • 节点数据的变化
  • 子节点个数的变化
  1. ls path [watch] 监控指定路径下数据的变化
  2. get path [watch] 监控指定路径数据的变化

注意: 监控和通知只能1次

  1. 打开两个zk客户端
  2. 1) 一个监控 2) 一个修改数据
  3. # 子节点个数变化
  4. 窗口01 : ls / watch
  5. ->(WatchedEvent state:SyncConnected type:NodeChildrenChangedpath:/)
  6. 窗口02 : rmr /a000000004
  7. ---------------------------------------------------------------------------
  8. # 节点数据变化
  9. 窗口01 : get /b watch
  10. ->(WatchedEvent state:SyncConnected type:NodeDataChanged path:/b)
  11. 窗口02 : set /b 321

3.4 java操作

  • 添加依赖
  • 获取zk客户端
  • 调用API
  • 释放资源

添加依赖

  1. <dependency>
  2. <groupId>org.apache.zookeeper</groupId>
  3. <artifactId>zookeeper</artifactId>
  4. <version>3.4.6</version>
  5. </dependency>

入门示例-[获取连接\创建节点]

  1. package com.doitedu.zk.cli;
  2. import org.apache.zookeeper.CreateMode;
  3. import org.apache.zookeeper.ZooDefs;
  4. import org.apache.zookeeper.ZooKeeper;
  5. import java.io.IOException;
  6. /**
  7. * @Date 2022/2/23
  8. * @Created by HANGGE
  9. * @Description TODO
  10. */
  11. public class Demo01 {
  12. public static void main(String[] args) throws Exception {
  13. // 获取zk的客户端
  14. /**
  15. * 参数一 zk的地址 host:port,host2:port
  16. * 参数二 连接的超时时间 毫秒
  17. * 参数三 连接成功后的监听
  18. */
  19. ZooKeeper zk = new ZooKeeper("linux01:2181,linux02:2181,linux03:2181", 3000, null);
  20. // 调用API
  21. //1 创建节点
  22. /**
  23. * 参数1 路径
  24. * 参数2 数据 值 字节数组
  25. * 参数3 权限
  26. * 参数4 节点类型 1 2 3 4
  27. */
  28. zk.create("/doitedu" , "JINGYINGDOIT30_".getBytes() , ZooDefs.Ids.OPEN_ACL_UNSAFE , CreateMode.EPHEMERAL_SEQUENTIAL);
  29. // System.out.println(zk);
  30. //释放资源
  31. Thread.sleep(8000);
  32. zk.close();
  33. }
  34. }

zookeeper-Java-API使用

  1. package com.doitedu.zk.cli;
  2. import org.apache.zookeeper.KeeperException;
  3. import org.apache.zookeeper.ZooKeeper;
  4. import org.apache.zookeeper.data.Stat;
  5. import java.util.List;
  6. /**
  7. * @Date 2022/2/23
  8. * @Created by HANGGE
  9. * @Description
  10. * 创建节点
  11. * 删除节点
  12. * 获取值
  13. * 修改值
  14. * 遍历子节点列表
  15. * 判断节点是否存在
  16. */
  17. public class ClientApiDemo {
  18. public static void main(String[] args) throws Exception {
  19. // 获取客户端对象
  20. ZooKeeper zk = ZookeeperUtil.getZookeeper();
  21. // testGetData(zk);
  22. //修改数据
  23. //testSetData(zk);
  24. //获取子节点列表
  25. //testls(zk);
  26. // 只能删除空节点 递归
  27. // zk.delete("/b" , -1);
  28. // 递归删除节点
  29. ZookeeperUtil.rmr(zk,"/b") ;
  30. zk.close();
  31. }
  32. // 查看路径下的子节点列表
  33. public static void testls(ZooKeeper zk) throws KeeperException, InterruptedException {
  34. List<String> ls = zk.getChildren("/", null);
  35. if(ls!=null && ls.size()>0){
  36. for (String name : ls) {
  37. System.out.println("节点的名字是:" + name);
  38. byte[] data = zk.getData("/" + name, null, null);
  39. System.out.println(new String(data));
  40. }
  41. }
  42. }
  43. // 更新数据
  44. public static void testSetData(ZooKeeper zk) throws KeeperException, InterruptedException {
  45. Stat stat = zk.setData("/b", "liulan".getBytes(), -1);
  46. // 如果更新成功Stat 不为null
  47. if(stat != null){
  48. testGetData(zk);
  49. }
  50. }
  51. // 获取数据
  52. public static void testGetData(ZooKeeper zk) throws KeeperException, InterruptedException {
  53. byte[] data = zk.getData("/b", null, null);
  54. String str = new String(data);
  55. System.out.println(str);
  56. }
  57. }

封装工具类

  1. package com.doitedu.zk.cli;
  2. import org.apache.zookeeper.KeeperException;
  3. import org.apache.zookeeper.ZooKeeper;
  4. import java.io.IOException;
  5. import java.util.List;
  6. /**
  7. * @Date 2022/2/23
  8. * @Created by HANGGE
  9. * @Description TODO
  10. */
  11. public class ZookeeperUtil {
  12. /**
  13. * 获取指定zk集群的客户端对象
  14. * linux01 02 03
  15. * @return
  16. * @throws IOException
  17. */
  18. public static ZooKeeper getZookeeper() throws IOException {
  19. return new ZooKeeper("linux01:2181,linux02:2181,linux03:2181", 3000, null);
  20. }
  21. /**
  22. * 删除任意节点
  23. * @param zk
  24. * @param path
  25. * @throws KeeperException
  26. * @throws InterruptedException
  27. */
  28. public static void rmr(ZooKeeper zk , String path) throws KeeperException, InterruptedException {
  29. // 遍历是否有子节点
  30. List<String> ls = zk.getChildren(path, null);
  31. // 有子节点
  32. if(ls!=null && ls.size() >0){
  33. // 删除子节点
  34. for (String name : ls) {
  35. //---递归
  36. rmr(zk , path+"/"+name);
  37. }
  38. }
  39. //没有子节点
  40. zk.delete(path , -1);
  41. }
  42. }

监控和通知

  • 连接成功 监听通知
  • 数据变化
  • 节点变化

例子

  1. package com.doitedu.zk.cli;
  2. import org.apache.zookeeper.WatchedEvent;
  3. import org.apache.zookeeper.Watcher;
  4. import org.apache.zookeeper.ZooKeeper;
  5. import java.io.IOException;
  6. /**
  7. * @Date 2022/2/23
  8. * @Created by HANGGE
  9. * @Description 连接对象获取成功 事件通知
  10. */
  11. public class TestWatcher01 {
  12. public static void main(String[] args) throws Exception {
  13. /**
  14. * 参数三 事件通知 监听器
  15. * 在获取对象的时候使用 当连接成功以后会 回调一次process方法
  16. */
  17. ZooKeeper zk = new ZooKeeper("linux11:2181", 2000, new Watcher() {
  18. public void process(WatchedEvent event) {
  19. System.out.println("获取连接成功......");
  20. }
  21. });
  22. System.out.println(zk);
  23. zk.close();
  24. }
  25. }
  26. ----------------------------------------------------------------------
  27. package com.doitedu.zk.cli;
  28. import org.apache.zookeeper.KeeperException;
  29. import org.apache.zookeeper.WatchedEvent;
  30. import org.apache.zookeeper.Watcher;
  31. import org.apache.zookeeper.ZooKeeper;
  32. /**
  33. * @Date 2022/2/23
  34. * @Created by HANGGE
  35. * @Description
  36. * 监听节点数据的变化
  37. * 当监听的节点的数据发生变化 通知客户端 回调process
  38. */
  39. public class TestWatcher02 {
  40. public static void main(String[] args) throws Exception {
  41. /**
  42. * 参数三 事件通知 监听器
  43. * 在获取对象的时候使用 当连接成功以后会 回调一次process方法
  44. */
  45. final ZooKeeper zk = new ZooKeeper("linux01:2181", 2000, null);
  46. // 获取指定节点数据的时候 绑定监听器 监听此节点数据的变化
  47. byte[] data = zk.getData("/b", new Watcher() {
  48. // /b节点数据变化就会执行这个方法 1次
  49. public void process(WatchedEvent event) {
  50. try {
  51. System.out.println("/b的数据发生了变化....");
  52. System.out.println(event.getType());
  53. // 改变后的数据是
  54. byte[] data1 = zk.getData("/b", this, null);
  55. System.out.println("变化后的的数据是: "+new String(data1));
  56. } catch (Exception e) {
  57. e.printStackTrace();
  58. }
  59. }
  60. }, null);
  61. System.out.println("变化以前的数据是: "+new String(data));
  62. Thread.sleep(Integer.MAX_VALUE);
  63. zk.close();
  64. }
  65. }
  66. -----------------------------------------------------------------------
  67. package com.doitedu.zk.cli;
  68. import org.apache.zookeeper.KeeperException;
  69. import org.apache.zookeeper.WatchedEvent;
  70. import org.apache.zookeeper.Watcher;
  71. import org.apache.zookeeper.ZooKeeper;
  72. import java.util.List;
  73. /**
  74. * @Date 2022/2/23
  75. * @Created by HANGGE
  76. * @Description
  77. * 监听节点数据的变化
  78. * 当监听的节点的数据发生变化 通知客户端 回调process
  79. */
  80. public class TestWatcher03 {
  81. public static void main(String[] args) throws Exception {
  82. /**
  83. * 参数三 事件通知 监听器
  84. * 在获取对象的时候使用 当连接成功以后会 回调一次process方法
  85. */
  86. final ZooKeeper zk = new ZooKeeper("linux01:2181", 2000, null);
  87. List<String> ls = zk.getChildren("/", new Watcher() {
  88. // 当 / 节点的子节点 被删除 添加 执行这个方法
  89. public void process(WatchedEvent event) {
  90. try {
  91. System.out.println(event.getType());
  92. List<String> ls2 = zk.getChildren("/", this);
  93. System.out.println("变化后的节点有:"+ls2);
  94. } catch (Exception e) {
  95. e.printStackTrace();
  96. }
  97. }
  98. });
  99. System.out.println("当前的节点有: "+ls);
  100. Thread.sleep(Integer.MAX_VALUE);
  101. zk.close();
  102. }
  103. }

4 原理基础

4.1 选举机制

在ZK中有三种状态 ;

Leader: 优先负责写数据

follower 存储数据 参与选举

observe 观察者 不参与选举 存储数据

每个服务器都有一个唯一的myid标记

初始启动选举

  1. ZK服务启动[linux01(myid=1)] , 发现集群中没有Leader .进入到选举状态 ; 投自己一票
  2. myid=1的机器获取1票 , 票数没有过半, 不能当选leader
  3. linux01, 广播投票结果
  4. linux02(myid=2)启动 ,发现集群中没有leader , 进入到选举状态
  5. 收到linux01的1票信息 , 发现linux02的myid > linux01的myid ;投自己一票 ,广播
  6. linux01收到广播 ,发现自己的myid小 ; 改投lnux02 1票 , 广播
  7. linux02 收到linux01的广播 ,自己的票数为2 , 过半 ,切换leader状态
  8. linux01 切换follower状态
  9. linux03启动 ,发现集群中有leader ;切换follower状态

运行过程中选举

注意: 要求整个集群中的数据是一致的! 有事务的保证! zxid事务id

1 先比较zxid的大小 , zxid大的优先当选

2 如果事务id一致 , 再比较myid

整个集群中有机器宕机 ,属于不正常的状态! 修复.........

数据一致性

zk中存储数据以KV的形式 ; K是以节点的组织的 以/开头

整个集群中所有的节点存储一样的数据

记录的数据一般为状态数据 ,配置数据 ,命令....数据量不大


本文转载自: https://blog.csdn.net/qq_37933018/article/details/123082841
版权归原作者 白眼黑刺猬 所有, 如有侵权,请联系我们删除。

“zookeeper随堂笔记”的评论:

还没有评论