集群概论
Zookeeper 可以运行在集群中。
Zookeeper 集群包含三类成员:leader,follower,obverser。
leader 作为中心点处理对所有 Zookeeper 系统变更的请求,像是一个定序器,建立了所有对 Zookeeper 状态更新的顺序。 follower 接受 leader 发出的变更请求,同时对请求进行按序处理,保证数据一致。observer 为了系统的可扩展性而设计,不会参与系统的任何决策。
请求、事务、标识符
Zookeeper 服务器会在本地处理读取请求,对于写操作,则都转发给 leader,让 leader 处理写操作。因此,可以通过增加更多的服务器到集群中,处理更多的读请求。
写操作会导致数据的更新。请求表示源自于客户端发起的操作。数据的更新被称之为事务,包括了处理对应请求而改变 Zookeeper 状态所需要执行的步骤。
事务是数据更新的基本单位,必须要以原子的方式执行,同时要不被其他事务干扰。在 Zookeeper 中,不存在关系型数据库锁设计的回滚问题,而是确保事务的每一步操作互不干扰。
同时事务还具有幂等性,对同一个事务执行两次,得到的结果应该是一样的,前提是确保多个事务的执行顺序每次都是一样的。
当 leader 产生一个事务,就会给事务分配一个标识符,zxid。通过 zxid 对事务进行标识,follower 就可以按照 leader 指定的顺序在各个服务器中按序执行。
zxid 为一个 long 型整数,分为时间戳和计数器两部分,每个部分32位。
Leader 选举
Leader 的主要作用是将每一个写请求转化为一个事务,确保各个节点按序执行事务,从而保证各个节点数据一致性。
Leader 必须要被仲裁的法定数量的服务器认可才可以成为 Leader(否则就会出现脑裂问题)。
(总体上说)每个服务器启动之后都会进入 LOOKING 状态,开始选举一个 leader 或者查找已经存在的 leader。如果 leader 已经存在,其他服务器就会通知该服务器谁是 leader,与此同时,新的服务器会和 leader 建立连接,以确保自己的 leader 状态一致。如果每个服务器都处在 LOOKING 状态,服务器之间就会通信来选举 leader。
对于 leader 选举的消息,称之为 leader 选举通知消息,或简称为通知。
当一个服务器进入 LOOKING 状态,就会发送向集群中的每个服务器发送一个通知,包括该服务器的投票信息,投票中包含服务器标识符 sid 和最近执行的事务的 zxid 信息。
当一个服务器收到一个投票信息,该服务器会根据以下规则修改自己的投票信息:
- 如果对方的 zxid 比自己的 zxid 更大(其实主要是比较计数器部分,对方的数据更新),或者对方的 zxid 和自己的 zxid 相同,但对方的 sid 比自己的 sid 更大,则更新自己的投票信息为收到的投票信息。
- 如果不满足上述条件,那么就不会更新自己的投票信息。
当一个服务器接收到的仲裁数量的服务器发来的投票都一致时,就表示 leader 选举成功。被选举为 leader 的服务器行使 leader 的权利,其他变成 follower,并试图连接 leader。
选举最大的 zxid 的原因是为了防止遗漏事务。
值得一提的是,为了让选举尽可能的在一轮结束,每个服务器都将该消息的延迟设的很长(200ms),保证有充足的时间接收到其他节点的投票。
Zab
Zab 是 Zookeeper 中负责执行事务的协议。
假设当前有一个活动的 leader,并且有足够数量的 follower,通过该协议提交一个事务很简单,类似两阶段提交:
- Leader 向所有 follower 发送一个 proposal 消息 p。
- 当一个 follower 收到消息 p 后,会响应一个 ack 消息,通知 leader 其已经接受 proposal。
- 当收到仲裁数量的服务器发送的确认消息后,leader 就会发送消息通知 follower 进行提交。
Zab 保证了下面的几个重要属性:
- 如果 leader 按照顺序广播了事务 A,B。那么每个服务器在提交 B 之前必须保证 A 提交完成
- 如果某个服务器按照 A B 的顺序提交数据,那么其他服务器也是按照此顺序提交。
第一个属性保证了事务在任何一个服务器上的执行顺序都是一致的。第二个属性保证了服务器不会跳过任何的事务。
但是 Zookeeper 并不是始终都有一个活动的 leader,leader 服务器也可能崩溃,其他服务器需要选举一个新的 leader 保证系统整体仍然可用。
时间戳(有点像年号)的概念代表了管理权随着时间变化的情况。一个时间戳表示了这个服务器行使管理权的这段时间,在一个时间戳内,leader 会广播提案,并且根据计数器识别每一个消息。
时间戳的值每次随着选举的发生便会增加,同一个服务器成为 leader 之后可能持有不同的时间戳信息。
Zab 协议保证在新的时间戳的事务开始执行前,旧的时间戳的事务全部被提交。此外,Zab 协议保证同一时间点不会出现两个被仲裁支持的群首。
选举新的 leader 之后,在向 follower 同步事务时候有两种方式,一种是 follower 落后不太多时候,采用 DIFF 的方式,将新增的内容发过去。另一种是落后很多时候,把整个 SNAP 发送过去。
观察者
Observer 接收来自 leader 的消息并提交。不过不同于 follower,observer 并不参与 leader 选举。
引入 observer 的主要原因是提高读请求的可扩展性,通过加入多个观察者,可以在不牺牲写操作吞吐量的情况下服务更多的读操作。因为不参与投票等,所以不会引起仲裁数量的变化。
扫描二维码,分享此文章