在旧金山 QCon 大会上,我介绍了 Dropbox 的 EB 级 Blob 存储系统是如何存储所有客户数据的。Magic Pocket的核心是一个非常大的键值存储,其中的值可以是任意大小的 Blob。
我们的系统提供了超过 12 个 9 的持久性和 99.99%的可用性,在北美的三个地理区域运营。系统针对 4BM Blob、不可变写入和冷数据做了优化。
Magic Pocket 每秒处理数千万个请求,其中很多流量来自验证器和后台迁移。目前,我们部署了 60 多万个存储驱动器,运行着数千台计算机。
对象存储设备
Magic Pocket 主要聚焦对象存储设备(OSD)。这些设备的容量超过 2PB,每台存储机包含大约 100 块采用了叠瓦式记录(SMR)技术的磁盘。
与传统的磁记录驱动器相比,SMR 的不同之处在于它执行顺序写入而不是随机写入,提升了密度。
SMR 的缺点是,磁头会在走过下一条磁道时擦除它,以防在任何地方随机写入。
不过,这非常适合我们的工作负载模式。SMR 驱动器也有一个传统区域,允许在必要时缓存随机写操作。通常,该区域占驱动器总容量的不到 1%。
图 1:SMR 磁道布局
宏观上,Magic Pocket 的架构由三个区域组成:西海岸、中部和东海岸。Pocket 是该系统的核心概念,它代表了系统中所有东西的逻辑版本。Magic Pocket 可以有多个实例,如测试 Pocket 或生产 Pocket 之前的过渡 Pocket。Pocket 是独立运行的,彼此之间不共享数据库和计算资源。
区域
以下是每个区域中 Magic Pocket 架构的不同组件。
图 2:区域的工作机制
第一个服务是前端,它是与客户端交互的服务。客户端通常会发起 PUT 请求(带有键和 Blob)、GET 请求、删除调用或扫描系统中可用的散列。
GET 请求会查询散列索引(分片 MySQL 数据库的集合)。散列索引按散列分片,散列是 Blob 的键,每个散列都映射到一个单元格(cell)或一个桶(bucket),并有一个校验和。单元格是所有存储设备所在的隔离单元:它们可以超过 100PB,并且规模上有一定的增长空间。当容量不足时,系统将开辟一个新的单元格,实现水平扩展。
跨区域复制器是执行跨区域复制的组件,可以将数据存储在多个区域。该操作是异步完成的,一旦主区域发生了提交,数据就会排队等待复制到另一个区域。控制平面管理流量协调、生成迁移计划并控制机器重装。它还管理着单元格状态信息。
单元格
如果想获取一个 Blob,就需要访问了解桶和卷的桶服务:当请求一个桶时,请求会被映射到一个卷,而这个卷会被映射到一组 OSD。
图 3:单元格的运作机制
一旦找到拥有所需 Blob 的 OSD,就可以检索它了。对于写入数据,前端服务会找出哪些桶是打开的,并提交给处于就绪状态的桶。桶是预先创建好的,数据存储在卷内的一组 OSD 中。
协调器是单元格中的一个重要组件,管理所有桶、卷和存储机。协调器不断检查存储机的运行状况,与桶服务和数据库协调信息,并执行擦除编码和修复:它通过在单元格内移动数据实现数据优化,并负责在必要时将数据移动到其他机器。卷管理器处理卷的读、写、修复和擦除编码。验证步骤在计算单元格内外都会执行。
桶、卷和区段
现在,我们可以更深入地研究 Magic Pocket 存储系统的组件了,即桶、卷和区段。
图 4:桶、卷和区段
桶是与卷和区段相关联的逻辑存储单元,代表磁盘上 1 到 2GB 的数据。当写入时,我们找到打开的桶和与之关联的 OSD,然后写入区段。协调器管理桶、卷和区段信息,并可以通过为已删除的区段找到新的位置确保数据不会丢失。一个卷由一个或多个桶组成,它要么被复制,要么被擦除编码,它的状态可以是打开或关闭。一旦一个卷关闭后,就再也不会打开了。
如何在对象存储设备上查找 Blob
在这一部分中,我们将介绍如何在存储机中查找 Blob。为此,我们将 OSD 的地址存储在 Blob 中,并直接与这些 OSD 通信。
图 5:查找 Blob
磁盘驱动器(OSD)会加载所有区段信息,并创建一个内存索引,其中有磁盘偏移量的哈希值。如果想要获取块,就需要知道卷以及哪些 OSD 拥有该 Blob。对于 PUT,过程是一样的,但我们是并行地对每个 OSD 进行写操作,并且要在所有存储机上的写操作都完成后才会返回。由于卷被复制了 4 份,所以所有四个 OSD 中都有完整的副本。
擦除编码
虽然故障不可避免,但 2 个区域 4 个副本的复制成本很高。我们来看一下复制卷和擦除编码卷之间的区别,以及如何处理它。
图 6:擦除编码
擦除编码可以降低复制成本,并保持与复制相似的持久性。在我们的系统中,当一个卷快满了的时候,它就会关闭,就可以进行擦除编码。我们使用了一个擦除码,就像Reed-Solomon误码校正编码(6,3),在一个卷组中有 6 个 OSD 和 3 个奇偶校验位。这是说,在一个数据区段中只有一个 Blob,如果一个 OSD 出现故障,则可以重建它。重建可以发生在对数据的实时请求中,也可以作为修复的一部分在后台完成。擦除码有许多变体,它们在开销方面有各自的考量,例如,使用 XOR 作为擦除码可能很简单,但自定义擦除码可能更合用。
图 7:故障和擦除编码
关于这个主题,Huang 等人的论文“Windows Azure存储中的擦除编码”是一份不错的资源,我们的系统就使用了类似的技术。
图 8:Huang 等人的论文“Windows Azure存储中的擦除编码”中的 Reed-Solomon 误码校正编码
我在前面的例子中提到过的 Reed-Solomon 纠错码(6,3),有 6 个数据区段和 3 个奇偶校验位。另一个选项为本地重建代码,它优化了读取成本。Reed-Solomon 纠错码(6,3)在出现任何故障时都要读取 6 次。但是,使用本地重建代码,对于同一类型的数据故障,虽然读取成本相同,但是与 Reed Solomon 的 1.5 倍复制因子相比,存储开销大约降低了 1.33 倍。虽然这看起来差别不大,但当规模比较大时,却可以节省大量的资金。
图 9:Huang 等人的论文“Windows Azure存储中的擦除编码”中的重建代码比较
本地重建代码针对组中出现一个故障的情况做了优化,生产环境中经常会遇到这种情况。做出这种权衡是可以接受的,因为在一个卷组中出现 2 个以上故障的情况很少见。
这些编码的复制因子甚至可以更低:编码 LRC-(12,2,2)可以容忍组内有三个故障,但不能容忍四个,此时只有部分故障可以重建。
冷存储系统
我们的系统还能做得更好吗?正如我们观察到的那样,90%的检索是针对去年上传的数据,80%的检索发生在前 100 天内,我们正在探索改进跨区域复制的方法。
图 10:文件访问分布
我们有大量不经常访问的冷数据,因此,我们希望优化工作负载,减少读取,并保持延迟、持久性和可用性基本不变。根据我们的观察,为了实现这一点,我们不必对冷存储进行实时写入,并且可以利用多个区域将复制因子降至 2x 以下。
让我们看一下我们的冷存储系统是如何工作的,其灵感来自 Facebook 的暖Blob存储系统。这篇有关 f4 的论文提出了一种方法,将一个 Blob 分成两半(分别存储在不同的区域),并对这两半做XOR。要检索完整的 Blob,Blob1 和 Blob2 的任意组合或 XOR 就必须在任意两个区域中可用。但是,要执行写入操作,所有区域都需要完全可用。请注意,由于迁移是在后台异步进行的,所以它们不会影响实时进程。
图 11:分割 Blob 和冷存储
这种冷存储系统有什么好处呢?通过将复制因子从 2x 降低到 1.5x,我们节省了 25%的成本。存储在冷存储中的片段仍然会在内部进行擦除编码,并且迁移是在后台进行的。为了减少主干带宽的开销,我们将请求发送到两个最近的区域,并且只在必要的时候才从其他区域获取。这又节省了大量的带宽。
发布周期
Magic Pocket 是如何发布的?从所有过渡环境到生产环境,我们的发布周期大约为四周。
图 12:Magic Pocket 的发布周期
在提交更改之前,我们会运行一系列单元测试和集成测试,包含所有的依赖项,以及一个对所有数据进行全面验证的持久性阶段。每个区域在每个阶段都会进行大约一周的验证:我们的发布周期是完全自动化的,它会做适当的检查,如果有任何警告,它就会中止或不再继续更改代码。只有在特殊情况下,我们才会停止自动部署过程,并人为干预。
验证
那么验证呢?在系统内部,为了确保数据的准确性,我们做了大量的验证。
图 13:验证
其中一项是由跨区域验证器执行的,它负责在上游客户端和系统之间同步数据映射。另一个是索引验证器,它会扫描索引表,确认每台存储机中是否存在特定的 Blob:我们只是询问存储机已加载的区段询中是否有这个 Blob,而不获取实际的内容。观察器是另一个会对 Blob 本身进行全面验证的组件,按分钟、小时、天和周进行采样。我们还有一个垃圾检查器,确保区段被删除后,其中的所有散列都会被删除。
运营
因为 Magic Pocket 跨多个数据中心,所以我们要处理大量的迁移。我们管理着一个非常大的存储机机群,知道每时每刻都发生了什么非常重要。混乱时有发生,我们会通过大量的灾难恢复活动来测试系统的可靠性:升级这种规模的系统和系统本身一样困难。管理后台流量是我们的关键运营工作之一,因为那占用了我们大部分的流量和磁盘 IOPS。磁盘洗涤器不间断地扫描所有流量并检查区段的校验和。我们根据业务将流量划分为不同的层,并根据网络情况对实时流量做优先级排序。
控制平面会根据我们对数据中心迁移所做的预测来规划大量的后台流量:我们会考虑正在进行的迁移类型,如冷存储,并相应地制定计划。
系统中有许多故障需要我们处理:我们每秒要修复 4 个区段,大小从 1GB 到 2GB 不等。我们有相当严格的 SLA(少于 48 小时),因为那是我们持久性模型的组成部分,我们希望尽可能地缩短修复时间。OSD 会根据单元格的大小和当前的利用率自动分配到系统中。
我们也有很多向不同数据中心的迁移。
图 14:迁移
两年前,我们迁出了 SJC 地区,为此我们做了大量的计划。对于非常大的迁移,比如数百个 PB,幕后会有大量的准备工作,我们会给自己额外留出时间,以确保迁移能够及时完成。
预测
在管理这种规模的存储系统时,预测是一个很关键的部分。我们一直在应对存储增长的挑战,有时可能是意料之外的,那就需要我们能够快速做出调整并将新的数据接收到我们的系统中。此外,我们可能会因为供应链中断(如 COVID 大流行造成的供应链中断)而面临容量问题:一旦发现潜在的问题,我们就会开始制定备份计划,因为订购并向数据中心交付新容量需要相当长的时间。我们的预测直接集成到了控制平面中,这有助于我们根据容量团队提供的信息执行迁移。
小结
在维护 Magic Pocket 的过程中,我们总结出了以下 4 条关键的经验:
保护和验证
规模比较大时要慢慢来
保持简单
做最坏的打算
首先,我们要优先考虑系统的保护和验证。这需要大量的开销,但端到端验证对于确保一致性和可靠性至关重要。
在这种规模下,要慢慢来,稳定很重要。我们要优先考虑持久性,部署任何新内容之前都要等待验证完成。我们总是会考虑风险,为最坏的情况做准备。
简单性也是一个关键因素。我们的目标是保持简单,特别是在大规模迁移期间,因为过多的优化可能会导致复杂的心智模型,增加计划和调试的难度。
此外,我们总会准备一个备份计划,以防在迁移或部署期间出现故障或问题。我们会确保变更不是单向的,必要时可以逆转。总体而言,管理这种规模的存储系统需要综合考量保护、验证、简单性和准备工作等诸多方面。
原文链接:
https://www.infoq.com/articles/dropbox-magic-pocket-exabyte-storage/
评论