zookeeper扫盲知识

  1. 概述
    zookeeper是一个开源的、分布式的、为分布式应用提供协调服务的Apache项目.

  2. zookeeper的工作机制
    从设计模式角度理解: zookeeper是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,zookeeper就将负责通知已经在zookeeper上注册的那些观察者做出相应的反应.

  3. zookeeper特点

  • 一个领导者leader,多个跟随者follower组成的集群
  • 集群中只要有半数以上节点存活,zookeeper集群就能正常服务
  • 全局数据一致: 每个server保存一份相同的数据副本,client无论连接到哪一个server,数据都是一致的
  • 更新请求顺序进行: 来自同一个client的更新请求按其发送顺序依次执行
  • 数据更新原子性: 一次数据更新要么成功,要么失败
  • 实时性: 在一定时间范围内,client能读到最新的数据(zookeeper中存储的数据很少,同步很快).
  1. zookeeper数据结构
    zookeeper数据模型的结构和unix文件系统类似,整体可以看作是一棵树,每一个节点称作一个Znode.每一个Znode默认能够存储1MB的数据,每个Znode都可以通过其路径唯一标识.
    在这里插入图片描述
  2. zookeeper应用场景
  • 统一命名服务(包含进统一配置管理)
    在分布式环境下,经常需要对应用/服务进行统一命名,便于识别
    例如: 一个集群一个统一名称

  • 统一配置管理
    可将配置信息写入zookeeper上的一个Znode,各个客户端服务器监听这个Znode,一旦Znode中的数据修改,zookeeper将通知各个客户端服务器.

  • 统一集群管理
    zookeeper可以实现实时监控节点状态变化.可将节点信息写入zookeeper上的一个Znode,监听这个Znode可以获取它的实时状态变化.

  • 服务器节点动态上下线(包含进统一集群管理)
    客户端能实时洞察到服务器上下线的变化
    在这里插入图片描述

  • 软负载均衡
    在zookeeper中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求.

  1. zookeeper的安装
  • 安装jdk
# 更新软件包列表
sudo apt-get update
# 安装openjdk-8-jdk
sudo apt-get install openjdk-8-jdk
# 查看java版本,看是否安装成功
java -version
  • 下载zookeeper
    下载地址

  • 解压及拷贝zookeeper到指定目录

tar -zxvf zookeeper-3.3.3.tar.gz
mv zookeeper-3.3.3 /usr/local/zookeeper
  • 设置及更新环境变量
export ZOOKEEPER_HOME=/usr/local/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin 
source /etc/profile
  • 将conf文件夹下的zoo_sample.cfg拷贝一份为zoo.cfg、修改dataDir路径、在zookeeper文件夹下创建zkData文件夹
cp zoo_sample.cfg zoo.cfg
vim zoo.cfg
dataDir=/usr/local/zookeeper/zkData
  1. zookeeper常用命令
# bin目录下执行

# 启动zookeeper服务器
./zkServer.sh start

# 启动zookeerper客户端
./zkCli.sh

# 退出zookeeper客户端界面:
quit

# 终止zookeeper服务器提供服务
./zkServer.sh stop

# 查看zookeeper服务器状态
./zkServer.sh status

# 查看状态结果:
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Mode: standalone
  1. zoo.cfg初始配置文件参数解读
