原作者:Sijie Guo
翻译:StreamNative-Sijia
Apache BookKeeper 是企业级存储系统,旨在保证高持久性、一致性与低延迟。Pulsar 由雅虎研究院(Yahoo! Research)开发,旨在实现 Hadoop 分布式文件系统(HDFS)NameNode 的高可用,在此之前,NameNode 不具备高可用特性,存在单点故障的问题。自 2011 年起,BookKeeper 开始在 Apache ZooKeeper 下作为子项目孵化,并于 2015 年 1 月作为顶级项目成功问世。在这四年间,Twitter、Yahoo、Salesforce 等公司使用 BookKeeper 存储和服务重要数据,并支撑了许多不同场景。本文将简要介绍 BookKeeper 的概念和相关术语。
背景介绍
BookKeeper 的开发者(Benjamin Reed、Flavio Junqueira、Ivan Kelly)凭借搭建 ZooKeeper 的经验设计了一个灵活的系统,能够支持多种工作负载。最初,BookKeeper 是分布式系统的预写式日志(WAL)机制。现在 BookKeeper 已经发展成为支持多个企业级系统的基础构建模块,如:Twitter 的 EventBus、雅虎的 Apache Pulsar 等。
BookKeeper 是什么?
BookKeeper 是一种优化实时工作负载的存储服务,具有可扩展、高容错、低延迟的特点。根据我们多年的工作经验,企业级的实时存储平台应符合以下几项要求:
- 以极低的延迟(小于 5 毫秒)读写 entry 流
- 能够持久、一致、容错地存储数据
- 在写数据时,能够进行流式传输或追尾传输
- 有效地存储、访问历史数据与实时数据
BookKeeper 的设计完全符合以上要求,并广泛用于多种用例,例如为分布式系统提供高可用性或多副本(如 HDFS NameNode 节点、Twitter 的 Manhattan key-value 存储);在单个集群中或多个集群间(多个数据中心)提供跨机器复制;为发布 / 订阅(pub-sub)消息系统(如 Twitter 的 EventBus、Apache Pulsar)提供存储服务;为流工作存储不可变对象(例如:检查点数据的快照)等。
BookKeeper 的概念及术语
BookKeeper 复制并持久存储日志流。日志流是形成良好序列的记录流。
记录
数据以不可分割记录的序列,而不是单个字节写入 Apache BookKeeper 的日志。记录 是 BookKeeper 中最小的 I/O 单元,也被称作地址单元。单条记录中包含与该记录相关或分配给该记录的序列号(例如递增的长数)。客户端总是从特定记录开始读取,或者追尾序列。也就是说,客户端通过监听序列来寻找下一条要添加到日志中的记录。客户端可以单次接收单条记录,也可以接收包含多条记录的数据块。序列号也可以用于随机检索记录。
日志
BookKeeper 中提供了两个表示日志存储的名词:一个是 ledger(又称日志段);另一个是 stream(又称日志流)。
Ledger 用于记录或存储一系列数据记录(日志)。当客户端主动关闭或者当充当 writer 的客户端宕机时,正在写入此 ledger 的记录会丢失,而之前存储在 ledger 中的数据不会丢失。Ledger 一旦被关闭就不可变,也就是说,不允许向已关闭的 ledger 中添加数据记录(日志)。
图 1 BookKeeper ledger:有界数据 entries 序列
Stream(又称日志流)是无界、无限的数据记录序列。默认情况下,stream 永远不会丢失。stream 和 ledger 有所不同。在追加记录时,ledger 只能运行一次,而 stream 可以运行多次。一个 stream 由多个 ledger 组成;每个 ledger 根据基于时间或空间的滚动策略循环。在 stream 被删除之前,stream 有可能存在相对较长的时间(几天、几个月,甚至几年)。Stream 的主要数据保留机制是截断,包括根据基于时间或空间的保留策略删除最早的 ledger。
图 2 BookKeeper stream:无界数据记录 stream
Ledger 和 stream 为历史数据和实时数据提供统一的存储抽象。在写入数据时,日志流流式传输或追尾传输实时数据记录。存储在 ledger 的实时数据成为历史数据。累积在 stream 中的数据不受单机容量的限制。
命名空间
通常情况下,用户在命名空间分类、管理日志流。命名空间是租户用来创建 stream 的一种机制,也是一个部署或管理单元。用户可以配置命名空间级别的数据放置策略。同一命名空间的所有 stream 都拥有相同的命名空间的设置,并将记录存放在根据数据放置策略配置的存储节点中。这为同时管理多个 stream 的机制提供了强有力的支持。
Bookies
Bookies 即存储服务器。一个 bookie 是一个单独的 BookKeeper 存储服务器,用于存储数据记录。BookKeeper 跨 bookies 复制并存储数据 entries。出于性能考虑,单个 bookie 上存储 ledger 段,而不是整个 ledger。因此,bookie 就像是整个集成的一部分。对于任意给定 ledger L,集成指存储 L 中 entries 的一组 bookies。将 entries 写入 ledger 时,entries 就会跨集成 分段(写入 bookies 的一个分组而不是所有的 bookies)。
元数据
BookKeeper 需要元数据存储服务,用来存储 ledger 与可用 bookie 的相关信息。目前,BookKeeper 利用 ZooKeeper 来完成这项工作(除了数据存储服务外,还包括一些协调、配置管理任务等)。
与 BookKeeper 交互
与 bookie 交互时,BookKeeper 应用程序有两个主要作用:一个是创建 ledger 或 stream 以便写入数据;另一个是打开 ledger 或 stream 以便读取数据。为了与 BookKeeper 中两个不同的存储原语交互,BookKeeper 提供了两个 API。
| API | 说明 |
|—-|—-|
| Ledger API | 较低级别的 API,允许用户直接与 ledger 交互,极具灵活性,用户可根据需要与 bookie 交互。|
| Stream API | 较高级别、面向流的 API,通过 Apache DistributedLog 实现。用户无需管理与 ledger 交互的复杂性,就可以与 stream 交互。|
选择使用哪个 API 取决于用户对 ledger 语义设定的的粒度控制程度。用户也可以在单个应用程序中同时使用这两个 API。
放在一起看
下图即为 BookKeeper 的典型安装示例。
上图中的几个注意事项:
- 典型的 BookKeeper 安装包括元数据存储区(如 ZooKeeper)、bookie 集群,以及通过提供的客户端库与 bookie 交互的多个客户端。
- 为便于客户端的识别,bookie 会将自己广播到元数据存储区。
- Bookie 会与元数据存储区交互,作为回收站收集已删除数据。
-
应用程序通过提供的客户端库与 BookKeeper 交互(使用 ledger API 或 DistributedLog Stream API)
- 应用程序 1 需要对 ledger 进行粒度控制,以便直接使用 ledger API。
- 应用程序 2 不需要较低级别 ledger 控制,因此使用更加简化的日志流 API。
总结
本文对 BookKeeper 进行了技术层面的概述,首先介绍了 entry、ledger、stream、命名空间、bookie 的概念,然后介绍了典型的 BookKeeper 部署,以及如何处理数据等。
如果你对 BookKeeper 或 DistributedLog 感兴趣,可以通过以下方式加入我们的社区:
- BookKeeper Slack channel。你可以在 https://apachebookkeeper.herokuapp.com/ 注册。
- BookKeeper email list。
想要了解更多关于 Apache BookKeeper 项目的信息,请访问官方网站:http://bookkeeper.apache.org