ArcticDB
2023 年 4 月 14 日
在 Man Group,数据管理是我们工作的核心,我们的量化师和研究人员最常使用的数据结构就是 DataFrame。作为管理着数十亿美元资产的积极型投资管理人,我们必须能够以卓越的性能和内置的可靠性存储和处理各种规模的 DataFrame;从微小的元数据到巨大的时间序列。我们早在十多年前就意识到,我们需要一个将 DataFrame 置于其数据模型核心的数据库,这就是我们通过 ArcticDB 构建的成果。
ArcticDB 旨在利用数据库领域的两个现代发展优势
首先,云端和本地都具备了经济高效、高性能的存储。
其次,对不变性重新产生的兴趣,将其视为确保水平可扩展性而不降低性能、提供对先前版本的时间旅行功能以及保证关键数据可用性的一种方式。
ArcticDB 基于键值存储而非本地磁盘,这意味着我们需要仔细考虑键的结构,以避免命名冲突并确保键具有意义。
我们决定采用多分段的“结构化”键,其中包含描述版本、开始和结束索引点、时间戳等不同字段。使用结构化键的一个优点是,许多操作只需查看键的内容即可完成。这意味着完全避免了检索对象的成本;例如在实现并行写入功能时,这使得并行写入许多 DataFrame 并将它们合并为一个实体成为可能。这意味着我们可以使用键中的开始和结束索引来判断各个 DataFrame 是否有重叠的索引需要合并,或者可以直接插入到索引中。
类似地,我们可以扫描索引,仅通过读取其中包含的键,即可确定它引用的对象是否大小适合高性能读取,或者是否需要执行拆分或压缩。
我们很快意识到,一组这样的结构化键可以完美地放入 DataFrame 中。其效果是我们可以将单一类型的对象写入存储,并将其用于用户数据和系统数据。
这是数据库设计中的一个常见模式,数据库使用其基本类型(无论是表、文档还是图)来存储元数据,这是有充分理由的:实现者可以专注于使单一结构尽可能高性能,而数据处理能力(如过滤)的改进则会同时提升用户和系统的性能。
一个 DataFrame,其行代表其他对象的键,使得在存储中创建不同类型的结构(如 B 树、LSM 树或链表)成为可能,而这些正是构成 ArcticDB 的基本数据结构。
我们做出的第二个设计决策是将所有关键结构持久化,这意味着无论它们如何修改,都能有效地保留其所有先前的形态。
这有多重好处
如果不修改数据,就不可能破坏它;
用户在应用层免受不良写入的影响(因为总是可以恢复到之前的好版本);以及;
确保同时修改同一块数据不会产生数据竞争所需的复杂的锁定和协调机制可以得到简化,并且在许多情况下可以完全移除。
传统的分布式数据库花费大量时间在不同节点之间传递同一数据的副本,以防硬件故障。但在复制块存储的时代,在数据库层重复这项工作是不必要的。由于数据只添加和删除,而不修改,我们不再需要一个始终在线的服务器组件来保证一致性。鉴于我们可以将管理磁盘故障的责任推迟到存储层,我们能够在客户端操作中无需服务器进程即可管理。
这极大地降低了支持成本并提高了弹性,因为不再依赖于必须将时间分配给执行清理任务(如压缩和碎片整理)和持续可用以服务客户端请求的单一进程。
只要客户端能够连接到存储,数据就始终可用。一个独立的后台进程跟踪预写日志,在数据中心之间进行复制,以提供备份和灾难恢复功能,因此始终有最新的存储可供客户端连接。
数据库层
数据库架构由四层组成;最底层的数据和索引 DataFrame 存储用户数据,并允许按时间范围、列和次要特征快速子选数据。在其上方是版本层,其中记录有关可用数据的信息并随后进行压缩。在其顶部是一个由微小的指针对象组成的可变层,通过为每个版本列表的头部提供确定性键来加速查找特定版本的过程。
这些层始终自下而上写入,以便在指针对象更新和新版本可用之前,对象的所有组件都完全可用。由于不同命名对象(我们称之为符号)之间不共享数据,因此任务可以在符号之间并行执行,实现完美的扩展性,直至达到存储和网络的容量。
希望您喜欢这次对 ArcticDB 如何在磁盘上构建数据的深入探讨。这为我们带来了整个业务的性能改进,并且我们相信它也能为其他人提供同样的帮助。