跳转至

Zookeeper

简单介绍一下zookeeper

Zookeeper是一个开源的分布式的用于为分布式应用提供协调服务的Apache项目(主要基于文件系统+通知机制)

※为什么要用zk?

  1. 统一命名服务:在分布式环境下,经常需要对服务进行统一命名,便于识别,例如ip地址
  2. 统一配置管理在一个集群中,要求所有节点的配置信息是一致
  3. 统一集群管理:在一个集群中,需要实时监控每个节点的状态变化
  4. 负载均衡在zookeeper中记录每台服务器的访问数,再次请求的时候,让访问最少的服务器去处理当前请求

※zk的数据持久化是怎么做的

  • zk中的数据是保存在节点上的,节点就是znode,多个znode之间构成一棵树的目录结构zk的数据是运行在内存中,zk提供了两种持久化机制
  • 事务日志(保存执行命令):zk把执行的命令以日志形式保存在dataLogDir指定的路径中的文件中(如果没有指定dataLogDir,则按照 dataDir指定的路径)
  • 数据快照(保存机器状态):zk会在一定的时间间隔内做一次内存数据快照,把当前时刻的内存数据保存在快照文件中
  • zk通过两种形式的持久化,在恢复时先恢复快照文件中的数据到内存中,再用日志文件中的数据做增量恢复,这样恢复的速度更快

※※※zk的选举机制

  • zookeeper的选举原则

  • zxid(事务ID)优先原则

  • 若节点有历史数据(zxid > 0),则zxid最大的节点直接成为Leader(无论myid大小)。
  • 若所有节点的zxid相同(如全新集群),则进入myid比较阶段。
  • 半数投票原则
  • Leader必须获得超过半数节点的投票(n/2 +1)才能正式成为Leader。

zookeeper第一次启动myid最大的节点会优先成为Leader,且遵循半数投票原则

  1. 假设有3台服务器,服务器1先启动,此时只有它一台服务器启动了,没有任何服务器可以进行通信,因此处于Looking状态
  2. 紧接着服务器2启动,它就会和1进行通信,交换选举结果,此时id较大的2胜出
  3. 此时也满足半数以上的服务器同意选举2,所以2就成为了leader
  4. 最后服务器3启动,虽然自己的id大一些,但是前面已经选出了leader,因此自己就成为了follower
  5. 如果2号机挂机,则按照前面逻辑处理,3号机就是leader,即便2号机恢复也只能是成为follower

zookeeper启动的时候存在旧数据:先比较zxid,当zxid相同时,才比较myid并进行半数投票

  1. 假设服务器3曾处理过事务,zxid=100,服务器1、2为全新节点,zxid=0
  2. 服务器1启动,进入Looking状态
  3. 服务器2启动,发现服务器1的zxid=0,开始比较myid(2 > 1),服务器2暂时成为Leader
  4. 服务器3启动,广播zxid=100
  5. 服务器1、2发现服务器3的zxid更大,立即放弃竞争,投票给服务器3
  6. 服务器3获得3票(超过半数),成为Leader

※zookeeper有三种角色之间的功能与区别

zookeeper中有三种角色:老大Leader(领导者) 、老二Follower (跟随者) 、老三Observer(观察者),其中,Follower和Observer归类为Learner(学习者),按重要性排序是Leader > Follower > Observer

  • Leader

Leader在集群中只有一个节点,是集群中心,负责协调集群中其他节点。从性能的角度考虑,leader可以选择不接受客户端的连接。

  1. 发起与提交写请求。所有的跟随者Follower与观察者Observer节点的写请求都会转交给领导者Leader执行。Leader接受到一个写请求后,首先会发送给所有的Follower,统计Follower写入成功的数量。当有超过半数的Follower写入成功后,Leader就会认为这个写请求提交成功,通知所有的Follower commit这个写操作,保证事后哪怕是集群崩溃恢复或者重启,这个写操作也不会丢失。
  2. 与learner保持心跳
  3. 崩溃恢复时负责恢复数据以及同步数据到Learner(以Follower为主)

  4. Follower

