Zookeeper集群搭建及原理

1 概述

1.1 简介

ZooKeeper 是 Apache 的一个顶级项目,为分布式应用提供高效、高可用的分布式协调服务,提供了诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知和分布式锁等分布式基础服务。由于 ZooKeeper 便捷的使用方式、卓越的性能( 基于内存)和良好的稳定性,被广泛地应用于诸如 Hadoop、HBase、Kafka 和 Dubbo 等大型分布式系统中。
官方地址:https://zookeeper.apache.org

1.2 角色

领导者(leader):负责进行投票的发起和决议,更新系统状态。
跟随者(follower):用于接收客户端请求并给客户端返回结果,在选主过程中进行投票。
观察者(observer):可以接受客户端连接,将写请求转发给 leader,但是observer 不参加投票的过程,只是为了扩展系统,提高读取的速度。

Zookeeper集群搭建及原理

; 1.3 节点特性

ZooKeeper 节点的生命周期取决于节点的类型。在 ZooKeeper 中,节点根据持续时间可以分为 持久节点(PERSISTENT)临时节点(EPHEMERAL),根据是否有序可以分为顺序节点(SEQUENTIAL)、和无序节点(默认是无序的)。 每个客户端连接zookeeper会产生一个session,客户端连接关闭时session也会消失
持久节点一旦被创建,除非主动移除,不然一直会保存在 Zookeeper 中(不会因为创建该节点的客户端的会话失效而消失)。

1.4 数据模型

层次化的目录结构,命名符合常规文件系统规范,类似于文件目录。
每个节点在 Zookeeper 中叫做 Znode,并且其有一个唯一的路径标识。
每个节点中数据存储不能超过1M(不要把Zookeeper当数据库用)。

Zookeeper集群搭建及原理

; 1.5 特性

顺序一致性。客户端的更新将按发送顺序应用。
原子性。要么成功要失败。没有中间状态( 最终一致性)。
单个系统映像。由于zookeeper使用复制集群,无论客户端连接哪个节点都能看到相同的数据。
可靠性。即所有节点支持持久化。
及时性。存储在节点中的数据会在较短时间内及时同步。

1.6 CAP

任何分布式架构都不能同时满足C(一致性)、A(可用性)、P(分区容错性)。zookeeper集群在保证一致性的同时,在A和P之间做了取舍,最终选择了P,因此可用性差一点。

2 zookeeper集群搭建

2.1 网络拓扑

Zookeeper集群搭建及原理

; 2.2 环境准备

CentOS7 * 4
JDK8
Zookeeper3.6.3

2.3 安装

在q101服务器中配置好后发送到其他服务器。q101操作如下:

wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.6.3/apache-zookeeper-3.6.3-bin.tar.gz --no-check-certificate

tar xf apache-zookeeper-3.6.3-bin.tar.gz
mv apache-zookeeper-3.6.3-bin /usr/local/zookeepe
cd /usr/local/zookeeper/conf
mv zoo_sample.cfg zoo.cfg
vi zoo.cfg
1. 修改dataDir路径为"/var/zookeeper"
2. 增加集群节点信息,信息如下
server.4=192.168.88.101:2888:3888
server.3=192.168.88.102:2888:3888
server.2=192.168.88.103:2888:3888
server.1=192.168.88.104:2888:3888
3. 保存退出

创建配置文件中设置的持久化目录
mkdir /var/zookeeper

将节点信息中的节点ID写如myid中
echo 4 > /var/zookeeper/myid

修改环境变量 增加zookeeper信息
export ZOOKEEPER_HOME=/usr/local/zookeeper
在export PATH末尾追加 :$ZOOKEEPER_HOME/bin
 vi /etc/profile
 source /etc/profile

Zookeeper集群搭建及原理

详细配置说明

leader和follower心跳时间,用于维护节点是否存活。单位毫秒
tickTime=2000

初始延迟。当follower追随leader时,leader允许初始延迟时间。
用tickTime乘以initLimit,此处为2000*10即20秒
initLimit=10