# zookeeper服务器和客户端心跳间隔时间(单位ms)
tickTime=2000
# leader和follower初始通信时限(单位tickTime)
# leader和follower之间的第一次通信超过initLimit*tickTime=10*2s=20s没有通信,就会被认为leader和follower连不上了.initLimit为心跳时间间隔次数
initLimit=10
# leader和follower同步通信时限(单位tickTime)
# 集群正常启动后,leader和follower之间的通信超过syncLimit*tickTime=5*2s=10s没有通信,就会被认为leader和follower连不上了
syncLimit=5
# 数据文件目录+数据持久化路径,主要用于保存zookeeper中的数据
dataDir=/usr/local/zookeeper/zkData
# 对客户端提供服务的端口
clientPort=2181
  1. zookeeper内部原理
  • 选举机制
    • 半数机制: 集群中半数以上的机器存活,集群可用.所以zookeeper适合安装奇数台服务器.

    • zookeeper工作时有一个节点为leader,其他为follower.leader是通过内部的选举机制临时产生的.

    • ZXID(参考链接):

      • ZXID 由 Leader 节点生成,有新写入事件时,Leader 生成新 ZXID 并随提案一起广播,每个结点本地都保存了当前最近一次事务的 ZXID,ZXID 是递增的,所以谁的 ZXID 越大,就表示谁的数据是最新的
      • ZXID的生成规则如下:
        在这里插入图片描述
      • ZXID 由两部分组成:
        任期:完成本次选举后,直到下次选举前,由同一 Leader 负责协调写入;
        事务计数器:单调递增,每生效一次写入,计数器加一。
      • ZXID 的低 32 位是计数器,所以同一任期内,ZXID 是连续的,每个结点又都保存着自身最新生效的 ZXID,通过对比新提案的 ZXID 与自身最新 ZXID 是否相差“1”,来保证事务严格按照顺序生效的。
    • 全新集群选举
      若进行Leader选举,则至少需要两台机器,这里选取3台机器组成的服务器集群为例。在集群初始化阶段,当有一台服务器Server1启动时,其单独无法进行和完成Leader选举,当第二台服务器Server2启动时,此时两台机器可以相互通信,每台机器都试图找到Leader,于是进入Leader选举过程。选举过程如下

      • 每个Server发出一个投票。由于是初始情况,Server1和Server2都会将自己作为Leader服务器来进行投票,每次投票会包含所推举的服务器的myid和ZXID,使用(myid, ZXID)来表示,此时Server1的投票为(1, 0),Server2的投票为(2, 0),然后各自将这个投票发给集群中其他机器。
      • 接受来自各个服务器的投票。集群的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票、是否来自LOOKING状态的服务器。
      • 处理投票。针对每一个投票,服务器都需要将别人的投票和自己的投票进行PK,PK规则如下
          优先检查ZXID。ZXID比较大的服务器优先作为Leader。
          如果ZXID相同,那么就比较myid。myid较大的服务器作为Leader服务器。
          对于Server1而言,它的投票是(1, 0),接收Server2的投票为(2, 0),首先会比较两者的ZXID,均为0,再比较myid,此时Server2的myid最大,于是更新自己的投票为(2, 0),然后重新投票,对于Server2而言,其无须更新自己的投票,只是再次向集群中所有机器发出上一次投票信息即可。
      • 统计投票。每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受到相同的投票信息,对于Server1、Server2而言,都统计出集群中已经有两台机器接受了(2, 0)的投票信息,此时便认为已经选出了Leader。
      • 改变服务器状态。一旦确定了Leader,每个服务器就会更新自己的状态,如果是Follower,那么就变更为FOLLOWING,如果是Leader,就变更为LEADING。
    • 非全新集群选举
      对于运行正常的 zookeeper 集群,中途有机器 down 掉,需要重新选举时, 选举过程就需要加入数据 ID、服务器 ID 和逻辑时钟。

    • 数据 ID:数据新的 version 就大,数据每次更新都会更新 version。
    • 服务器 ID:就是我们配置的 myid 中的值,每个机器一个。
    • 逻辑时钟:这个值从 0 开始递增,每次选举对应一个值。 如果在同一次选举中,这个值是一致的。 这样选举的标准就变成:
      ① 逻辑时钟小的选举结果被忽略,重新投票;
      ②统一逻辑时钟后,数据 id 大的胜出;
      ③数据 id 相同的情况下,服务器 id 大的胜出;
      根据这个规则选出 leader。
  1. zookeeper节点类型
    Zookeeper 中节点类型按持久化可分为临时节点和持久节点,按顺序性可分为顺序和无序。
  • 持久节点:节点创建后,会一直存在,不会因客户端会话失效而删除
  • 持久顺序节点:基本特性与持久节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名
  • 临时节点:客户端会话失效或连接关闭后,该节点会被自动删除,且不能再临时节点下面创建子节点
    应用场景: 服务器节点动态上下线
  • 临时顺序节点:基本特性与临时节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名
  1. zookeeper分布式安装部署
  • 集群规划
机器编号 IP地址(使用的虚拟机) 端口
Zk-1 192.168.145.3 2181
Zk-2 192.168.145.3 2182
Zk-3 192.168.145.3 2183
  • 新建集群文件夹并准备三个zookeeper