Follower在集群中有多个

  1. 与Leader保持心跳连接
  2. 当Leader挂了的时候,经过投票后成为新的leader

Leader的重新选举是由Follower们内部投票决定的。

  1. 向leader发送消息与请求
  2. 处理leader发来的消息与请求

  3. Observer

Observer是zookeeper集群中最边缘的存在

  1. 主要作用是提高zookeeper集群的读性能。由于zookeeper的一个写操作是要经过半数以上的Follower确认才能够写成功的。那么当zookeeper集群中的节点越多时,zookeeper的写性能就越差。而Observer角色可以实现在提高zookeeper读性能(也就是支持更多的客户端连接)的同时又不影响zookeeper的写性能
  2. 与Leader同步数据
  3. 不参与leader选举,也不参与写操作的提议过程
  4. 数据不持久化到硬盘,只将数据加载到内存

※※※※zab协议和raft协议的区别以及zookeeper基于什么协议

  • zookeeper基于zab协议
Raft协议 Zab协议
一致性模型 Leader-Follower模型 Leader-Follower模型
一致性强度 Raft协议保证一旦大多数Follower确认,日志条目就被标记为已提交,确保了强一致性 Zab协议在提交事务时,只需要得到Quorum的确认,因此保证的是弱一致性
选举条件 在Raft中,如果 Follower 在一段时间内没有收到 Leader 的心跳信息,就会主动进入候选人状态并启动新一轮选举,原因可能只是 Leader 节点繁忙而无法及时响应等情况 在Zab中除了系统启动时,只有等到 Leader 故障,无法提供服务时才会进行选举
Raft更偏向于积极选举,只要有可能就尝试选举新的领导者,而ZAB更倾向于保持现状,只有在确定领导者无法提供服务时才触发选举
投票规则 Raft 中,每个节点只能投票一次,并且投票给第一个请求投票的候选人 Zab中,节点可能会改变自己的投票,投给 zxid 更大的节点。所以 Zab 不存在随机超时时间,虽然第一票都会投给自己,但后续如果决定其他节点的 zxid 更大,就修改自己的选票
票数要求 在Raft 中,候选人在获得超过半数的投票后成为 Leader 在 Zab 中,新的领导者被选出后,还需要得到超过半数的节点的确认才能开始工作
决定因素 在Raft中,选举过程严格按照轮次进行,每轮选举只能选出一位Leader,选出 Leader 很大程度取决于随机的超时时间和日志最新 在 Zab 中,选举的结果主要取决于节点的 zxid 以及节点编号。zxid最大的节点通常是最近处理过事务,数据最新的节点
日志复制机制 Raft协议将每个节点的日志直接复制到其他节点,降低了中心化的压力 Zab协议将每个节点的事务日志存储在Leader节点中,然后通过Leader节点进行复制
可扩展性 Raft协议可以通过水平扩展来增加整个系统的容量和性能 Zab协议的可扩展性受限于Leader节点的性能

※paxos 算法

paxos 算法是一种基于消息传递具有高度容错特性一致性算法,用来解决分布式系统的数据一致性的问题

paxos系统中将所有节点划分为proposer(提议者),acceptor(接收者),learner(学习者)

paxos 算法主要分为三个阶段:

  1. prepare 准备阶段:首先 proposer 向多个 acceptor 发出 propose 请求 (proposer 生成全局唯一且递增proposal id没有携带提案内容),然后acceptor 针对收到的请求进行promise承诺
  2. accept 接收阶段:proposer收到过半数acceptor 的promise 承诺后, 再向acceptor 发出propose 请求,然后acceptor 针对收到的请求进行accept 处理
  3. learn学习阶段:proposer将通过的决议发送给所有learner(服从proposer)

※※※Zab协议

img

zab协议借鉴了paxos算法,是专门为zookeeper设计的支持崩溃恢复的原子广播协议

  • 消息广播

paxos算法中采用多个提案者会存在竞争acceptor的问题,于是zab协议就只采用了一个提案者。zookeeper 的一致性就是基于 zab 协议实现的,即只允许一个leader作为proposer发起提案