数据同步时间,及超过时间数据同步失败。
用tickTime乘以syncLimit,此处为2000*5即10秒
syncLimit=5

持久化目录,不建议存在tmp下
dataDir=/var/zookeeper

客户端连接zookeeper端口号
clientPort=2181

允许客户端连接最大连接数
#maxClientCnxns=60

dataDir中保留快照数量
#autopurge.snapRetainCount=3

清除任务时间间隔,单位小时。0表示禁用自动清楚功能
#autopurge.purgeInterval=1

自定义监控
#metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
#metricsProvider.httpPort=7000
#metricsProvider.exportJvmInfo=true

此处为自己添加的配置。集群信息,投票过半数量=(集群节点行数 除以 2)+1
数字1,2,3,4为节点ID,用于谦让出leader,投票过半后数字最大的为leader
端口说明:当leader挂掉后(或第一次启动没有leader时候)其他节点通过3888建立连接进行投票选出leader,
               选中leader后,leader会通过2888端口来与follower进行工作
server.4=192.168.88.101:2888:3888
server.3=192.168.88.102:2888:3888
server.2=192.168.88.103:2888:3888
server.1=192.168.88.104:2888:3888

将q101相关文件传到q102并修改myid

scp -r /usr/local/zookeeper 192.168.88.102:/usr/local/
scp -r /var/zookeeper 192.168.88.102:/var/
scp /etc/profile 192.168.88.102:/etc

切换到q102服务器执行,数字与配置文件中的节点ID数据一致
echo 3 > /var/zookeeper/myid
q102执行 使环境变量生效
source /etc/profile

将q101相关文件传到q103并修改myid

scp -r /usr/local/zookeeper 192.168.88.103:/usr/local/
scp -r /var/zookeeper 192.168.88.102:/var/
scp /etc/profile 192.168.88.103:/etc

切换到q103服务器执行
echo 2 > /var/zookeeper/myid
source /etc/profile

将q101相关文件传到q104并修改myid

scp -r /usr/local/zookeeper 192.168.88.103:/usr/local/
scp -r /var/zookeeper 192.168.88.102:/var/
scp /etc/profile 192.168.88.104:/etc

切换到q104服务器执行
echo 1 > /var/zookeeper/myid
source /etc/profile

2.4 启动

为了测试我们采用前台启动,4台节点分别执行

zkServer.sh start-foreground

启动前3台的时候会发现报错,连接其他节点失败,属于正常情况,当启动最后一台的时候发现没有发错了。原因是启动前2台的时候没有leader。当第3台启动完成的时候,此时节点数量已经超过半数,所以开始根据 zoo.cfg配置文件中的服务ID进行选举,因为q101服务器ID 设置的4,按节点谦让规则q101为leader。
启动错误信息如下:

Zookeeper集群搭建及原理
节点角色验证
在q101执行
zkServer.sh status

Zookeeper集群搭建及原理

3 zookeeper常用功能

3.1 常用命令

启动关闭
后台启动: zkServer.sh start
前台启动: zkServer.sh start-foreground
停止: zkServer.sh stop
重启: zkServer.sh restart
查看版本:z kServer.sh version
查看状态: zkServer.sh status

连接与退出
连接zookeeper客户端: zkCli.sh -server 127.0.0.1:2181 连接本机可以直接输入 zkCli.sh
退出zookeeper客户端: quit

操作命令
查看zookeeper所有命令:连接到zookeeper客户端后输入 help
查看根目录下包含的节点: ls /
查看节点状态信息: ls2 /或者使用 ls -s /

创建一个非顺序的持久化节点: create [-s] [-e] path data acl比如 create /test test-1
创建一个临时节点: create -e /test/tmp tem-data
创建一个顺序节点: create -s /test/aaa aaa-data
删除一个节点: delete /test

