zookeeper使用说明文档


难度 中等

安装部署

需对每一台zookeeper集群节点做如下操作:

  • 安装openjdk并设置JAVA_HOME

    sudo apt-get install openjdk-8-jdk
    export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
  • 下载zookeeper

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

    注意:下载时需下载带bin的包,否则会在启动时报找不到主类的错。

  • 安装zookeeper

    cd /opt
    tar -xvf apache-zookeeper-3.6.3-bin.tar.gz
    export ZOOKEEPER_HOME=/opt/apache-zookeeper-3.6.3-bin
    export PATH=$PATH:$ZOOKEEPER_HOME/bin
  • 配置zookeeper

    cd /opt
    mkdir data
    mkdir logs
    cd /opt/apache-zookeeper-3.6.3-bin/conf
    vim zoo.cfg

    zoo.cfg的文件内容如下:

    tickTime=2000
    initLimit=10
    syncLimit=5
    dataDir=/opt/data
    dataLogDir=/opt/logs
    clientPort=2181
    server.1=ip1:2888:3888
    server.2=ip2:2888:3888
    server.3=ip3:2888:3888

    对每个节点分别执行如下命令:

    # 对2,3节点分别换成2和3
    echo "1" >> /opt/data/myid
  • 启动

    cd /opt/apache-zookeeper-3.6.3-bin/bin
    ./zkServer.sh start
  • 查看状态

    cd /opt/apache-zookeeper-3.6.3-bin/bin
    ./zkServer.sh status
  • 连接服务端

    cd /opt/apache-zookeeper-3.6.3-bin/bin
    ./zkCli.sh -server ip1:2181

zookeeper基础概念

ZooKeeper 是一个开源的分布式协调服务,由雅虎创建,是 Google Chubby 的开源实现。

分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、配置维护,名字服务、分布式同步、分布式锁和分布式队列等功能。

它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

ZooKeeper使用共享存储实现对分布式系统的协调。其实共享存储,分布式应用也需要和存储进行网络通信。网络通信是分布式系统并发设计的基础。

  • znode

在ZooKeeper中,任务的分配、完成情况,等共享信息被保存在一个个数据节点上,这些节点被称为znode。它采用了类似文件系统的层级树状结构进行管理。znode节点存储的数据为字节数组。存储数据的格式zookeeper不做限制,也不提供解析,需要应用自己实现。

znode支持如下操作:

create /path data

    创建一个名为/path的znode,数据为data。

delete /path

    删除名为/path的znode。

exists /path

    检查是否存在名为/path的znode

set /path data

    设置名为/path的znode的数据为data

get /path

    返回名为/path的znode的数据
  • 观察与通知

zookeeper采用了通知的机制。客户端向zookeeper请求,在特定的znode设置观察点(watch)。当该znode发生变化时,会触发zookeeper的通知,客户端收到通知后进行业务处理。观察点触发后立即失效。所以一旦观察点触发,需要再次设置新的观察点。

  • 版本

每个znode都有版本号,随着每次数据变化自增。setData和delete,以版本号作为参数,当传入的版本号和服务器上不一致时,调用失败。当多个zookeeper客户端同时对一个znode操作时,版本将会起到作用,假设c1,c2同时往一个znode写数据,c1先写完后版本从1升为2,但是c2写的时候携带版本号1,c2会写入失败。

  • 法定人数

zookeeper服务器运行于两种模式:独立模式和仲裁模式(集群)。仲裁模式下,会复制所有服务器的数据树。但如果让客户端等待所有复制完成,延迟太高。这里引入法定人数概念,指为了使zookeeper集群正常工作,必须有效运行的服务器数量。同时也是服务器通知客户端保存成功前,必须保存数据的服务器最小数。例如我们有一个5台服务器的zookeeper集群,法定人数为3,只要任何3个服务器保存了数据,客户端就会收到确认。只要有3台服务器存活,整个zookeeper集群就是可用的。

  • 会话

客户端对zookeeper集群发送任何请求前,需要和zookeeper集群建立会话。客户端提交给zookeeper的所有操作均关联在一个会话上。当一个会话因某种原因终止时,会话期间创建的临时节点将会消失。而当当前服务器的问题,无法继续通信时,会话将被透明的转移到另外一台zookeeper集群的服务器上。

ZAB协议

ZooKeeper 保证 分布式系统数据一致性的核心算法就是 ZAB 协议(ZooKeeper Atomic Broadcast,原子消息广播协议)。其主要依赖于 ZAB 协议的 消息广播,崩溃恢复和数据同步 三个过程。