# /usr/local目录下执行
sudo mkdir zk-cluster
sudo cp -r /usr/local/zookeeper/ /usr/local/zk-cluster/zk1/
sudo cp -r /usr/local/zookeeper/ /usr/local/zk-cluster/zk2/
sudo cp -r /usr/local/zookeeper/ /usr/local/zk-cluster/zk3/
  • 创建数据和日志文件夹,并在zkData文件夹下新建myid文件添加与server对应的编号,
# 在zk1、zk2、zk3目录下分别执行
sudo mkdir zkData(之前创建单机模式的时候创建过)
sudo mkdir log

# 在zk1的zkData下执行
sudo touch myid
sudo vim myid
输入1保存退出

# 在zk2的zkData下执行
sudo touch myid
sudo vim myid
输入2保存退出

# 在zk3的zkData下执行
sudo touch myid
sudo vim myid
输入3保存退出 
  • 修改conf/zoo.cfg配置文件
tickTime=2000
initLimit=10
syncLimit=5

# 下面三行配置zk2/zk3类似
dataDir=/usr/local/zk-cluster/zk1/zkData
dataLogDir=/usr/local/zk-cluster/zk1/log
# zk2为2182,zk3为2183
clientPort=2181

# 集群的配置文件(zk2和zk3相同)
#第几个服务器(1,2,3来自数据目录的一个myid文件,该文件里面保存着当前集群的标识(1,2,3))
# 后面的ip代表将绑定那个ip地址 第一个端口:代表在集群内部,数据复制的接口 第二个端口代表:选举端口
server.1=192.168.145.3:2888:3888
server.2=192.168.145.3:2889:3889
server.3=192.168.145.3:2887:3887
  • 启动zk1、zk2、zk3
# 在zk-cluster目录下执行
./zk1/bin/zkServer.sh start
./zk2/bin/zkServer.sh start
./zk3/bin/zkServer.sh start