[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] create /abc
Created /abc
[zk: localhost:2181(CONNECTED) 3] ls /
[abc, zookeeper]
创建节点后默认数据为null
[zk: localhost:2181(CONNECTED) 9] get /abc
null
[zk: localhost:2181(CONNECTED) 4] create /abc/abcd
Created /abc/abcd
[zk: localhost:2181(CONNECTED) 15] set /abc/abcd hello
[zk: localhost:2181(CONNECTED) 16] get /abc/abcd
hello

3.2 stat结构

Zookeeper每个znode都有一个与之关联的stat结构,类似于Unix/Linux文件系统中文件的stat结构。通过 stat /xxx/xxx查看

[zk: localhost:2181(CONNECTED) 17] stat /abc/abcd
cZxid = 0x100000003
ctime = Wed Mar 02 23:41:34 CST 2022
mZxid = 0x100000006
mtime = Wed Mar 02 23:43:32 CST 2022
pZxid = 0x100000003
cversion = 0
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0

字段含义
cZxid:创建节点znode时的事务ID由leader维护的递增计数器,共64位,其中前32为表示leader纪元,即leader革新换代次数,比如上面的0x1表示目前leader为做变更,如当前leader关闭后重新选举的leader此处会变成0x2,并且后32位的事务ID重新开始;后32为表示所有的增删改操作次数。
mZxid:修改节点znode更改的事务ID。
pZxid:添加或删除子节点znode更改的事务ID。
ctime:表示从1970-01-01T00:00:00Z开始以毫秒为单位的znode创建时间。
mtime:表示从1970-01-01T00:00:00Z开始以毫秒为单位的znode最近修改时间。
dataVersion:表示对该znode的数据所做的更改次数。
cversion:表示对此znode的子节点进行的更改次数。
aclVersion:版本号,即znode的ACL进行更改的次数。
ephemeralOwner:如果znode是ephemeral类型节点,则这是znode所有者的 session ID。 如果znode不是ephemeral节点,则该字段设置为零。
dataLength:这是znode数据字段的长度。
numChildren:这表示znode的子节点的数量。

3.3 临时节点

临时节点伴随着session会话,当会话结束后临时节点销毁

  1. 通过q101连接zookeeper客户端查看日志
    Zookeeper集群搭建及原理

通过日志发现sessionID为:0x400000595cc0001
2. 创建临时节点 create -e /xxxx

create -e /aaa
  1. 通过stat查看发现刚创建的临时节点”bbbb”的ephemeralOwner正是连接时候的sessionID
    Zookeeper集群搭建及原理
    当使用另一台服务器q102连接zkCli后查看aaa节点stat sessionID依旧是q101连接的sessionID。

3.4 持久序列

通过 create -s path data可以创建持久序列,znode被创建后,znode名称会自动添加一个编号,编号会自动递增。编号的递增和节点名称无关.

Zookeeper集群搭建及原理
编号的递增不会因为断开而重置,也不会因为zookeeper重启而重置

; 4 zookeeper原理

4.1 Paxos算法

它是一个基于消息传递的一致性算法,Leslie Lamport在1990年提出,近几年被广泛应用于分布式计算中,Google的Chubby,Apache的Zookeeper都是基于它的理论来实现的,Paxos还被认为是到目前为止唯一的分布式一致性算法,其它的算法都是Paxos的改进或简化。有个问题要提一下,Paxos有一个前提:Paxos只有在一个可信的计算环境中才能成立,这个环境是不会被入侵所破坏的。

关于Paxos的具体描述可以参考:https://baike.baidu.com/item/Paxos算法

4.2 ZAB协议

ZAB(ZooKeeper Atomic broadcast)即ZooKeeper原子消息广播协议,类似于一个二阶段提交过程(2PC)属于最终一致性。是zookeeper基于Paxos算法的简化实现。

