Zookeeper

Zookeeper

一、zookeeper 入门

1.1 概述

zookeeper 是一个开源的分布式的,为分布式应用提供协调服务的Apache 项目。

主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。

简单来说zookeeper=文件系统+监听通知机制。

1.2 特点

在这里插入图片描述

  • zookeeper:一个领导者 (Leader),多个跟随者(Follower)组成的集群
  • 及群众只要半数以上的节点存活,zookeeper就能正常服务
  • 全局数据一致:每个server 保存一份相同的数据副本,client无论连接到那个server,数据都是一致的
  • 更新请求顺序进行,来子同一个client 的更新请求按其顺序依次执行
  • 数据更新的原子性,一次数据更新要么成功,要么失败
  • 实时性,在一定时间范围内,client 能读取到最新数据。
1.3 数据结构

Zookeeper 数据模型的结构与Unix文件系统很类似,整体上可以看做是一棵树,每个节点称作一个 Znode。每一个Znode 默认能够存储 1M的数据,每个Znode 都可以通过其路径唯一标识。

在这里插入图片描述

1.4 应用场景

提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。

  • 统一命名服务

在这里插入图片描述

  • 统一配置管理

在这里插入图片描述

  • 统一集群管理

在这里插入图片描述

  • 软负载均衡

在这里插入图片描述

1.5 下载地址

https://zookeeper.apache.org/

二、Zookeeper 安装

2.1 本地模式安装部署
  • 拷贝Zookeeper安装包到Linux系统下
  • 解压指定目录
tar -zxvf zookeeper-3.4.10.tar.gz
  • 将/zookeeper-3.4.10/conf这个路径下的zoo_sample.cfg修改为zoo.cfg;
mv zoo_sample.cfg zoo.cfg
  • 在/zookeeper-3.4.10/这个目录上创建zkData文件夹
mkdir zkData
  • 打开zoo.cfg文件,修改dataDir路径
dataDir=/opt/module/zookeeper-3.4.10/zkData
  • 启动 zookeeper
bin/zkServer.sh start
  • 查看进程是否启动
jps
  • 查看状态:
bin/zkServer.sh status
  • 启动客户端
bin/zkCli.sh
  • 退出客户端
quit
  • 停止Zookeeper
bin/zkServer.sh stop
2.2 配置参数解读

Zookeeper中的配置文件zoo.cfg中参数含义解读如下:

  • tickTime =2000:通信心跳数,Zookeeper服务器与客户端心跳时间,单位毫秒

Zookeeper使用的基本时间,服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个tickTime时间就会发送一个心跳,时间单位为毫秒。
它用于心跳机制,并且设置最小的session超时时间为两倍心跳时间。(session的最小超时时间是2*tickTime)

  • initLimit =10:LF初始通信时限

集群中的Follower跟随者服务器与Leader领导者服务器之间初始连接时能容忍的最多心跳数(tickTime的数量),用它来限定集群中的Zookeeper服务器连接到Leader的时限。

  • syncLimit =5:LF同步通信时限

集群中Leader与Follower之间的最大响应时间单位,假如响应超过syncLimit * tickTime,Leader认为Follwer死掉,从服务器列表中删除Follwer。

  • dataDir:数据文件目录+数据持久化路径

主要用于保存Zookeeper中的数据。

  • clientPort =2181:客户端连接端口

监听客户端连接的端口。

三、Zookeeper 内部原理

3.1 zookeeper 角色

Leader 角色

它是Zookeeper集群工作的核心,也是事务性请求(写操作)的唯一调度和处理者,它保证集群事务处理的顺序性,同时负责进行投票的发起和决议,以及更新系统状态。

Follower

它负责处理客户端的非事务(读操作)请求,如果接收到客户端发来的事务性请求,则会转发给Leader,让Leader进行处理,同时还负责在Leader选举过程中参与投票。

Observer

它负责观察Zookeeper集群的最新状态的变化,并且将这些状态进行同步。对于非事务性请求可以进行独立处理;对于事务性请求,则会转发给Leader服务器进行处理。它不会参与任何形式的投票,只提供非事务性的服务,通常用于在不影响集群事务处理能力的前提下,提升集群的非事务处理能力(提高集群读的能力,也降低了集群选主的复杂程度)。

3.2 zookeeper 选举机制
  • 半数机制:集群中半数以上机器存活,集群可用。所以Zookeeper适合安装奇数台服务器。
  • Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内部的选举机制临时产生的。
  • 以一个简单的例子来说明整个选举的过程。
    假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动,来看看会发生什么,如下图所示。

在这里插入图片描述

  • 服务器1启动,此时只有它一台服务器启动了,它发出去的报文没有任何响应,所以它的选举状态一直是LOOKING状态。
  • 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1、2还是继续保持LOOKING状态。
  • 服务器3启动,根据前面的理论分析,服务器3成为服务器1、2、3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的Leader。
  • 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1、2、3、4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了。
  • 服务器5启动,同4一样当小弟。
