Delta:链式复制架构的存储服务

Oct 6, 2023 12:00 · 2402 words · 5 minute read Architecture Distributed System

链式复制一种在保证强一致性的前提下尽可能高可用的架构。

Facebook/Meta 的需求:

  1. 通用的存储系统(减少和融合已有的)
  2. 为关键的工作负载(服务)提供专用的解决方案
  3. 容灾
  4. 为构建和分发软件提供存储服务

Delta 在 Facebook 基础设施栈中的定位属于最底层:

什么是 Delta?

  • Delta 是一个简单可靠可扩展低依赖对象存储系统
  • 只有四个高级操作:
    1. put
    2. get
    3. delete
    4. list
  • 延迟存储效率换取简单可靠(有得必有失)
  • 针对依赖关系采取合适的故障恢复策略

Delta 不是

  • 通用存储系统:Delta 的核心原则是弹性和数据保护,专为低依赖性系统的使用而设计
  • 文件系统:Delta 是一个简单的对象存储系统,不暴露像 Posix 那样的文件系统语义
  • 为最大化存储效率而优化:以弹性为宗旨,没有为存储效率、延迟或吞吐量优化

架构

Delta 是链式复制架构的实现。

链式复制架构以线形拓扑将服务器串成,每条链都是一组冗余副本的主机。

第一台服务器叫做链头,最后一台服务器叫做链尾。每个写入请求都会定向到链头,更新就像管道一样通过链从头传到尾。所有服务器都持久化更新后,链尾就响应写请求。读取请求只会被定向至链尾,客户端从链尾读取的内容,在链中的所有服务器上都是一样的,保证了强一致性。

链式复制 vs quorum(法定票数)复制

  • 存储效率链式复制的存储效率不高,因为整个数据集的冗余副本存储在链中的所有主机上。一种相对高效的方法是使用纠删码技术复制数据片段。
  • 容错链式复制比 quorum 更好,因为 n 个节点的链可以容忍最多 n - 2 个节点的故障;反观基于 quorum 的复制系统,n 个节点的集群,至少需要 n/2 + 1 个节点存活。
  • 性能:在链式复制中所有节点(副本)都可以提供读读取服务,这增提升了读取吞吐量(Facebook 优化后的,原生的只有链尾提供)。与 quorum 机制类似,链式复制中所有写入都会定向至链头(quorum 中的 leader);但链式复制只有在链中所有节点都确认更新后才会响应,quorum 只需要 n/2 + 1 个节点确认更新。因此链式复制的写入延迟更高
  • 复杂度:基于 quorum 的系统需要复杂的共识算法和选主机制来维护系统中的法定票数;相比之下,链式复制系统 quorum 共识的范围缩小到更简单的链主机映射(链头始终充当处理写入的 leader,不需要显式的选主)。

Delta bucket

每个桶(bucket)都包含了几条链,每条链通常由 4+ 台服务器组成。每条链本身充当副本集,提供数据的切片并承载流量。特定链中的服务器分布在不同的域(机房)中,这样做是为了保证数据的持久性和可用性。Delta 维护一个桶的配置,即权威的桶布局的链-主机映射。当向桶中添加或删除服务器和链时,桶配置会被更新。

客户端访问 Delta 存储桶中的对象时,根据对象名称的一致性哈希选择正确的链。读写请求遵循链式复制协议。

Delta 支持水平扩展,在新节点加入到存储桶中后会智能地重新平衡新增服务器的链,不会影响服务的可用性和吞吐量。

故障恢复

故障包括主机停机网络分区计划中的维护操作事故其他意外事件。在链式复制的实现中,我们假设服务器是故障停机的(fail-stop):

  • 每台服务器都会因故障直接停机,而不是错误地转换状态
  • 服务器的停机状态可以被环境探测到

Delta 中与故障主机同一条链的其他主机能够检测到疑似出问题的主机并报告:心跳或在链上传递确认/请求时遇到故障。如果多个节点怀疑某个特定的节点,则该节点会从链中剔除并送修,桶配置会被更新。

检测到主机的可疑行为时要权衡:

  • 超时设置:正确的超时设置是通过多次性能测试仔细评估出来的,不能太短也不能太长。客户端在等待应答时也可能超时。
  • 票数:评估可疑节点被剔除,要满足多少节点投票给它,不能太小也不能太大,太大会导致问题节点在链中停留太久从而影响到服务的性能。将票数设置为 2 的效果很好。

故障节点修复后可以被添加至原来的链中,新节点会被添加到链的后端,必须先扫描上游节点同步数据。在重建期间,该主机不能被读取,必须将读取推至上游。

Delta 桶扩容也是这个流程。

Delta 的改进

分配查询

链式复制架构读取服务效率较低:

  • 链尾是唯一的读写节点,会成为热点
  • 链尾处理所有读取,限制了吞吐量

**通过分配查询请求,让链中所有节点都提供读取服务。**在响应客户端读取请求前,必须验证被读取对象的本地副本是否过期(访问链尾),确保客户端只能读到链中所有节点已提交的对象版本,保证链式复制的强一致性。链尾是对象最新版本的权威。

节点访问链尾检查对象版本的开销很低,不会严重影响客户端延迟。

自动修复

硬件故障和网络分区在大型集群中相当频繁,因此故障检测、主机修复和恢复应该自动化。

Facebook 构建了一个控制平面服务(CPS)来实现 Delta 集群的自动化管理。

在修复链时,CPS 实现最高效率的技术:

  • CPS 维护桶布局中所有链的故障域分布,确保主机均匀分布在所有故障域中。
  • 通过多条链来避免服务器过载。
  • 当一条链缺了一个节点,CPS 优先修复故障节点而非向链中添加一台全新的主机。与修复后同步部分数据相比,将所有数据同步至新主机需要大量计算。
  • 在主机添加到链之前,CPS 将对其进行详细的“体检”,确保将健康的主机加进去。
  • 除了存储桶中的服务器,CPS 还会维护一个健康的备用服务器池。如果一条链丢失了超过 50% 的主机,CPS 会向该链添加一个新的备用主机,确保这种链不会危及存储桶的可用性。

全局复制

Delta 最初的实现中,客户端出于数据安全的考虑想要将 blob 存储在多个区域,会向各个区域发送请求。从用户角度来看这不理想,用户不应该跟踪对象的位置。客户端应该一旦将对象放入存储,底层服务将变更传播到各处。检索也一样,客户端通过提交请求让服务从最佳来源获取检索对象。

随着服务的演进,向客户端引入了全局复制。是以将 blob 同步复制到几个区域,异步复制到其他区域混合完成的。

灾难恢复

与归档服务集成,持续将客户端 blob 备份到冷存储中,此外还开发了从归档服务持续恢复对象的能力。

下一步

基于 Delta 存储为 Meta 的核心基础设施提供集中式的备份和恢复服务。任何有状态服务都必须能够生成其内部状态(备份)的快照并从快照恢复内部状态。终极目标是为客户提供集中式备份服务。