所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为 Leader服务器,而余下的其他服务器则成为 Follower服务器。 Leader服务器负责将一个客户端事务请求转换成一个事务 Proposal(提议),并将该 Proposal分发給集群中所有的Follower服务器。之后 Leader服务器需要等待所有 Follower服务器的反馈,一旦超过半数的 Follower服务器进行了正确的反馈后,那么 Leader就会再次向所有的 Follower服务器分发 Commit消息,要求其将前一个 Proposal进行提交。

Zookeeper集群搭建及原理

上图说明:
1:Client向Follower发出写操作;
2:Follower将收到的写请求转发给Leader处理;
3:Leader收到请求后分配一个全局单调递增的唯一的事务ID(即ZXID,按其先后顺序来进行排序与处理);
4.1:Leader服务器会为每一个 Follower服务器都各自分配一个单独的队列,然后将需要广播的事务Proposal依次放入这些队列中去,并且根据FIFO策略进行消息发送;每一个 Follower服务器在接收到这个事务 Proposal之后,都会首先将其以事务日志的形式写入到本地磁盘中去,并且在成功写入后反馈给 Leader服务器个Ack响应。Leader自己也会将事务日志写入磁盘;
4.2:当 Leader服务器接收到 超过半数Follower的Ack响应后,就会广播一个Commit消息给所有的 Follower服务器以通知其进行事务提交( 写入内存),同时 Leader自身也会完成对事务的提交。
5:由Leader将结果返回给Client1

上图中4.1和4.2步骤,由于Leader自身也计一票,如果Follower2 由于网络等原因没有给Leader Ack响应,但Leader和Follower 1 两票已超过半数,所以结果依然会成功。此时Client2请求Follower2获取”/aaa”数据时,可以通过sync 让Follower 2向Leader同步后再返回数据。

; 4.3 选举机制

4.3.1 节点网络

基于上面的第2章集群搭建,查看每台节点网络连接情况

yum install net-tools
netstat -natp | egrep '(2888|3888)'

查看结果如下:

q101信息
[root@q101 ~]# netstat -natp | egrep '(2888|3888)'
tcp6       0      0 192.168.88.101:3888     :::*                    LISTEN      1924/java
tcp6       0      0 192.168.88.101:58052    192.168.88.102:3888     ESTABLISHED 1924/java
tcp6       0      0 192.168.88.101:39738    192.168.88.103:3888     ESTABLISHED 1924/java
tcp6       0      0 192.168.88.101:54174    192.168.88.102:2888     ESTABLISHED 1924/java
tcp6       0      0 192.168.88.101:47726    192.168.88.104:3888     ESTABLISHED 1924/java

q102信息
[root@q102 ~]#  netstat -natp | egrep '(2888|3888)'
tcp6       0      0 192.168.88.102:2888     :::*                    LISTEN      1661/java
tcp6       0      0 192.168.88.102:3888     :::*                    LISTEN      1661/java
tcp6       0      0 192.168.88.102:3888     192.168.88.101:58052    ESTABLISHED 1661/java
tcp6       0      0 192.168.88.102:2888     192.168.88.103:38244    ESTABLISHED 1661/java
tcp6       0      0 192.168.88.102:50104    192.168.88.104:3888     ESTABLISHED 1661/java
tcp6       0      0 192.168.88.102:2888     192.168.88.104:48034    ESTABLISHED 1661/java
tcp6       0      0 192.168.88.102:2888     192.168.88.101:54174    ESTABLISHED 1661/java
tcp6       0      0 192.168.88.102:37466    192.168.88.103:3888     ESTABLISHED 1661/java

q103信息
[root@q103 ~]#  netstat -natp | egrep '(2888|3888)'
tcp6       0      0 192.168.88.103:3888     :::*                    LISTEN      1415/java
tcp6       0      0 192.168.88.103:38244    192.168.88.102:2888     ESTABLISHED 1415/java
tcp6       0      0 192.168.88.103:3888     192.168.88.101:39738    ESTABLISHED 1415/java
tcp6       0      0 192.168.88.103:3888     192.168.88.102:37466    ESTABLISHED 1415/java
tcp6       0      0 192.168.88.103:58344    192.168.88.104:3888     ESTABLISHED 1415/java