消息广播

  1. 一个事务请求(Write)进来之后,Leader 节点会将写请求包装成 Proposal 事务,并添加一个全局唯一的 64 位递增事务 ID,也就是 Zxid(消息的先后顺序就是通过比较 Zxid);
  2. Leader 节点向集群中其他节点广播 Proposal 事务,Leader 节点和 Follower 节点是解耦的,通信都会经过一个 FIFO 的消息队列,Leader 会为每一个 Follower 节点分配一个单独的 FIFO 队列,然后把 Proposal 发送到队列中;
  3. Follower 节点收到对应的 Proposal 之后会把它持久到磁盘上,当完全写入之后,发一个 ACK 给 Leader;
  4. 当 Leader 节点收到超过半数 Follower 节点的 ACK 之后(Quorum 机制),会提交本地机器上的事务,同时开始广播 commit, Follower 节点收到 commit 之后,完成各自的事务提交。

崩溃恢复

如果在同步过程中出现 Leader 节点宕机,会进入崩溃恢复阶段,重新进行 Leader 选举,崩溃恢复阶段还包含数据同步操作,同步集群中最新的数据,保持集群的数据一致性。

整个 ZooKeeper 集群的一致性保证就是在上面两个状态之前切换,当 Leader 服务正常时,就是正常的消息广播模式;当 Leader 不可用时,则进入崩溃恢复模式,崩溃恢复阶段会进行数据同步,完成以后,重新进入消息广播阶段。

数据同步

崩溃恢复完成选举以后,接下来的工作就是数据同步,在选举过程中,通过投票已经确认 Leader 节点是最大 Zxid 的节点,同步阶段就是利用 Leader 前一阶段获得的最新 Proposal 历史同步集群中所有的副本。

zxid

Zxid 是 Zab 协议的一个事务编号,Zxid 是一个 64 位的数字,其中低 32 位是一个简单的单调递增计数器,针对客户端每一个事务请求,计数器加 1;而高 32 位则代表 Leader 周期年代的编号。

每当有一个新的 Leader 选举出现时,就会从这个 Leader 服务器上取出其本地日志中最大事务的 Zxid,并从中读取 epoch 值,然后加 1,以此作为新的周期 ID。总结一下,高 32 位代表了每代 Leader 的唯一性,低 32 位则代表了每代 Leader 中事务的唯一性。

ZAB节点选举算法

Zab 中的节点有三种状态,伴随着的 Zab 不同阶段的转换,节点状态也在变化:

  • following

    当前节点是follower,遵从leader的命令

  • looking/eletion

    当前节点处于选举投票状态

  • leading

    当前节点是leader,负责协调和分配工作

选举算法流程如下:

1.各个节点变更状态,变更为 Looking

  • ZooKeeper 中除了 Leader 和 Follower,还有 Observer 节点,Observer 不参与选举, Leader 挂后,余下的 Follower 节点都会将自己的状态变更为 Looking,然后开始进入 Leader 选举过程。

2.各个 Server 节点都会发出一个投票,参与选举

  • 在第一次投票中,所有的 Server 都会投自己,然后各自将投票发送给集群中所有机器,在运行期间,每个服务器上的 Zxid 大概率不同。

3.集群接收来自各个服务器的投票,开始处理投票和选举

  • 处理投票的过程就是对比 Zxid 的过程,假定 Server3 的 Zxid 最大,Server1判断Server3可以成为 Leader,那么Server1就投票给Server3,判断的依据如下:首先选举 epoch 最大的,如果 epoch 相等,则选 zxid 最大的,若 epoch 和 zxid 都相等,则选择 server id 最大的,就是配置 zoo.cfg 中的 myid;在选举过程中,如果有节点获得超过半数的投票数,则会成为 Leader 节点,反之则重新投票选举。

zookeeper的读写操作

  • quorum 是zookeeper的一种投票方式,当发起proposal时,只要多数派同意,即可生效。多数派指的是,意思是至少过半的节点响应,才可以进行下面的操作。quorum数 = 节点数/2 +1
  • 为了保证事务的顺序一致性,ZooKeeper采用了递增的事务id号(zxid)来标识事务,所有提议(proposal)都有zxid
  • 每次事务的提交,必须符合quorum多数派
  • leader选举投票vote的信息结构为(sid,zxid),sid是节点的id,zxid是事务id。选举leader的规则是zxid大的server胜出,若zxid相等,sid大的胜出。zxid数值大,说明是最新更新。

zookeeper读操作

读操作比较简单,客户端与某个zookeeper服务建立session,从这个服务器读取数据,返回给客户端,最后关闭session。

zookeeper写操作

  1. 客户端向zookeeper集群写入数据,与一个follower建立Session连接,假设为follower01

  2. follower01将写请求转发给leader

  3. leader收到消息后,把本次写入操作,转化为事务proposal提案发送给每个follower,每个follower先记录下要本次写入操作

  4. 超过半数quorum(包括leader自己)发回反馈,则leader提交commit提案,leader执行写入操作

  5. leader通知所有follower,也commit提案,follower各自在本地写入

  6. follower01响应客户端

zookeeper如何处理“脑裂”

  1. 首先我们搞清楚,脑裂是什么?