它包括两种基本的工作模式:正常和异常

  • 正常模式

  • 首先客户端Client向leader 发送写操作请求

  • 紧接着 leader 将客户端的请求转换为事务proposal 提案,同时为每个proposal分配一个全局唯一的zxid
  • 然后leader 会为每个follower(作为Accepter)分配一个单独的队列,将需要广播的 proposal 依次放到队列中,并且根据先进先出的策略向follower发送提案
  • 【两阶段提交:ACK】当follower接收到proposal提案之后,会首先写入本地磁盘中, 写入成功后向leader响应ack
  • 【两阶段提交:Commit】当leader接收到半数以上(Quorum)的服务器的ack响应之后,即认为提案发送成功,可以发送commit消息
  • 【两阶段提交:Commit】然后leader就会向所有follower广播 commit 消息,同时自身也会进行事务提交,所有follower 接收到后,就会进行事务提交

  • 崩溃恢复模式

  • leader发起事务提案之后就宕机了,此时follower还没有收到提案

  • leader 收到半数的ack以后,还没来得及发送commit消息就宕机了

那么这时候就涉及到leader选举数据恢复两个过程

  1. leader选举

  2. 所有节点(除了Observer不参与投票)均可作为Proposer发起选举提案,同时也作为Accpeter收集其他节点的提案并进行投票,选举出zxid最大或myid最大的节点为Leader。

  3. 新的leader必须满足两个条件
  4. 第一,新的leader必须是已经提交了 proposal 的 follower 节点
  5. 第二,新的leader 节点含有最大的zxid(其次才是最大的myid)

  6. 数据恢复

在新的leader选举之后,在正式工作开始之前,leader会确认所有的 proposal 是否已经被集群中过半的服务器提交,同时等到follower将所有尚未同步的提案都从 leader 上同步过,并且应用到内存数据中以后,leader 才会把该follower 加入到真正可用的follower列表中。

※※简述什么是 CAP 理论,zookeeper 满足 CAP的哪两个

C表示Consitency(一致性,也就是从每个节点读取的数据是一样的),A表示Avaliablity(可用性,也就是整个系统一直处于可用的状态),P表示Partition tolerance(分区容错性,分布式系统在任何网络分区故障问题的时候,仍然能正常工作)

对于一个分布式系统来说的话,最多只能满足其中的两项,并且满足P是必须的,所以往往选择就在CP或者AP中。而zookeeper就是满足了一致性和分区容错性(CP),因为leader节点挂掉的时候,集群会重新选举出leader,在这个期间集群是不满足可用性的

  • 为什么只能满足其中的两项?

比如说两个机器之间的数据同步出现了问题,如果想要保证可用性,那么不管数据的一致性,继续提供服务就可以了;如果想要保证一致性,那么就需要等待一段时间进行数据恢复,在 这个期间,集群是不满足可用性的 ,所以一个分布式系统要么满足AP,要么满足CP 。

※※zookeeper 集群的节点数为什么建议奇数台 (zk机房扩容有什么要注意的吗)

zookeeper集群的节点数量应为奇数:因为根据paxos理论,只有集群中超过半数的节点还存活才能保证集群的一致性

  1. 因为zookeeper 中有一个半数可用机制。集群中只要有半数以上的 机器正常工作,那么整个集群对外就是可用的。比如说如果有2个zookeeper, 那么只要1个死了zookeeper就不能用了,因为1没有过半,那么zookeeper 的死亡容忍度为0,同理,如果有3个zookeeper,如果死了1个,还剩2个 正常,还是过半的,所以zookeeper 的死亡容忍度为 1,而2n和2n-1的容忍度是一样 的,所以为了节约资源,就选择奇数台
  2. 防止因为集群脑裂造成集群用不了。比如有4个节点,脑裂为2个小集群, 都为2个节点,这时候,不能满足半数以上的机器正常工作,因此集群就不可用了,那么当有5个节点的时候,脑裂为2个小集群,分别为2和3,这 时候3这个小集群仍然可以选举出leader,因此集群还是可用的

评论