Midjourney操作界面

Apache BookKeeper核心技术解析:高可用读写协议、类结构与容错设计

4.8
0热度

在分布式系统中,数据的高可用性与一致性是核心挑战。Apache BookKeeper作为高性能、强一致的分布式日志存储系统,通过独特的读写协议、灵活的类结构设计以及高效的容错机制,为这一问题提供了可靠的解决方案。  本文将从三个维度剖析BookKeeper的设计精髓:  1. 读写协议:基于Quorum机制实现副本管理,结合动态的 Ensemble 策略提升吞吐,并通过 lastAddCo

在分布式系统中,数据的高可用性与一致性是核心挑战。Apache BookKeeper作为高性能、强一致的分布式日志存储系统,通过独特的读写协议、灵活的类结构设计以及高效的容错机制,为这一问题提供了可靠的解决方案。  

本文将从三个维度剖析BookKeeper的设计精髓:  

1. 读写协议:基于Quorum机制实现副本管理,结合动态的 Ensemble 策略提升吞吐,并通过 lastAddConfirmed 标志与 Fencing 机制确保数据可见性;  

2. 类结构设计:以 LedgerHandler 为核心,通过异步写入队列、多副本回调机制及连接池共享,实现高并发与资源优化;  

3. 容错设计:针对客户端与Bookie节点的故障场景,设计快速重配、数据恢复等策略,保障系统持续可用。  

通过解析这些设计细节,读者将深入理解BookKeeper如何平衡性能、一致性与容错能力,为构建可靠分布式存储系统提供实践参考。

一、读写协议

BookKeeper 的副本机制是在客户端上实现的。写数据时,客户端会并行往多个 Bookie 节点写入数据,读数据时也可以并行向多个副本所在节点发送读请求。

BookKeeper 数据读写采用类似 Quorum 的机制,Quorum机制是一种基于“抽屉原理”的副本管理机制。它通过对更新操作和读操作进行折衷,实现了数据在多个副本之间的一致性和可用性。在Quorum机制中,假设有N个副本,更新操作wi在W个副本中更新成功之后,才认为此次更新操作wi成功。对于读操作而言,至少需要读R个副本才能读到此次更新的数据。其中,W+R>N,即W和R有重叠。一般情况下,W+R=N+1。

BookKeeper 中引入了 ensemble 的概念,ensemble 表示数据要分布的 Bookie 节点数。好处是可以将 ledger 中的数据写到更多的 Bookie 节点上,以提升吞吐能力。假如 E>Qw(数据的副本数),数据就是条带状分布的,如下图右侧所示:

在这里插入图片描述

BookKeeper 使用一致性算法计算出 entryId 所有副本所在的 Bookie

第w个副本所在的Bookie索引,只要保证 ensemble 是个有序的 List,就能根据索引确定副本所在的 Bookie 节点(entryId + w) % ensembleSize

BookKeeper 的一致性协议里,有个 lastAddConfirmed 的标志位,lastAddConfirmed 之前的数据是已经满足 ackQuorum 的,可以被读取。假如客户端(Writer)挂了,会有一个 Fencing 过程,将 lastAddConfirmed 移动到最后,以确保最后的数据可以被读取。

在这里插入图片描述


二、类结构设计

LedgerHandler 封装了 ledger 的读写方法。一个 LedgerHandler 对应着一个 ledger 文件,LedgerHandler 随着 Ledger 的创建而创建,ledger关闭时对应的 LedgerHandler 对象也会回收。

Ledger的写操作是异步执行的,写入结果是顺序回调通知客户端的。使用一个 pendingAddOps 队列,保存了待完成的写入操作。

entryId 也是在客户端 LedgerHandler 中生成的,每个 Ledger 文件,同一时刻只能有一个客户端负责写入。

一个 PendingAddOp 对象代表一条 entry 的写入操作,会同时向多个 bookie 节点写入这条 entry,PendingAddOp 实现了 WriteCallback接口,每个bookie节点完成写入后会回调。PendingAddOp 中 引用了 LedgerHandler 对象,当多个 bookie 节点都处理完这条entry的写请求后,会回调 LedgerHandler 中的发送成功或者失败的处理方法。

BookieClient 对象负责执行向一个 Bookie 节点发送写或读请求。

BookieClientImpl 在客户端初始化时创建,维护着与所有Bookie节点的连接池,给所有 LedgerHandler 共享。

连接池中维护的 PerChannelBookieClient 就是客户端和一个 Bookie 节点的连接,PerChannelBookieClient 内部是一个 Netty 的客户端,继承了 ChannelInboundHandlerAdapter 类,接收服务端的响应。组合了 ChannelOutboundInvoker 类型的 channel,向服务端写数据。connect 方法初始化 channel

在这里插入图片描述

三、容错设计

BookKeeper 的重客户端设计,容错有下面几点:

1. 客户端故障时,未完成写入丢失,已确认数据保留。

2. Bookie 故障时,快速标记故障,触发Ensemble重配置。

3. 加入新节点后,在创建新的 Ledger 时,会选择将新 Bookie 节点使用起来。



点赞(0)

立即下载

相关下载

顶部