Bookkeeper

357 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情 >>

\

基本概念:Ledger:BK中的基本存储单元;Fragment:BK的最小分布单元;Entry:日志

架构设计:Clients、ZooKeeper、Bookie pool;Bookies 在启动的时候向 ZooKeeper 注册节点,Client 通过 ZooKeeper 发现可用的 Bookie。

image.png

1、Journals :存储事务日志,提供sync

2、EntryLogFile:存储真正数据的文件。所有ledger的数据先缓存在buffer中,然后聚合然后flush顺序写入到同一个EntryLog文件中,避免磁盘随机写。

  • 刷盘前会做排序,通过 聚合+排序 优化读取性能

3、Index 文件:数据的索引文件,存储在Rocksdb中。为了加速数据读取,设置的 ledgerId + entryId 到文件 offset 的映射。先缓存在内存中,称为IndexCache,容量达到上限时,通过sync写入磁盘。

写入流程

  1. Writer 会先分配对应的 id,然后按照 round-robin 算法从3个 Bookie 中选取2个 Bookie;

  2. Writer 会向两个 Bookie 发送写入请求,因为 Qa 设置为2,只有收到两个 ack 响应后,才会认为这条 Entry 写入成功;

    如果写入过程中有一台 Bookie 挂了怎么办?

    1. 那么只能向另外2台 Bookie 写入数据;
    2. 这时候这个 Ledger 会新建一个 Fragment,假设挂的是A,之前 Ensemble 是 A、B、C,现在的是 B、C;
    3. 这个变化会更新到 zk 中这个 Ledger 的 meta 中。

    如果写入过程中有两个 Bookie 挂了怎么办?

    1. Ensemble 里面的存活的 Bookies 不能满足 Qw 的要求;
    2. Client 会进行一个 Ensemble Change 操作;
    3. Ensemble Change 将从 Bookie Pool 中根据数据放置策略挑选出额外的 Bookie 用来取代那些不存活的 Bookie 。

Bookie写细节

  1. 数据同时写入Journal和Memtable
  2. 写入Memtable对写入请求进行相应
  3. Memtable写满之后flush到Entry Logger和Index cache
  4. 后台线程帮助数据落盘

读取流程

  1. 在读取会选择最优的 Bookie,有了 Entry 的 id 和 Ledger 的 Ensemble 就可以根据 round-robin 计算出其所在 Bookie 信息,会选择向其中一个 Bookie 发送读请求。

    • 优化:读取时一般是选择读一段数据,如果 entries 在同一台机器上,会从同一个 Bookie 把这批 Entry 全部读取。
  2. 长尾效应处理——Speculative Read,先发送给第一个副本,如果在指定时间没有response,向第二副本发送请求,同时等待,又一个返回即读取成功。

Bookie读细节

  1. Tailing read:直接从Memtbale中读取Entry
  2. Catch-up read(滞后消费)请求:先读取Index信息,然后索引从Entry Logger文件读取Entry

一致性保证

写的一致性:

  1. 写入的数据都是先缓存在内存中,如果BK奔溃,可以根据journal中的事务信息进行数据恢复,LastLogMark记录了journal恢复位置信息
  2. LastLogMark被持久化磁盘上之后,journal在此之前的数据都可以被清除了。
  3. BK限制每个Ledger只能被一个writer写,Fencing机制防止脑裂现象出现。
  4. 每条记录会被 writer 赋予一个严格递增的 id,写成功更新Last-Add-Confirm指针。LAC 与 LAP(Pushed)差值为正在写数据

读的一致性

所有的 Reader 都可以安全读取 Entry ID 小于或者等于 LAC 的记录

容错机制

  1. Fencing机制:严格保证一个 Ledger 只能被一个 Writer 来写

    • 触发时机:如果一个 Writer 打开一个 Ledger,发现这个 Ledger 存在,并且没有 close,这种情况下,就会触发 Fencing 策略,并且触发 Ledger Recovery。
  1. Log Recovery机制:正常关闭异常 Ledger,并将 The Last Entry 及状态更新到 metadata 中

    • 实现方式:

      1. 遍历ledger所有entry进行恢复;
      2. 利用LAC加速恢复

生产模式

  1. Shared:多个Producer可以同时往一个Topic中生产消息
  2. Exclusive:独占模式生产,只有一个Producer可以connect并生产消息,其他Producer可以启动成功,作为stand-by
  3. ExclusiveWithFencing:独占模式生产,只有一个Producer可以connect并生产消息,其他Producer启动时,老的Producer会断开链接
  4. WaitForExclusive:独占模式生产,只有一个Producer可以connect并生产消息,其他Producer会卡在创建Producer环节

消费模式

  1. Exclusive:独占订阅,在任何时间,一个消费组订阅中有且只有一个消费者来消费Topic中的消息
  2. Failover:故障切换,多个消费者可以附加到同一订阅
  3. Shard:同一个订阅,用户按照应用的需求挂载任意多的消费者
  4. key_shared:使用共享订阅,订阅中的所有消息以key-hash发送给订阅背后的多个消费者,并且一个消息仅传递给一个消费者

参考

  1. bookkeeper读写
  1. BookKeeper 原理浅谈