q104信息
[root@q104 ~]#  netstat -natp | egrep '(2888|3888)'
tcp6       0      0 192.168.88.104:3888     :::*                    LISTEN      1333/java
tcp6       0      0 192.168.88.104:3888     192.168.88.101:47726    ESTABLISHED 1333/java
tcp6       0      0 192.168.88.104:3888     192.168.88.102:50104    ESTABLISHED 1333/java
tcp6       0      0 192.168.88.104:3888     192.168.88.103:58344    ESTABLISHED 1333/java
tcp6       0      0 192.168.88.104:48034    192.168.88.102:2888     ESTABLISHED 1333/java

通过上面的网络信息整体网络连接图如下

Zookeeper集群搭建及原理
上图说明:
zookeeper Leader和Follower连接主要通过2888和3888,2888主要用于leader与follower进行工作,3888用于Leader选举。每个zookeeper节点都会与其他节点建立连接。

4.3.2 选举流程

情况一:第一次启动
以上面我们搭好的4台节点为例,myid和zxid情况如下:

Zookeeper集群搭建及原理

节点名称 myid zxid q101 4 0 q102 3 0 q103 2 0 q104 1 0

选举前提当投票数量超过半数时才有效,此处4台节点,当第一次启动时候zxid都为0。只要有3台节点启动就可以选举出Leader。虽然说q101的myid=4但是如果最后启动q101,那么第一次启动时一定是q102成为Leader。

情况二:zxid不为0时,当集群重启,或Leader挂了的时候
当Leader挂了后,zookeeper集群会进行推选制选举,会优先选举数据最全的节点作为Leader(通过比较zxid,zxid越大代表该节点数据最全),如果zxid相同再比较myid。

Zookeeper集群搭建及原理

节点名称 myid zxid q101 4 0x100000009 q103 2 0x100000010 q104 1 0x100000010

原Leader q102挂掉后无论哪个节点先发现Leader挂掉,都会推选zxid最大的节点,q103和q104 zxid 都为xxx10再比较myid。所以此处q103最终会被选为新的Leader。

; 5 watch

  1. Watch是轻量级的,其实就是本地JVM的Callback,服务器端只是存了是否有设置了Watcher的布尔类型。
  2. 在服务端,在FinalRequestProcessor处理对应的Znode操作时,会根据客户端传递的watcher变量,添加到对应的ZKDatabase(org.apache.zookeeper.server.ZKDatabase)中进行持久化存储,同时将自己NIOServerCnxn做为一个Watcher callback,监听服务端事件变化
  3. Leader通过投票通过了某次Znode变化的请求后,然后通知对应的Follower,Follower根据自己内存中的zkDataBase信息,发送notification信息给zookeeper客户端。
  4. Zookeeper客户端接收到notification信息后,找到对应变化path的watcher列表,挨个进行触发回调。

6 zookeeper实现分布式锁

6.1 实现原理

多个节点同时在一个指定的节点下面创建临时会话顺序节点,谁创建的节点序号最小,谁就获得了锁,并且其他节点就会监听序号比自己小的节点,一旦序号比自己小的节点被删除了,其他节点就会得到相应的事件,然后查看自己是否为序号最小的节点,如果是,则获取锁。

Zookeeper集群搭建及原理

