分布式数据库tigerbeetle设计灵感来自LMAX架构


这份文档记录了分布式财务会计数据库 TigerBeetle 背后的设计决策:

我们希望其他人可以轻松构建下一代金融服务和应用程序,而不必从头开始拼凑会计或分类账记录系统。
TigerBeetle 采用最新的研究和技术来提供前所未有的安全性、耐用性和性能,同时将运营成本降低几个数量级,并提供出色的开发人员体验。

架构原理
理论上,TigerBeetle 是一个复制状态机,它采用初始起始状态(开户余额),并以确定的顺序应用一组输入事件(转移),在首先安全地复制这些输入事件之后,到达最终状态(账户期末余额)。

实际上,TigerBeetle 基于LMAX Exchange Architecture并做了一些改进。

我们采用相同的三个经典 LMAX 步骤:

  1. 将传入事件安全地记录到磁盘,并复制到备份节点,然后
  2. 将这些事件应用于内存状态,然后
  3. ACK给客户端

然后我们引入一些新东西:

  1. 完全删除本地日记步骤,并且
  2. 将其替换为并行复制到 3/5 分布式副本。

我们的架构然后变成三个简单的步骤:

  1. 将传入事件安全地复制到分布式副本的法定人数,然后
  2. 将这些事件应用于内存状态,然后
  3. ACK给客户端

这就是 TigerBeetle 如何消除领导者本地磁盘中的灰色故障,以及 TigerBeetle 如何消除到复制节点的网络链接中的灰色故障。

与 LMAX 一样,TigerBeetle 使用每核线程设计以获得最佳性能,并使用严格的单线程来执行单写入器原则并避免多线程协调访问数据的成本。


数据结构
了解 TigerBeetle 的最佳方式是通过它提供的数据结构。为了性能和简单性,所有数据结构都是固定大小的,并且有两种主要的数据结构,事件和状态。

事件
事件是实例化或改变状态数据结构的不可变数据结构:

  • 事件无法更改,即使其他事件也无法更改。
  • 事件无法导出,因此必须在执行前记录下来。
  • 事件必须以确定的顺序一个接一个地执行,以确保可重玩性。
  • 事件可能取决于过去的事件(他们应该选择)。
  • 事件不能依赖于未来事件。
  • 事件可能取决于处于确切版本的状态(他们应该选择)。
  • 事件可能成功或失败,但事件的结果永远不会存储在事件中;它存储在事件实例化或变异的状态中。
  • 事件只能有一个不可变版本,可以通过事件的id直接引用。
  • 应保留事件以用于审计目的。然而,一旦事件的影响被捕获到状态快照中,事件可能会被排入一个单独的冷存储系统,以压缩日志并缩短启动时间。

create_account:创建一个账户:

  • 我们使用贷方credit 和借方debit ,而不是 "应付款 payable"或 "应收款receivable",因为贷方余额的含义取决于账户是资产还是负债,还是权益,收入还是支出。
  • 记账posted 金额是指通过转账记账的金额。
  • 待定pending 金额指的是一个尚未通过两阶段转账过账的飞行金额,在这种情况下,转账仍在等待中,而且转账超时还没有发生。换句话说,转账金额已经在待定账户余额中保留(以避免重复消费),但尚未记入已记账余额。如果转账最终失败,保留的金额将回滚。默认情况下,转账会自动过账,但能够将金额保留为待定,然后稍后才过账有时会很方便,例如,在转换信用卡付款时。
  • 一个账户的借方debit 余额是由已过账的借方debits_posted和待过账的借方debits_pending相加得出的,同样,一个账户的贷方余额也是如此。
  • 一个账户的总余额可以通过从总借方余额中减去总贷方余额得出。
  • 我们将账本的两边(借方和贷方)分开,以避免处理签名的数字,并保留关于账户性质的更多信息。例如,两个账户的余额可能相同为0,但一个账户可能在分类账的两边都有1,000,000个单位,而另一个账户可能在两边都有1个单位,两者平衡为0。
  • 一旦创建,一个账户只能通过转移事件来改变,以保持不可改变的纸面记录,供审计使用。