# 启动完成后可以通过以下命令查看服务器状态
./zk1/bin/zkServer.sh status   (follower)
./zk2/bin/zkServer.sh status   (leader)
./zk3/bin/zkServer.sh status   (follower)
  1. zookeeper常用shell命令
  • help: 显示所有操作命令

  • ls /: 查看当前znode中所包含的内容

  • ls2 /: 查看当前znode详细数据

  • create /znode_name znode_value: 创建节点(持久型)

    create /sanguo "shuguo"
    create /sanguo/shuguo "liubei"
    
  • get /znode_name: 获取节点的值
    比如可以应用于服务器节点动态上下线.如果能获取到节点中的值,则说明服务器节点存在,否则不存在.

    [zk: localhost:2181(CONNECTED) 12] get /sanguo
    shuguo
    cZxid = 0x100000002
    ctime = Wed Jan 06 18:41:01 ULAT 2021
    mZxid = 0x100000002
    mtime = Wed Jan 06 18:41:01 ULAT 2021
    pZxid = 0x100000003
    cversion = 1
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 6
    numChildren = 1
    
    [zk: localhost:2181(CONNECTED) 13] get /sanguo/shuguo
    liubei
    cZxid = 0x100000003
    ctime = Wed Jan 06 18:41:38 ULAT 2021
    mZxid = 0x100000003
    mtime = Wed Jan 06 18:41:38 ULAT 2021
    pZxid = 0x100000003
    cversion = 0
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 6
    numChildren = 0
    
  • create -e /znode_name znode_value: 创建短暂节点

    [zk: localhost:2181(CONNECTED) 14] create -e /sanguo/weiguo "caocao"
    Created /sanguo/weiguo
    [zk: localhost:2181(CONNECTED) 17] ls /sanguo
    [shuguo, weiguo]
    [zk: localhost:2181(CONNECTED) 18] quit
    zhaolijian@ubuntu:/usr/local/zk-cluster/zk1/bin$ sudo ./zkServer.sh start
    zhaolijian@ubuntu:/usr/local/zk-cluster/zk1/bin$ ./zkCli.sh
    [zk: localhost:2181(CONNECTED) 0] ls /sanguo
    [shuguo]      # 可以看到没有weiguo了,因为它是短暂节点
    
  • create -s /znode_name znode_value: 创建带序号的节点(持久型)

    [zk: localhost:2181(CONNECTED) 1] create -s /sanguo/wuguo "sunquan"
    Created /sanguo/wuguo0000000002
    [zk: localhost:2181(CONNECTED) 2] ls /sanguo
    [wuguo0000000002, shuguo]
    
  • set /znode_name znode_value: 修改节点数据值

    [zk: localhost:2181(CONNECTED) 3] get /sanguo/shuguo  
    liubei      
    [zk: localhost:2181(CONNECTED) 4] set /sanguo/shuguo "diaochan"
    [zk: localhost:2181(CONNECTED) 6] get /sanguo/shuguo
    diaochan
    
  • get /znode_name watch: 监听节点值变化(只对一次修改有效,再次set就不能监听了)

    # zk1
    [zk: localhost:2181(CONNECTED) 8] get /sanguo/shuguo watch
    diaochan
    
    # 启动zk2 client
    [zk: localhost:2181(CONNECTED) 0] set /sanguo/shuguo "wode"
    
    # zk1:
    [zk: localhost:2181(CONNECTED) 9] 
    WATCHER::
    WatchedEvent state:SyncConnected type:NodeDataChanged path:/sanguo/shuguo
    
    
  • ls /zparent_node watch: 监听节点的子节点变化(路径变化,只一次有效)

    # zk1: 监听/sanguo节点下的子节点
    [zk: localhost:2181(CONNECTED) 10] ls /sanguo watch   
    [wuguo0000000002, shuguo]
    # zk2: 在/sanguo节点下增加节点
    [zk: localhost:2181(CONNECTED) 4] create /sanguo/weiguo "caopei"  
    Created /sanguo/weiguo
    # zk1:
    [zk: localhost:2181(CONNECTED) 11]         
    WATCHER::
    WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/sanguo
    
  • delete /znode: 删除节点

    [zk: localhost:2181(CONNECTED) 11] ls /sanguo 
    [wuguo0000000002, shuguo, weiguo]
    [zk: localhost:2181(CONNECTED) 12] delete /sanguo/weiguo
    [zk: localhost:2181(CONNECTED) 13] ls /sanguo
    [wuguo0000000002, shuguo]
    
  • rmr /znode: 递归删除节点

    [zk: localhost:2181(CONNECTED) 14] rmr /sanguo
    [zk: localhost:2181(CONNECTED) 15] ls /
    [zookeeper]
    
  • stat /znode: 查看节点状态

    [zk: localhost:2181(CONNECTED) 18] create /sanguo "tianzi"
    Created /sanguo
    [zk: localhost:2181(CONNECTED) 19] stat /sanguo
    cZxid = 0x100000015
    ctime = Wed Jan 06 20:07:02 ULAT 2021
    mZxid = 0x100000015
    mtime = Wed Jan 06 20:07:02 ULAT 2021
    pZxid = 0x100000015
    cversion = 0
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 6
    numChildren = 0
    
  1. stat查看节点状态结构体参数
  • cZxid: 创建节点的事务zxid
    每次修改zookeeper状态都会收到一个zxid形式的时间戳,也就是zookeeper事务ID,事务ID是zookeeper中所有修改总的次序.每个修改都有一个唯一的zxid,如果zxid1<zxid2,那么zxid1发生在zxid2之前
  • ctime: znode被创建的毫秒数(从1970年开始)
  • mZxid: znode最后更新的事务zxid
  • mtime: znode最后修改的毫秒数(从1970年开始)
  • pZxid: znode最后更新的子节点zxid
  • cversion: znode子节点变化号,znode子节点修改次数
  • dataVersion: znode数据变化号
  • aclVersion: znode访问控制列表的变化号
  • ephemeralOwner: 如果是临时节点,这个是znode拥有者的session id, 否则为0
  • dataLength: znode的数据长度
  • numChildren: znode子节点数量
  1. zookeeper监听器原理
    在这里插入图片描述
  2. zookeeper写数据流程
    在这里插入图片描述
  3. 服务器动态上下线案例分析
    在这里插入图片描述
    注:
  • 服务器1/2/3不是zookeeper服务器,而是为客户端1/2/3提供服务的服务器.
  • zookeeper集群中有leader/follower服务器,图中没有展示
  • zookeeper集群框中的80 nodes / 90 nodes /95 nodes是连接到服务器的客户端数量

猜你喜欢

转载自blog.csdn.net/qq_26496077/article/details/112239069