Quorum
['kwɔrəm]
• 写入数据的时候,要求W个节点确认收到
• 读取数据的时候,读取R个节点,获取最新数据版本
• W + R > N(总节点数)则称为Quorum
Zookeeper
ZAB: Zookeeper Atomic Broadcast
• 读的时候,读任意1个节点
• 写的时候,leader处理,过半数节点确认;类似两阶段提交
– 收到客户端写请求,如果自己是follower,转发给leader
– Leader收到写请求,转换为事务,广播该事务
– 各节点收到事务广播,写入事务日志并返回确认
– Leader收到多数节点确认,广播COMMIT消息;未收到多数节点确认,补发事务Proposal
– 各节点收到commit消息,该事物更新到内存的DataTree数据结构中
Zookeeper
ZAB: Zookeeper Atomic Broadcast
Zookeeper
ZAB: Zookeeper Atomic Broadcast
• 为什么称为原子广播协议?
– Proposal具有幂等性(即原子性),重复发送无影响
– Proposal中的事务包含的是znode的最终状态,而不是操作命令
– 每个Proposal有zxid,顺序递增由leader产生,保证follower能按leader的处理顺序进行处理
– 每次读或写znode的数据,只能全部读取或全部覆盖
• Leader发送proposal、commit的时候也会发送给自己
• Leader自己commit完成后向客户端返回处理结果
Zookeeper
故障处理
• 已经向client返回处理结果,此时leader故障
– Follower与leader连接断开,达到阈值发起选举
– 过半数节点正常,选举方能成功
– 选举的节点是zxid最大的,myid文件内容最大的
– 新leader根据snapshot和事务日志恢复数据,同步至follower
• 未向client返回处理结果
– client应查询一下leader,判断是否成功;也可查询任意follower,可能不一致,但最终一致
– 如果leader故障,等待新leader产生
Zookeeper
故障处理
• 选举出新leader,老leader恢复
– 老leader发起选举,发现有其他节点zxid比自己大,且已经有leader,于是成为follower,加入现集群
– 老leader发送最大zxid给新leader,新leader据此要求其丢弃部分数据(可能有没发送给follower的proposal),并重新发送故障期间的新事物
Zookeeper
FastLeaderElection选举(选举算法可在zoo.cfg中配置)
• 逻辑时钟clock表示第几轮选举,重启时为0,选举时加1
• 启动时处于looking状态
– 先选自己,选票为“clock(1)、 looking、zxid、myid”
– 广播选票,收到其他节点选票
– 如果其他节点选票的clock大,更新自己的clock;其他节点zxid大,或zxid相等但myid大,则更新自己选票的相应值为该节点值,表示选举该节点;
– 重新发出选票
• 收到选票时,判断当前的选票是否过半数选举同一节点;满足条件时结束选举
Zookeeper
zxid说明:为什么zxid不会重复,如何保证顺序递增
• ZooKeeper Transaction Id
• zxid为8字节64位
– 高32位表示逻辑时钟,初始为0,称为epoch
– 低32位表示事务顺序号,初始为0,每次事务加1
• 选举新leader后
– 新leader的zxid一定是最大的
– 新leader不会继续原来的zxid
– 高32位加1,低32位置0,将新的epoch通知follower
Zookeeper
hierarchical quorums跨数据中心
• 每个group有3个机器
– group.1=1:2:3 group.2=4:5:6 group.3=7:8:9
• 每个机器默认权重为1,可修改
– weight.1=1
• 过半数的group正常即可选举或ZAB时commit;
• group中,正常的server加权求和,结果大于该group所有server加权求和,认定该group正常
• 如果3个group分别部署在3个数据中心,可容忍1个DC完全挂掉
Zookeeper
总结
• 可用性:3节点容忍1故障;5节点容忍2故障
• 一致性:写多数节点,读1节点,leader、follower可能短暂不一致,但最终一致
• 网络分区容忍性:网络分区不会导致数据出错,但多数节点仍联通时才能服务(否则也可处理只读操作)
• 适用场景:
– 读写比大于2,读多写少(因为写操作全部在leader上)
– 不适用大数据存储(znode只能全部读取或覆盖,znode数据必须小于1M),需要正常副本过半数
Quorum及其在Zookeeper中的演变 到此结束~~
后面是在Kafka中的应用
Kafka 0.10
来自Microsoft的PacificA协议
• 场景:高吞吐量,高可用性,高性能,大数据
• W + R > N性能不高,修改后的协议读写都在leader,多个分区leader共同承担读写请求:
– R = 1,W = 1(可丢数据)
– R = 1,W = N1 < N(N1为正常的副本)(不丢数据,除非所有副本都故障)
– 正常(in-sync)的条件:和zookeeper的会话没有断开(通过定时的心跳消息),如果是follower,则不能落后leader太多。落后多久算太久是通过参数“replica.lag.time.max.ms”控制的。leader会根据这俩条件跟踪in-sync的follower
Kafka 0.10
Kafka概述
• 每个topic分为多个分区
• 每个分区可有多个副本
• 同一分区副本通常不在同一broker上;leader故障,in-sync的副本成为leader;无in-sync的副本,选举最新数据的副本
• Broker:一个java进程,Kafka在服务器的唯一进程
– replica.lag.time.max.ms超过此时间未与leader同步为不正常副本
– min.insync.replicas最少需要多少个正常的副本才接受写请求
– log.segment.bytes一个单独的文件存储多少字节的消息
– message.max.bytes每个消息最大多少字节
Kafka 0.10
Kafka概述
• 消息在生产者发出的时候,broker存储、消费者消费的时候,都是同样的二进制格式,无需任何转换,性能更高
• Producer生产者配置
– acks:0-放入本地OS缓冲区后返回;1-leader处理后返回客户端;all-所有in-sync的副本都确认收到消息后才返回客户端
– compression消息压缩格式
– 可使用sync或async的producer
– batch.size达到多少字节才批量发送消息,async时有效
• 不建议使用fsync,网络完全可以比普通磁盘快
Kafka 0.10
Kafka概述
• 消费者采用pull模式,能按自己的能力尽最大努力处理消息
• 每次取一批消息,然后再处理;每个分区只能被一个消费者消费
• 取消息时,按offset取,服务端无需维护客户端状态,且可回溯
• Consumer消费者配置
– fetch.min.size:至少取多少字节消息,如果消息没有这么多,服务器阻塞等待
– fetch.mat.wait.ms:消息不足fetch.min.size,服务器最多阻塞多久
– max.partition.fetch.bytes:每个partition服务器最多返回多少字节数据,但如果第一条消息大于此值仍会返回
– fetch.max.bytes:服务器总的最多返回多少字节数据,但如果第一条消息大小大于此值仍会返回
Kafka
总结
• 可用性:只要有1节点正常即可
• 一致性:
– 读写都在leader,完全一致;其他副本为特殊的消费者
– 发送消息时使用acks=all则leader故障后也一致
– 所有正常副本都收到特定消息后才可能被消费者消费到
• 网络分区容忍性:
– 网络分区不会导致partition出现多个leader的情况,因为使用了Zookeeper做协调
– 网络分区可能导致部分partition可用、部分不可用
Kafka
总结
• 高可用:只要有1节点正常即可
• 高吞吐量:
– 生产者可批量发送消息;消费者批量取消息后消费
• 高性能:
– 消息格式在producer、consumer、broker保持一致
– sendfile减少文件内容copy次数,上下文切换次数
– broker顺序写,顺序读,segment设计避免扫描大文件
• 大数据:
– 依靠分区将数据分布到不同节点处理
– 只需1节点即可使用避免Quorum重复存储大量数据
2017年3月29日