安全
TigerBeetle 的设计安全标准高于 MySQL 等通用关系数据库或 Redis 等内存数据库:

  • 严格的一致性、CRC 和crash安全性还不够。
  • TigerBeetle检测并修复磁盘损坏(每 32 个月 3.45%,每个磁盘),检测并修复磁盘固件写入错误扇区的错误定向写入(每 17 个月,每个磁盘 0.042%),并防止数据篡改哈希链加密校验和。
  • TigerBeetle通过设计使用直接 I/O来避免 EIO fsync 错误后内核页面缓存中的缓存一致性错误。
  • TigerBeetle超过了单个磁盘和单个服务器硬件的 fsync 耐久性,因为磁盘固件可能包含错误并且因为单个服务器系统出现故障。
  • TigerBeetle提供严格的可序列化性,即一致性的黄金标准,作为复制状态机和 TigerBeetle 服务器集群(称为副本),以实现最佳的高可用性和分布式容错。
  • TigerBeetle使用开创性的Viewstamped 复制和共识协议对 TigerBeetle 服务器进行同步复制,以实现低延迟自动领导者选举,并消除与手动故障转移相关的脑裂风险。
  • TigerBeetle 具有“故障感知”能力,可以在全局共识协议的上下文中从本地存储故障中恢复,提供比 ZooKeeper 和 LogCabin 等复制状态机更高的安全性。例如,TigerBeetle 可以将已提交日志中间的损坏(由位腐烂引起)与日志末尾的撕裂写入(由电源故障引起)分开,以维护为已提交数据提供的持久性保证并最大限度地提高可用性。
  • TigerBeetle 不依赖于同步系统时钟,不使用领导者租约,并执行基于领导者的时间戳,因此您的应用程序只能处理与传输超时相关的安全相对时间量。为确保领导者的时钟在“真实时间”的安全范围内,TigerBeetle 将集群中的所有时钟组合起来创建一个容错时钟,我们称之为“集群时间”

性能
TigerBeetle 提供比通用关系数据库(如 MySQL)或内存数据库(如 Redis)更高的性能:

  • TigerBeetle使用小型、简单的固定大小数据结构(账户和转账)和一个严格限定范围的域。
  • TigerBeetle在数据库中执行所有余额跟踪逻辑。这是一种范式转变,我们将代码一次移动到数据,而不是数据来回移动到关键路径中的代码。这消除了对数据库外部的复杂缓存逻辑的需要。“会计”业务逻辑内置于 TigerBeetle 中,因此您可以使应用层保持简单和完全无状态。
  • TigerBeetle通过设计支持批处理。您可以在固定的 10 毫秒窗口(或根据负载在动态的 1 毫秒到 10 毫秒窗口中)接收的所有传输准备或提交进行批处理,然后将它们全部发送到数据库的单个网络请求中。这可以实现低开销网络、大型顺序磁盘写入模式以及分摊 fsync 和跨越成百上千次传输的共识。
  • 一切都是一批。您可以选择一个批次包含 100 次传输还是 10,000 次传输,但我们的测量表明,由于 Little 定律(例如,100 次传输的批次为 50 毫秒,而 10000 次传输的批次为 20 毫秒),我们的测量结果表明,在批次大小较大的情况下,延迟会更短. TigerBeetle 能够通过消除小批量产生的排队延迟成本来分摊 I/O 成本以实现更低的延迟,即使对于相当大的批量大小也是如此。
  • 如果您的系统没有负载,TigerBeetle 还会优化​​小批量的延迟。从内核的 TCP 接收缓冲区复制后(TigerBeetle 不执行用户空间 TCP),TigerBeetle将直接 I/O 从网络协议零复制到磁盘,然后到状态机并返回,以减少内存压力和 L1-L3缓存污染。
  • TigerBeetle使用 io_uring 进行零系统调用网络和存储 I/O。对于几千次传输,系统调用在上下文切换方面的成本会迅速增加。
  • TigerBeetle通过使用固定大小的数据结构进行零反序列化,这些数据结构针对缓存行对齐进行了优化,以最大限度地减少 L1-L3 缓存未命中。
  • TigerBeetle利用 Heidi Howard 的 Flexible Quorums将同步复制的成本降低到最多一个(或两个)远程副本(除了领导者之外),并在剩余的跟随者之间进行异步复制。这在不牺牲严格的可串行性或持久性的情况下提高了写入可用性。这还将服务器部署成本降低多达 20%,因为具有灵活仲裁的 4 节点集群现在可以f=2为复制仲裁提供与 5 节点集群相同的保证。
  • “我们在云环境中看到的主要可用性故障和性能异常往往是由细微的潜在故障引起的,即灰色故障(缓慢故障的硬件)而不是故障停止故障。”
  • TigerBeetle绕过瞬态灰色故障延迟峰值。例如,如果通常需要 4 毫秒的磁盘写入开始需要 4 秒,因为磁盘正在慢慢出现故障,TigerBeetle 将使用集群冗余来自动屏蔽灰色故障,而用户不会看到任何 4 秒的延迟峰值。这是文献中称为“尾部公差”的一种相对较新的性能技术。

详细点击标题