Original: https://www.cnblogs.com/dooor/p/zookeeper0304.html
Author: Dvomu
Title: Zookeeper集群搭建及原理

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/607157/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • MySQL实现 group_concat 排序

    MySQL支持实现group_concat() 内部自定义排序: 实例: 新建一张表 reward,表中数据如下: SQL: SELECT uid, GROUP_CONCAT(mo…

    Linux 2023年6月13日
    0109
  • JavaScript快速入门-02-基本语法

    2 基本语法 2.1 JavaScript简介 JavaScript 是一门 解释型语言,其代码在客户端中执行前不需经过编译,而是直接由浏览器解释执行。主要用作 客户端脚本语言,在…

    Linux 2023年6月7日
    0106
  • MySQL注入流程

    确认注入点 信息收集 数据获取 提权 写个MySQL注入流程的大纲,类似一份全局地图,能指导下一步工作。MySQL注入流程分为四步: 确认注入点 信息收集 数据获取 提权 确认注入…

    Linux 2023年6月6日
    0112
  • Linux文件查找命令find与三剑客之grep

    一、find 根据文件的名称或者属性查找文件。 语法格式: find [查找范围] [参数] 参数: -name : 按照文件的名字查找文件 * :通配符 -iname : 按照文…

    Linux 2023年5月27日
    0157
  • C语言之初认识

    1.低级语言可以简明说:非常接近底层语言 2.可移值性:可以嵌入各大系统中 3.简单性:语法简单,语法规则没有太大限制,c语言的代码要求比较随意,一行可以写入多行语句,每条语句写完…

    Linux 2023年6月8日
    084
  • WPF 应用启动过程同时启动多个 UI 线程且访问 ContentPresenter 可能让多个 UI 线程互等

    在应用启动过程里,除了主 UI 线程之外,如果还多启动了新的 UI 线程,且此新的 UI 线程碰到 ContentPresenter 类型,那么将可能存在让新的 UI 线程和主 U…

    Linux 2023年6月6日
    089
  • PTA 《基础编程题目集》 6-7 统计某类完全平方数

    本题要求实现一个函数,判断任一给定整数N是否满足条件:它是完全平方数,又至少有两位数字相同,如144、676等。 函数接口定义: int IsTheNumber ( const i…

    Linux 2023年6月8日
    0109
  • Redis 基础

    Redis 基础 Redis 定位 – 特性 关系型数据库 特性 非关系型数据库 特性 Redis 特性 Redis 安装 – 启动 – 使用 …

    Linux 2023年6月13日
    0138
  • 异常—异常安全问题–内存泄漏动图演示

    异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的 直接或间接的调用者处理这个错误。 throw: 当问题出现时,程序会抛出一个异常。这是通过使用…

    Linux 2023年6月13日
    087
  • Mac远程windows工具

    现在很多小伙伴都是使用MAC系统,但在工作中或多或少会遇到需要远程windows的情况,今天给大家安利一款软件,让你轻轻松松远程windows Microsoft Remote D…

    Linux 2023年6月7日
    096
  • 每天一个 HTTP 状态码 100

    100 Continue 指示客户端应该继续当前请求;如果请求已经完成… 100 Continue 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分;指示客户…

    Linux 2023年6月7日
    096
  • Git的常见命令

    Git 一、git环境安装 1.初始化本地仓库: git init 2.将本地仓库跟远程仓库建立连接:git remote add name path ​ git clone pa…

    Linux 2023年6月7日
    080
  • hadoop分布式集群部署①

    Linux系统的安装和配置。(在VM虚拟机上) 一:安装虚拟机VMware Workstation 14 Pro 以上,虚拟机软件安装完成。 二:创建虚拟机。 三:安装CentOS…

    Linux 2023年6月13日
    084
  • 2.VMware三种网络模式

    本文参考《Vmware虚拟机三种网络模式详解》、《网络原理,以及对VMware Workstation虚拟网络VMnet0、VMnet1、VMnet8的图解》 一.VMware的网…

    Linux 2023年5月27日
    0120
  • 多用户共享文件

    假设有三个用户:Tom Jerry Bob.其中,tom和Jerry都属于market部,Bob属于tech部,请在/usr目录下创建两个用户共享的目录market和public,…

    Linux 2023年6月13日
    090
  • MediaFire 网盘队列下载脚本

    MediaFire是一个国外的网盘。通常情况下,我们可以用浏览器下载MediaFire的文件,但是不能同时下载过多文件,只能几个几个地慢慢手动下载,比较费时间,所以我设计了这样一个…

    Linux 2023年6月6日
    0131
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球