写点什么

【Apache BookKeeper】 概念与架构

用户头像
awen
关注
发布于: 2021 年 06 月 02 日
【Apache BookKeeper】 概念与架构

BookKeeper 是一种提供持久化流式日志条目的存储服务,其序列称为分类帐。BookKeeper 跨多个服务器复制存储的日志条目。

BookKeeper 最初的灵感来自 HDFS 中的 NameNode 服务器,但现在它的用途已经远远超出了这个范围。BookKeeper 基本上可以为任何其它 append-based 存储系统提供如下优势:

  • 高效写

  • 基于复制的高容错(消息在 ensembles 之间复制,这个概念之后会讲)

  • 高吞吐量写

基本术语

  1. 一个 entry 代表一个基本的日志单元

  2. 日志条目 entry 流被称为 ledger

  3. 存储日志条目分类账的服务器被称为 bookie

BookKeeper 被设计为可靠和弹性可恢复的,以应对各种各样的失败。Bookies 可能宕机、数据损坏甚至丢失数据,但是只要服务中有足够的 bookies 存活,那么整个服务运行正常。

Entries

Entries 包含写入到分类账的真实数据,同时带有一些重要的元数据信息。每一个 entry 主要包含如下几个字段:


| 字段 | Java Type | 描述 |

| --------- | -----: | :----: |

| Leder number | long | entry 所属的 ledger id |

| Entry number | long | entry 的唯一 id |

| Last confirmed | long | 上一个 entry 的 id |

| Data | byte[] | 数据 |

| Authentication code | byte[] | The message auth code, which includes allother fields in the entry |

Ledgers

Ledgers 是 BookKeeper 的基本的存储单元,是 entries 的序列。Entries 写入到 ledger。包含如下两大特点:

  1. 序列化数据

  2. 至多一次

以上特点说明 leders 只能追加。Entries 一旦被写入分类账 ledger 后就不能被再次修改。数据的写入顺序有客户端来负责。

Clients and APIs

BookKeeper 客户端承担两大主要角色:

  1. 创建和删除 ledger

  2. 读取和写入数据 到 ledger

BookKeeper 提供了 lower-level 和 higher-level API 与 ledger 进行数据交互。

  1. lower-lever API 提供底层 api 与 legers 直接进行交互

  2. DistributedLog API 使开发者无需直接与 ledgers 直接交互就能使用 BookKeeper

Bookies

Bookies 是处理分类账(更具体地说,是分类账的片段)的 ledger 服务器。

一个 bookie 是一个单独的 BookKeeper 存储服务器。单个 bookie 服务器存储了 ledgers 的片段而非全部 ledgers。

Metadata storage

BookKeeper 元数据存储 包含了 BookKeeper 集群的所有元数据信息,包括 ledger 元数据、可用 bookies 列表等。目前,BookKeeper 使用 ZeeKeeper 作为元数据存储服务。

Data management in bookies

Bookies 以日志结构的方式管理数据,具体以如下三种文件形式实现:

Journals

Journals 文件包含 BookKeeper 服务的事务日志。当 bookie 服务启动或者老的 journal 文件大小达到阈值的时候会创建新的 journal 文件。

Entry logs

Entry 日志文件管理从 BookKeeper 客户端接收到写入的 entries。不同分类账目的 entries 聚合并顺序写入,同事它们的偏移量被作为指针村住在 ledger 缓存方便快速查询。

当 bookie 服务启动或者老的 entry 日志文件大小达到阈值的时候会创建新的 entry 日志文件。一旦老的 entry 文件不在于任何活动的 ledger 关联,那马它将被 GC 回收。

Index files

为每个分类帐创建一个索引文件,包括一个标题和几个固定长度的索引页,这些索引页记录了存储在 entry 日志文件中数据的偏移量。

由于更新索引文件会引入随机磁盘 I/O,所以索引文件由后台运行的同步线程延迟更新。这确保了更新的快速性能。在索引页被持久化到磁盘之前,它们被收集到 ledger 缓存中进行查找。

ledger 缓存在内存池中,这样可以更有效地进行磁盘头调度管理。

Adding entries

当客户端指示 bookie 将 entry 写入分类账时,该 entry 将通过以下步骤保存到磁盘上:

  1. 当前 entry 被追加到 entry 日志文件

  2. entry 的索引 被追加到 ledger 缓存

  3. 与此操作相关的事务被追加到 journal

  4. 返回客户端

Data flush

Ledger 索引页在如下两种情况下会被刷新到索引文件:

  1. ledger 缓存 达到内存限制,没有可用的内存空间来保存新的索引页。脏索引页会从 ledger 缓存剔除并持久化到索引文件。

  2. 后台同步线程负责周期性从 ledger 缓存刷新索引页到索引文件。

除了刷新索引页外,同步线程还负责在日志文件占用过多磁盘空间的情况下滚动日志文件。同步线程中的数据刷新流程如下:

  • 最后一个日志标记记录在内存中。LastLogMark 表示在它被持久化之前的那些条目(索引和条目日志文件),它包含两个部分:

  1. txnLogId(日志的文件 ID)

  2. txnLogPos(日志中的偏移量)

  • 脏索引页从 ledger 缓存刷新到索引文件,entry 日志文件刷新以确保 entry 日志文件中的所有缓存 entry 都持久化到磁盘。

  • 理想情况下,bookie 只需要刷新索引页和包含 LastLogMark 之前的 entry 的 entry 日志文件。但是,ledger 和 entry 日志中没有此类信息映射到 journal 文件。因此,线程在这里整个刷新 ledger 缓存和 entry 日志,并且可能在 LastLogMark 之后刷新条目。不过,多次刷新不是问题,只是有些多余的。

LastLogMark 被持久化到磁盘,这意味着在 LastLogMark 之前添加的 entry 据和索引页也被持久化到磁盘。现在是安全删除比 txnLogId 更早创建的 journal 文件的时候了。

如果在将 LastLogMark 持久化到磁盘之前 bookie 已经宕机,那么它仍然有包含索引页可能尚未持久化的条目的日志文件。因此,当 这个 bookie 重启,会检查 journal 文件以恢复这些 entry,确保数据不会丢失。

Data compaction

在 bookie 服务上,不同 ledger 的 entry 在 entry 日志文件中交错。bookie 运行 GC 线程来删除没有关联关系的 entry 日志文件以回收磁盘空间。如果给定的 entry 日志文件包含尚未删除的 ledger 中的 entry,则该 entry 日志文件将永远不会被删除,占用的磁盘空间也永远不会被回收。为了避免这种情况,bookie 服务器压缩垃圾收集器线程中的 entry 日志文件以回收磁盘空间。

有两种不同频率的压缩运行:minor compaction 和 major compaction。它们区别在于它们的阈值和压实间隔。

  1. 垃圾回收阈值是那些未删除的 ledger 占用的条目日志文件的大小百分比。默认的 minor compaction 阈值为 0.2,而主要压缩阈值为 major compaction。

  2. 垃圾收集间隔是运行压缩的频率。默认的 minor compaction 间隔为 1 小时,而 major compaction 阈值为 1 天。

用户头像

awen

关注

Things happen for a reason. 2019.11.15 加入

还未添加个人简介

评论

发布
暂无评论
【Apache BookKeeper】 概念与架构