3.3 节点类型

持久(Persistent):客户端与服务端断开连接后,创建的节点不删除
临时(Ephemeral):客户端与服务端断开连接后,创建的节点自己删除

节点类型有

  • 普通持久节点:客户端与服务端断开连接后,该节点依旧存在。
  • 持久有序节点:客户端与服务端断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号。
  • 普通临时节点:客户端与服务端断开连接后,该节点被删除。
  • 临时有序节点:客户端与服务端断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号。
3.4 zookeeper 的 ZAB 协议

ZAB (Zookeeper Atomic Broadcast) 协议是为分布式协调服务 Zookeeper 专门设计的一种支持崩溃恢复的原子广播协议。
在 Zookeeper 中,主要依赖 ZAB协议实现分布式数据一致性,基于该协议,Zookeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间数据的一致性

ZAB的协议核心是在整个zookeeper集群中只有一个节点即Leader将客户端的写操作转化为事物(或提议proposal)。Leader节点再数据写完之后,将向所有的follower节点发送数据广播请求(或数据复制),等待所有的follower节点反馈。在ZAB协议中,只要超过半数follower节点反馈OK,Leader节点就会向所有的follower服务器发送commit消息。即将leader节点上的数据同步到follower节点之上。

在这里插入图片描述

  • ZAB 协议介绍

    ZAB 协议包括两种基本模式,崩溃恢复和消息广播

    崩溃恢复:当整个集群在启动或者当 leader 节点出现网络中断、崩溃等情况时,ZAB 协议就会进入恢复模式并选举产生新的 leader,当 leader 服务器选举出来后并且集群中有过半的机器和该 leader 节点完成数据同步(用来保证集群中过半的机器能够和 leader 服务器的数据状态保持一致)后,ZAB 协议就会退出恢复模式。

    简单地说,就是 leader 挂了,然后需要选举出新的 leader(ZK是有中心化节点的中间件),完成新 leader 和 follower 和 observer 的数据同步。

    消息广播:当集群中已经有过半的 follower 节点完成了和 leader 状态同步以后,那么整个集群就进入了消息广播模式。这个时候 leader 节点正常工作,如果启动一台新的服务器加入到集群,那这个服务器会直接进入数据恢复模式,和 leader 节点进行数据同步。同步完成后即可正常对外提供非事务请求的处理。

    注意:leader 节点可以处理事务请求和非事务请求,follower 节点只能处理非事务请求,如果 follower 节点接收到事务请求,会把这个请求转发给 leader 服务器。

  • 消息广播原理(zxid)

    消息广播的过程实际上就是一个简化版本的二阶段提交(2PC)提交过程,但是却又不同。二阶段提交的要求协调者必须等到所有的参与者全部反馈ACK确认消息后,再发送commit消息。要求所有的参与者要么全部成功要么全部失败。二阶段提交会产生严重阻塞问题。
    ZAB协议中Leader等待follower的ACK反馈是指”只要半数以上的follower成功反馈即可,不需要收到全部follower反馈”
    在这里插入图片描述

    • leader 接收到消息请求后,将消息赋予一个全局唯一的64 位自增 id(叫:zxid),通过 zxid 的大小比较既可以实现因果有序这个特征。
    • leader 为每个 follower 准备了一个 FIFO 队列(通过 TCP协议来实现,以实现了全局有序这一个特点)将带有 zxid的消息作为一个提案(proposal)分发给所有的 follower。
    • 当 follower 接收到 proposal,先把 proposal 写到磁盘,写入成功以后再向 leader 回复一个 ack。
    • 当 leader 接收到合法数量(超过半数节点)的 ACK 后,leader 就会向这些 follower 发送 commit 命令,同时会在本地执行该消息。
    • 当 follower 收到消息的 commit 命令以后会提交该消息。

    注意leader 的投票过程,不需要 Observer 的 ack,也就是 Observer 不需要参与投票过程,但是 Observer 必须要同步 Leader 的数据从而在处理请求的时候保证数据的一致性,用来实现提升读性能

  • 崩溃恢复的实现原理

    前面我们已经清楚了 ZAB 协议中的消息广播过程,ZAB 协议的这个基于原子广播协议的消息广播过程,在正常情况下是没有任何问题的,但是一旦 leader 节点崩溃或者由于网络问题导致 leader 服务器失去了过半的 follower 节点的联系(leader 失去与过半 follower 节点联系,可能是 leader 节点和 follower 节点之间产生了网络分区,那么此时的 leader 不再是合法的 leader 了),那么就会进入到崩溃恢复模式。崩溃恢复状态下 zab 协议需要做两件事:1. 选举出新的 leader;2. 数据同步;

    ZAB 协议中的崩溃恢复需要保证,如果一个事务 Proposal 在一台机器上被处理成功,那么这个事务应该在所有机器上都被处理成功,哪怕是出现故障。为了达到这个目的,我们先来设想一下,在 zookeeper 中会有哪些场景导致数据不一致性,以及针对这个场景zab 协议中的崩溃恢复应该怎么处理。

    • 已经被处理的消息不能丢:当 leader 收到合法数量 follower 的 acks 后,就向各个 follower 广播 COMMIT 命令,同时也会在本地执行 COMMIT 并向连接的客户端返回 acks 。但是如果在各个 follower 在收到 COMMIT 命令前 leader 就挂了,导致剩下的服务器并没有执行都这条消息。即 leader 在发 commit 命令前挂了(此时 follower 已经将该消息存入本地,只是没有 commit ),导致 follower 没有收到这条已经被 leader 处理的消息。

    • 被丢弃的消息不能再次出现:当 leader 接收到消息请求生成 proposal 后就挂了,其他 follower 并没有收到此 proposal,因此经过恢复模式重新选了 leader 后,这条消息是被跳过的。 此时之前挂了的 leader 重新启动并注册成了 follower,他保留了被跳过消息的proposal 状态,与整个系统的状态是不一致的,需要将其删除。

      ZAB 协议需要满足上面两种情况,就必须要设计一个 leader 选举算法:能够确保已经被 leader 提交的事务 Proposal 能够提交、同时丢弃已经被跳过的事务 Proposal。

    • 如果 leader 选举算法能够保证新选举出来的 Leader 服务器拥有集群中所有机器最高编号(ZXID 最大)的事务 Proposal,那么就可以保证这个新选举出来的 Leader 一定具有已经提交的提案。因为所有提案被 COMMIT 之前必须有超过半数的 follower ACK,即必须有超过半数节点的服务器的事务日志上有该提案的 proposal,因此,只要有合法数量的节点正常工作,就必然有一个节点保存了所有被 COMMIT 消息的 proposal 状态

    • zxid 是 64 位,高 32 位是 epoch 编号,每经过一次 Leader 选举产生一个新的 leader,新的 leader 会将 epoch 号+1,低 32 位是消息计数器,每接收到一条消息这个值+1,新 leader 选举后这个值重置为 0,这样设计的好处在于老的 leader 挂了以后重启,它不会被选举为 leader,因此此时它的 zxid 肯定小于当前新的 leader。当老的 leader 作为 follower 接入新的 leader 后,新的 leader 会让它将所有的拥有旧的 epoch 号的未被 COMMIT 的 proposal 清除。

      选主:leader选举是zk中最重要的技术之一,也是保证分布式数据一致性的关键所在。当集群中的一台服务器处于如下两种情况之一时,就会进入leader选举阶段——服务器初始化启动、服务器运行期间无法与leader保持连接。 选举阶段,集群间互传的消息称为投票,投票Vote主要包括二个维度的信息:ID、ZXID

    • ID:被推举的leader的服务器ID,集群中的每个zk节点启动前就要配置好这个全局唯一的ID。

    • ZXID:被推举的leader的事务ID ,该值是从机器DataTree内存中取的,即事务已经在机器上被commit过了。

      节点进入选举阶段后的大体执行逻辑如下:

    • 设置状态为LOOKING,初始化内部投票Vote (id,zxid) 数据至内存,并将其广播到集群其它节点。节点首次投票都是选举自己作为leader,将自身的服务ID、处理的最近一个事务请求的ZXID(ZXID是从内存数据库里取的,即该节点最近一个完成commit的事务id)及当前状态广播出去。然后进入循环等待及处理其它节点的投票信息的流程中。

    • 循环等待流程中,节点每收到一个外部的Vote信息,都需要将其与自己内存Vote数据进行PK,规则为取ZXID大的,若ZXID相等,则取ID大的那个投票。若外部投票胜选,节点需要将该选票覆盖之前的内存Vote数据,并再次广播出去;同时还要统计是否有过半的赞同者与新的内存投票数据一致,无则继续循环等待新的投票,有则需要判断leader是否在赞同者之中,在则退出循环,选举结束后根据选举结果及各自角色切换状态,leader切换成LEADING、follower切换到FOLLOWING、observer切换到OBSERVING状态。
      在这里插入图片描述

  • ZAB 协议原理

    • ZAB协议要求每个leader都要经历三个阶段,即发现,同步,广播。
    • 发现:即要求zookeeper集群必须选择出一个leader进程,同时leader会维护一个follower可用列表。将来客户端可以在follower中的节点进行通信。
    • 同步:leader要负责将本身的数据与follower完成同步,做到多副本存储。这样也是体现了CAP中高可用和分区容错。follower将队列中未处理完的请求消费完成后,写入本地事物日志中。
    • 广播:leader可以接受客户端新的proposal请求,将新的proposal请求广播给所有的follower。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_子栖_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值