1. ZooKeeper 集群


image.png

  • 可靠的 ZooKeeper 服务。
  • 只要集群的大多数都准备好了,就可以使用这项服务。
  • 容错集群设置至少需要三个服务器,强烈建议使用奇数个服务器。
  • 建议每个服务运行在单独的机器上。

    2. ZooKeeper 集群搭建


  1. tickTime=2000
  2. dataDir=/tmp/zookeeper
  3. clientPort=2181
  4. initLimit=10
  5. syncLimit=5
  6. server.1=zoo1.2888:3888
  7. server.2=zoo2.2888:3888
  8. server.3=zoo3.2888:3888
  • initLimit:集群中的 follower 服务器(F)与 leader 服务器(L)之间完成初始化同步连接时能容忍的最多心跳数(tickTime 的数量)。如果 zk 集群环境数量确实很大,同步数据的时间会很长,因此这种情况下可以适当调大该参数。
  • syncLimit:集群中的 follower 服务器与 leader 服务器之间请求和应答之间能容忍的最多心跳数(tickTime 的数量)。
  • 集群节点:server.id=host:port:port
    • id:通过在各自的 dataDir 目录下创建一个名为 myid 的文件来为每台机器赋予一个服务器 id。
    • 两个端口号:第一个跟随者用来连接到领导者,第二个用来选举领导者。
    • myid 文件:一行内容,只包含机器 id 的文本。id 在集群中必须是唯一的,其值应该在 1 到 255 之间。如服务器 1 的 id 为 “1”。

      3. 连接到 Zookeeper 集群


  • 集群的所有节点都可以提供服务,客户端连接时,连接串中可以指定多个或全部集群节点的连接地址。当一个节点不通时,客户端将自动切换另一个节点。
    "10.168.1.23:2181,10.168.1.24:2181,10.168.1.25:2181"
    

4. Zookeeper 集群监控


说明文档:http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_monitoring


image.png

  • Zookeeper 每个实例中保存的都是全量数据。作为重要的分布式协调服务,如何保证集群数据的一致性?

image.png

  • ZAB 协议(Zookeeper Atomic Broadcast,Zookeeper 原子广播协议)是专为 Zookeeper 设置的数据一致性协议。

    ZAB 协议过程说明

    image.png

  • 所有事务请求转发给 Leader。

  • Leader 分配全局单调递增事务 id(Zxid),广播事务提议。
  • Follower 处理提议,做出反馈。
  • Leader 收到过半数反馈,广播 Commit。
  • Leader 做出响应。

    ZAB 协议重要特性:有序性。

崩溃恢复