脑裂简单来说,就是集群中出现了两个leader

  1. 是如何出现的?

网络通信故障,集群被分为了两部分。

假设我们有五个节点,其中三台可以正常通信,而另外两台因为网络原因,无法与别的机器通信,所以,整个集群被分割成了两部分。两部分同时进行leader选取,自然出现了两个leader。

  1. zookeeper是如何解决的?

前面有提到过,zookeeper提交的每次proposal,都至少需要过半的节点响应,操作才会进行下去。

当发生网络分区后,三台节点的leader,我们称之为leader1。而因为网络原因分割出去的两个节点,选举出来的leader,我们称之为leader2。

这时有两个客户端,c1和c2,c1请求leader1写入一个znode为1。c2请求leader2写入一个znode为2。

c1的请求,leader1向另外两个节点发出proposal,两个节点响应加上leader本身,quorum = 3,符合多数派原则,则操作生效,同步到另外两个节点。

c2的请求,leader2往另一个节点发出proposal,quorum = 2,不符合多数派原则,操作则不生效。

所以,因为网络原因导致的两个leader,只有一个操作会生效。

当网络修复后,leader1的zxid肯定比leader2大,leader2变为follower状态,leader1同步操作。
————————————————
转载自CSDN博主「甜_tian」的原创文章。
原文链接:https://blog.csdn.net/weixin_39033058/article/details/118222322

reference

  1. https://cloud.tencent.com/developer/article/1333864
  2. https://blog.csdn.net/liyiming2017/article/details/83035157
  3. https://segmentfault.com/a/1190000022683594
  4. https://www.cnblogs.com/zz-ksw/p/12786067.html
  5. https://blog.csdn.net/weixin_39033058/article/details/118222322
  6. https://cloud.tencent.com/developer/article/1050471

文章作者: growdu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 growdu !
  目录
分类导航
随笔2 AI27 算法1 计算机基础13 博客搭建7 ChatGPT2 集群63 计算机通信1 数据库34 数据库深入80 DPDK26 Docker11 Elasticsearch4 编辑工具4 FAQ1 Go Web1 hometown2 编程语言16 网络9 OPC1 Linux38 openGauss4 页面12 PostgreSQL54 程序员自我修养1 协议11 成长之路1 stock1 存储5 工具20 VPP18 视频作品1 Vue13 Web1 代码示例11 数据库15 BenchmarkSQL1 PostgreSQL 源码修炼之路14
最热文章
1
13 逻辑复制深入
数据库深入🔥 1570
2
0 Postgresql存储、索引及系统优化、主备切换
PostgreSQL🔥 1495
3
一文读懂openguass dcf网络模块
集群🔥 1420
4
逻辑复制源码分析
数据库深入🔥 1327
5
PostgreSQL 分区表:从一行 `PARTITION BY` 到路由热路径的全链路拆解
数据库🔥 1094
6
applyparallelworker.c 之 LA 端源码深度解析:Leader Apply Worker 的指挥中枢
数据库深入🔥 1082
7
PostgreSQL Background Worker 全解:从 `RegisterBackgroundWorker` 到逻辑复制 4 类 worker 的全生命周期
数据库🔥 1078
8
PostgreSQL的后台进程walsender分析 - 关系型数据库 - 亿速云
PostgreSQL🔥 1033
9
PostgreSQL 逻辑复制的监控:六张视图 + 一组可执行 SQL,把 publisher/subscriber 的速率与健康度彻底看透
数据库🔥 1032
10
PostgreSQL 逻辑复制支持 DDL 之后:DDL 与 DML 的时序难题(重点:分区表)
数据库🔥 999
11
reorderbuffer.c 源码深度解析:PostgreSQL 逻辑复制的"事务重组引擎
数据库深入🔥 953
12
PostgreSQL 内核开发:读取一张表的 9 步标准流程与缓存全景
数据库🔥 938
13
从 `postgres` 二进制到生产级守护 —— PostgreSQL 最外层模块与启动全流程拆解
数据库🔥 936
14
支持逻辑复制同步 DDL 适配 SQL Server 方案
数据库深入🔥 934
15
PostgreSQL 逻辑复制的 ReorderBuffer 与事务机制:从一行 WAL 到一致性变更流的全链路绑定
数据库🔥 913
16
DDL同步架构(美化版)
数据库深入🔥 908
17
PostgreSQL Latch 机制详解:从一行 SetLatch 到 epoll 的内核之旅
数据库🔥 871
18
pgbench 源码全解:一个 C 文件如何撑起 PostgreSQL 官方压测工具
数据库🔥 860
19
PostgreSQL libpq 机制与缓冲区详解
数据库🔥 850
20
PostgreSQL 逻辑复制 spill 文件深度剖析:从 `xid-*.spill` 到 TPC-C 的增长方程
数据库🔥 845