提要
Apache Bookkeeper github地址:https://github.com/apache/bookkeeper
本源码分析基于bookkeeper 4.14版本
术语说明
- bk: Bookkeeper中bookie节点的简称
- ledger: Bookkeeper中分布式日志分段,由多个fragment组成
- e : 为了简述,文中e(E)表示fragment的ensemble size,即fragment的全部可写bookie集合大小。文中部分语境e指fragment的全部可写bookie集合。
- qw: 为了简述,文中qw(Qw)表示entry的write quorum size,即entry的写集合大小。文中部分语境qw指entry的写集合。文中entry读取时的读集合等同于写集合。
- qa: 为了简述,文中qa(Qa)表示entry的ack quorum size,即entry写入时至少qa数量的bk返回写入成功时bk client即可认为entry写入成功。
背景
Apache Bookkeeper通过entry的多副本存储策略保证数据安全。当e=3,qw=3,qa=2时,Bookkeeper承诺entry存储的副本数为2或3。当bk宕机或下线时,必然导致该bk上的ledger中entry的副本数减1。当qa数量的bk宕机或下线时,理论上会导致数据丢失。因此Bookkeeper社区提供AutoRecovery模块保证数据存储副本数始终>=qa。
此外,在Apache Pulsar中,broker作为bk client将消息持续写入bk中。对于OPEN状态的ledger,当>=qa数量的bookie下线,如果无消息写入或者写入频次很低,会等到写入请求到来时才会触发报错创建新的ledger。如果在此之前该ledger从broker A分配到Broker B会触发recover,但ledger的多个bookie节点(>=2)已下线因此recover必定失败,出现异常ledger(即异常topic)。社区autoRecovery模块也可解决该问题。
原理
autoRecovery模块有两个主要组件:Auditor与ReplicationWorker
注:下文按e=3,qw=3,qa=2策略展开
Auditor:
Auditor组件工作流程如下
- autoRecovery会选主启动Auditor,通过ledgers/underreplication/auditorelection目录下的临时节点选主,序列号最小的启动Auditor
- 监听ledgers/available目录和ledgers/available/readonly目录,若bookie节点下线则触发审计
- 监听ledgers/underreplication/lostBookieRecoveryDelay目录,若目录节点数据改变则触发审计
- 审计:获取全部的ledgermetadata并按bookie进行分类(Map<BookieId, Set>),将下线bookie对应的ledgers写入目录ledgers/underreplication/ledgers/,如下:
其中目录名urL0004064562的数字部分即为ledgerId,节点内容为该ledger对应的qw副本数地址与创建时间。
ReplicationWorker:
ReplicationWorker组件工作流程如下
- 各autoRecovery节点对等,每个节点单线程处理ledger
- 从ledgers/underreplication/ledgers/(可看作等待处理的ledger队列)目录下获取一个ledger,加锁,加锁成功表示该autoRecovery可处理,加锁失败则尝试下一个ledger。
其中目录名urL0003732832的数字部分即为ledgerId,节点内容为处理改ledger的bk节点。
3. 处理ledger,可分为如下两种情况:
3.1 当ledger状态为CLOSED时,如下图,
a: 筛选出ledger A中entry不可读的fragment:每个fragment的entry数量可以通过后一个fragment或LastEntryId-startEntryId获得,通过percentageOfLedgerFragmentToBeVerified将这些entry分成若干等份,每份随机取一个entry作为集合B(若percentageOfLedgerFragmentToBeVerified=0则只取首尾两个entry),读取集合B的entry若读取失败则认为对应fragment需要复制,读取失败节点bk-H即是检测到的下线节点。
b: 针对需要复制的fragment:从头到尾分批次读取entry,读取成功后将entry写到新的节点Bk-F
c: 修改原数据将fragment的ensemble里的Bk-H替换为Bk-F
d: 可解决影响数据丢失的风险
注:percentageOfLedgerFragmentToBeVerified配置决定数据副本是否严格达到qw数量。默认情况下值为0说明不要求严格达到qw副本数量。如果值为100说明要求全部entry严格达到qw副本数量。如果值为20说明要求20%概率下全部entry严格达到qw副本数量。
3.2 当ledger状态为OPEN/IN_RECOVERY时,如下图:
a: fragment1-3的修复同CLOSED的ledger。
b: fragment4为正在写的,若对应bookie节点都在线则无需处理。若存在bookie节点下线则需要处理:recover该open状态的ledger,目的是通过fence操作夺取broker的写权限。最后再close该ledger。
c: 可解决因bk下线或宕机导致的recover失败风险。
bk下线
如上为社区autoRecovery原理,主动触发bookie下线步骤如下:
$ bin/bookkeeper shell decommissionbookie -bookieid
该命令仅仅触发审计,并等待下线bookieid对应的ledger复制完毕。而下线bk的ledger处理则由autoRecovery完成。
如果不执行上述命令,会等待ledgers/underreplication/lostBookieRecoveryDelay配置时间触发审计。