Leader 服务器出现崩溃,或者说因为网络原因导致 Leader 服务器丢失与过半 Follower 的联系,那么就会进入崩溃恢复模式。

  • ZAB 协议规定如果一个 Proposal 在一台机器上被处理成功,那么应该在所有的机器上都处理成功,哪怕机器出现故障崩溃。
  • ZAB 协议确保那些已经在 Leader 服务器上提交的事务最终被所有服务器都提交。
  • ZAB 协议确保丢弃那些只在 Leader 服务器上被提出的事务。
  • ZAB 协议需要设计的选举算法应该满足:
    • 确保提交已经被 Leader 提交的事务 Proposal,同时丢弃已经被跳过的事务 Proposal。
    • 如果让 Leader 选举算法能够保证新选举出来的 Leader 服务器拥有集群中所有机器最高的 ZXID 的事务 Proposal,那么就可以保证这个新选举出来的 Leader 一定具有所有已提交的提案。
    • 如果让具有最高编号事务 Proposal 的机器成为 Leader,就可以省去 Leader 服务器检查 Proposal 的提交和丢弃工作的这一步操作。

      数据同步

      Leader 选举出来后,需完成 Followers 和 Leader 的数据同步,当半数的 Followers 完成同步,则可以开始提供服务。

  • Leader 服务器会为每一个 Follower 服务器都准备一个队列,并将那些没有被各 Follower 服务器同步的事务以 Proposal 消息的形式逐个发送给 Follower 服务器,并在每一个 Proposal 消息后面紧接着再发送一个 Commit 消息,以表示该事务已经被提交。
  • Follower 将所有其尚未同步的事务 Proposal 都从 Leader 服务器上同步过来并成功应用到本地数据库中后,Leader 服务器就会将该 Follower 服务器加入到真正的可用的 Follower 列表中,并开始之后的其他流程。

    丢弃事务 Proposal 处理

  • 在 ZAB 协议的事务编号 ZXID 设计中,ZXID 是一个 64 位的数字。

    • 低 32 位是一个简单的单调递增的计数器,针对客户端的每一个事务请求,Leader 服务器在产生一个新的事务 Proposal 的时候,都会对该计数器进行 +1 操作。
    • 高 32 位代表 Leader 周期纪元的编号,每当选举产生一个新的 Leader 服务器的时候,就会从这个 Leader 服务器上取出其本地日志中最大事务 Proposal 的 ZXID,并从该 ZXID 中解析出对应的纪元值,然后对其进行 +1 操作,之后就会以此编号作为新的纪元,并将低 32 位置 0 来开始生成新的 ZXID。
    • 基于这样的策略,当一个包含了上一个 Leader 周期中尚未提交过的事务 Proposal 的服务器启动加入到集群中,发现此时集群中已经存在 Leader,将自身以 Follower 角色连接上 Leader 服务器之后,Leader 服务器会根据自己服务器上最后被提交的 Proposal 和 Follower 服务器的 Proposal 进行对比,发现 Follower 中有上一个 Leader 周期的事务 Proposal 时,Leader 会要求 Follower 进行一个回退操作(回退到一个确实已经被集群中过半机器提交的最新的事务 Proposal)。

      6. Zookeeper 集群 Leader 选举


image.png

  • 对选举算法的要求:
    • 选出的 Leader 节点上要持有最高的 zxid。
    • 过半数节点同意。
  • 内置实现的选举算法:

    • LeaderElection
    • FastLeaderElection(默认)
    • AuthFastLeaderElection

      Leader 选举机制概念

  • 服务器id myid(一个数字)

  • 事务id,服务器中存放的最大 zxid
  • 逻辑时钟,发起的投票轮数技术(比如第一轮发起,长时间没收到响应,会发起第二轮投票,此时如果收到第一轮投票结果,需要将结果丢弃)
  • 选举状态:

    • Looking:竞选状态。
    • Following:跟随状态,同步 leader 状态,参与投票。
    • Observing:观察状态,同步 leader 状态,不参与投票。
    • Leading:领导者状态。

      Leader 选举算法

  • 选举算法:

    • 每个服务实例均发起选举自己为领导者的投票(自己的投给自己);
    • 其他服务实例收到投票邀请时,比较发起者的数据事务 ID 是否比自己最新的事务 ID 大,大则给它投一票,小则不投票给它,相等则比较发起者的服务器 ID,大则投票给它;
    • 发起者收到大家的投票反馈后,看投票数(含自己的)是否大于集群的半数,大于则胜出,担任领导者;未超过半数且领导者未选出,则再次发起投票。
  • 胜出条件:投票赞成数大于半数则胜出的逻辑。

    Leader 选举示例说明

  • 有5台服务器,每台服务器均没有数据,它们的编号分别是1,2,3,4,5,按编号依次启动,它们的选举过程如下:

    • 服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于Looking。
    • 服务器2启动,给自己投票,同时与之前启动的服务器1交换结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是Looking
    • 服务器3启动,给自己投票,同时与之前启动的服务器1,2交换信息,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为领导者,服务器1,2成为小弟。
    • 服务器4启动,给自己投票,同时与之前启动的服务器1,2,3交换信息,尽管服务器4的编号大,但之前服务器3已经胜出,所以服务器4只能成为小弟。
    • 服务器5启动,后面的逻辑同服务器4成为小弟。

      7. Zookeeper 参数配置