在 Google 早期开发阶段,最初的想法不包括构建新文件系统的计划。然而,当仍在进行公司爬网和索引系统的最早版本之一的工作时,核心工程师们非常清楚地意识到他们真的别无选择,GFS(Google 文件系统)由此诞生。
首先,考虑到 Google 的目标是利用廉价的商用硬件构建庞大的存储网络,因此必须假定组件故障将是常态——这意味着持续监控、错误检测、容错和自动恢复必须成为文件系统不可或缺的一部分。此外,即使按照 Google 最早的估计,该系统的吞吐量要求也将是任何人看来都令人生畏的——具有千兆字节的文件和包含太字节信息和数百万对象的数据集。显然,这意味着必须重新审视关于 I/O 操作和块大小的传统假设。还存在可扩展性问题。这是一个肯定需要像其他任何系统一样扩展的文件系统。当然,在最早的那些日子里,没有人能够想象到需要多少可扩展性。他们很快就会了解到这一点。
尽管如此,近十年后,Google 大部分令人难以置信的数据存储及其不断增长的应用程序阵列继续依赖 GFS。在此过程中,文件系统进行了许多调整,并且在应用程序内部实施了相当多的调整,这些调整共同促成了这一历程的实现。
为了探讨一些更关键的初始设计决策背后的原因,以及此后进行的一些增量调整, 请肖恩·奎因兰揭示不断变化的文件系统需求和 Google 不断发展的想法。由于奎因兰曾担任 GFS 技术主管几年,并且现在继续担任 Google 的首席工程师,因此他有资格提供这种视角。为了在 Googleplex 之外找到立足点, 请柯克·麦库斯克主持了讨论。他以其在 BSD(伯克利软件发行版)Unix 上的工作而闻名,包括伯克利 FFS(快速文件系统)的原始设计。
讨论从一开始就恰如其分地开始——基于单主设计的初始 GFS 实现的非正统决策。乍一看,单个集中式主节点成为带宽瓶颈的风险,或者更糟糕的是,成为单点故障的风险似乎显而易见,但事实证明,Google 的工程师们有理由做出这个选择。
MCKUSICK 最初 GFS 架构中更令人感兴趣且意义重大的方面之一是决定将其基于单个主节点。您能带我们了解一下导致这一决定的原因吗?
QUINLAN 采用单主节点的决定实际上是最早的决定之一,主要是为了简化总体设计问题。也就是说,从一开始就构建分布式主节点被认为太困难,并且会花费太多时间。此外,通过采用单主节点方法,工程师们能够简化许多问题。拥有一个中央位置来控制复制和垃圾回收以及许多其他活动,肯定比在分布式基础上处理所有这些问题要简单得多。因此,决定将这些集中在一台机器中。
MCKUSICK 这主要是为了能够在合理的时间框架内推出一些东西吗?
QUINLAN 是的。事实上,参与早期工作的一些工程师后来继续构建了 BigTable,一个分布式存储系统,但这项工作花费了多年时间。围绕单主节点构建原始 GFS 的决定确实有助于比其他任何方式更快地将一些东西交付到用户手中。
此外,在勾勒出他们预期的用例时,单主节点设计似乎不会造成太多问题。他们当时考虑的规模是以数百太字节和数百万个文件来衡量的。事实上,该系统最初运行良好。
MCKUSICK 但后来发生了什么?
QUINLAN 一旦底层存储的大小增加,问题就开始出现。从几百太字节增加到拍字节,然后再增加到数十拍字节… 这确实需要主节点必须维护的元数据量成比例增加。此外,扫描元数据以查找恢复等操作都与数据量呈线性关系。因此,主节点所需的工作量大幅增加。保留所有这些信息所需的存储量也增加了。
此外,这被证明是客户端的瓶颈,即使客户端本身发出的元数据操作很少——例如,客户端在执行打开操作时会与主节点通信。当有数千个客户端同时与主节点通信时,考虑到主节点每秒只能执行几千次操作,平均客户端每秒无法指挥那么多操作。还要记住,有些应用程序(如 MapReduce)可能会突然有数千个任务,每个任务都想打开许多文件。显然,处理所有这些请求需要很长时间,并且主节点将承受相当大的压力。
MCKUSICK 现在,在当前的 GFS 架构下,每个单元格都有一个主节点,对吗?
QUINLAN 是的,没错。
MCKUSICK 从历史上看,每个数据中心都有一个单元格,对吗?
QUINLAN 最初的目标是这样,但它并没有像那样广泛地实现——部分原因是单主节点设计的局限性,部分原因是隔离被证明是困难的。因此,人们通常最终在每个数据中心拥有多个单元格。我们最终也做了我们所谓的“多单元格”方法,这基本上使得在块服务器池之上放置多个 GFS 主节点成为可能。这样,可以将块服务器配置为分配给它们,例如,八个 GFS 主节点,这将为您提供至少一个底层存储池——如果愿意,可以使用多个主节点头。然后,应用程序负责跨这些不同的单元格对数据进行分区。
MCKUSICK 大概每个应用程序基本上都有自己的主节点,负责管理自己的小文件系统。基本上是这个想法吗?
QUINLAN 嗯,是的,也不是。应用程序倾向于使用一个主节点或一小组主节点。我们还有一些称为命名空间的东西,这只是一种非常静态的方式来划分命名空间,人们可以使用它来向实际应用程序隐藏所有这些。日志处理系统提供了这种方法的一个示例:一旦日志耗尽了仅使用一个单元格的能力,它们就会移动到多个 GFS 单元格;命名空间文件描述了日志数据如何在这些不同的单元格之间进行分区,并且基本上用于向应用程序隐藏确切的分区。但这都是相当静态的。
MCKUSICK 考虑到所有这些,性能如何?
QUINLAN 我们最终投入了相当多的精力来调整主节点性能,并且 Google 通常不会花费大量精力来调整任何特定的二进制文件。一般来说,我们的方法是让事情运行得相当好,然后将注意力转向可扩展性——这通常效果很好,因为您通常可以通过扩展事物来恢复性能。然而,在这种情况下,我们有一个单一的瓶颈开始对操作产生影响,因此我们认为投入一些额外的努力来减轻主节点的重量将是非常值得的。在从数千次操作扩展到数万次甚至更多次的过程中,单主节点在某种程度上变得不那么像瓶颈了。在那种情况下,更多地关注一个二进制文件的效率绝对有助于使 GFS 比原本可能的情况持续更长时间。
可以认为,在创纪录的时间内使 GFS 准备好投入生产本身就是一场胜利,并且通过加速 Google 进入市场,这最终极大地促进了公司的成功。一个三人团队负责所有这些工作——GFS 的核心——并使系统在不到一年的时间内准备好部署。
但随后就出现了任何成功系统经常遭受的代价——也就是说,一旦规模和用例有时间扩展到远远超出任何人可能想象的范围。在 Google 的案例中,这些压力被证明特别强烈。
尽管组织机构没有交换文件系统统计信息的习惯,但可以肯定地假设 GFS 是运行中最大的文件系统(事实上,即使在 Google 收购 YouTube 之前,情况可能也是如此)。因此,即使 GFS 的原始架构师认为他们已经充分考虑了至少两个数量级的增长,但 Google 很快就超越了这一点。
此外,GFS 需要支持的应用程序数量很快就激增了。在对 GFS 的原始架构师之一霍华德·戈比奥夫(Howard Gobioff)(在他 2008 年初意外去世前不久进行的采访中)的采访中,他回忆说:“我们最早的所有 GFS 版本的原始消费者基本上是这个庞大的爬网和索引系统。第二波浪潮发生在我们的质量团队和研究小组开始非常积极地使用 GFS 时——基本上,他们都希望使用 GFS 来存储大型数据集。然后,不久之后,我们有了 50 个用户,他们都需要不时地提供一些支持,以便他们都能够彼此友好相处。”
一个非常有帮助的方面是,Google 不仅构建了文件系统,还构建了在其之上运行的所有应用程序。虽然 GFS 不断进行调整以使其更适应所有新的用例,但应用程序本身在开发时也考虑到了 GFS 的各种优势和劣势。“因为我们构建了一切,所以我们可以随时随地作弊,”戈比奥夫简洁地总结道。“我们可以将问题在应用程序空间和文件系统空间之间来回推,然后找出两者之间的折衷方案。”
然而,纯粹的规模问题需要进行一些更实质性的调整。一种应对策略与在网络上使用多个“单元格”有关,这些单元格基本上充当相关但不同的文件系统。除了帮助解决眼前的规模问题外,这还被证明是广泛分散的数据中心运营的更有效安排。
快速增长也给原始 GFS 设计的另一个关键参数带来了压力:选择将 64 MB 作为标准块大小。当然,这比典型的文件系统块大小大得多,但这仅仅是因为 Google 的爬网和索引系统生成的文件异常大。然而,随着应用程序组合随时间变化,必须找到方法来让系统有效地处理大量远小于 64 MB 的文件(例如,考虑 Gmail)。问题不在于文件本身的数量,而在于所有这些文件对集中式主节点的内存需求,从而暴露了原始 GFS 设计中固有的瓶颈风险之一。
MCKUSICK 我从最初的 GFS 论文[Ghemawat, S., Gobioff, H., Leung, S-T. 2003. The Google File System. SOSP ( Symposium on Operating Systems Principles)]中了解到,文件计数一直是你们长期以来的一个重要问题。您能详细说明一下吗?
QUINLAN 文件计数问题很早就出现了,因为人们最终围绕 GFS 设计系统的方式。让我举一个具体的例子。在我在 Google 的早期,我参与了日志处理系统的设计。我们最初有一个模型,其中前端服务器会写入日志,然后我们基本上将其复制到 GFS 中进行处理和存档。最初这很好,但后来前端服务器的数量增加了,每个服务器每天都会滚动日志。与此同时,日志类型的数量也在增加,然后您就会有前端服务器经历崩溃循环并生成更多日志。因此,我们最终得到的文件数量比我们根据最初的粗略估计预期的要多得多。
这成为我们真正需要密切关注的领域。最后,我们不得不承认,我们无法在文件计数持续增长的情况下生存下去。
MCKUSICK 让我确保我理解正确:您对文件计数增长的问题是由于您需要在主节点上为每个文件保留一块元数据,并且该元数据必须适合主节点的内存。
QUINLAN 是的,没错。
MCKUSICK 并且在主节点内存耗尽之前,您可以容纳的文件数量是有限的?
QUINLAN 完全正确。并且有两部分元数据。一部分标识文件,另一部分指出支持该文件的块。如果一个块仅包含 1 MB,则它将仅占用 1 MB 的磁盘空间,但它仍然需要在主节点上使用这两部分元数据。如果您的平均文件大小最终低于 64 MB,则主节点上的对象数量与存储中的对象数量之比开始下降。这就是您遇到问题的地方。
回到日志示例,很快就显而易见,我们最初想到的自然映射——并且在我们进行粗略估计时似乎很有意义——结果完全不可接受。我们需要找到一种方法来解决这个问题,方法是找出如何将一些底层对象组合成更大的文件。对于日志而言,这并不完全是火箭科学,但确实需要付出很多努力。
MCKUSICK 这听起来像是 IBM 只有最小磁盘分配的旧时代,因此它为您提供了一个实用程序,让您可以将一堆文件打包在一起,然后为该文件创建目录。
QUINLAN 完全正确。对于我们来说,每个应用程序最终都在不同程度上这样做。事实证明,对于某些应用程序来说,这比其他应用程序负担更轻。就我们的日志而言,我们并没有真正计划删除单个日志文件。更有可能的是,我们将最终重写日志以对其进行匿名化或进行其他类似操作。这样,您就不会遇到垃圾回收问题,如果您仅删除捆绑包中的某些文件,则可能会出现垃圾回收问题。
然而,对于其他一些应用程序,文件计数问题更为严重。很多时候,某些应用程序最自然的设计根本不适合 GFS——即使乍一看您会认为文件计数完全可以接受,但结果证明这是一个问题。当我们开始使用更多共享单元格时,我们对文件计数和存储空间都设置了配额。人们最终遇到最多的限制是文件计数配额,到目前为止。相比之下,底层存储配额很少被证明是一个问题。
MCKUSICK 为了解决文件计数问题,您提出了哪些长期策略?当然,如果主节点仍然必须将所有元数据保存在内存中,那么分布式主节点似乎真的无法对此有所帮助。
QUINLAN 分布式主节点当然允许您增加文件计数,这与您愿意投入的机器数量成正比。
分布式多主节点模型的吸引力之一是,如果您将所有内容扩大两个数量级,那么平均文件大小降至 1 MB 将与平均文件大小为 64 MB 大不相同。如果您最终低于 1 MB,那么您还会遇到其他问题,您真的需要小心。例如,如果您最终必须读取 10,000 个 10 KB 的文件,那么您将比仅读取 100 个 1 MB 的文件进行更多的寻道操作。
我的直觉是,如果您为平均 1 MB 的文件大小进行设计,那么它应该比假设平均文件大小为 64 MB 的设计提供更广泛的用途。理想情况下,您希望想象一个可以一直降至更小文件大小的系统,但在我们的环境中,1 MB 似乎是一个合理的折衷方案。
MCKUSICK 为了使 GFS 与 1 MB 文件一起工作,您一直在做什么?
QUINLAN 我们没有对现有的 GFS 设计做任何事情。我们将提供 1 MB 文件的分布式主节点系统本质上是一个全新的设计。这样,我们可以将目标定为每个主节点大约 1 亿个文件。您也可以拥有数百个主节点。
MCKUSICK 那么,基本上没有单个主节点会拥有所有这些数据?
QUINLAN 就是这个想法。
随着 BigTable(Google 内部最近出现的用于管理结构化数据的分布式存储系统)的出现,文件计数问题的一个潜在解决方案(尽管可能不是最好的解决方案)现在已经可用。
然而,BigTable 的意义远远超出文件计数。具体而言,它旨在跨数百或数千台机器扩展到拍字节范围,并使向系统添加更多机器并自动开始利用这些资源而无需重新配置变得容易。对于一家基于利用大规模部署商用硬件中固有的集体力量、潜在冗余和规模经济的概念的公司来说,这些确实被认为是重要的优势。
因此,BigTable 现在与越来越多的 Google 应用程序结合使用。尽管它在某种程度上代表了与过去的背离,但也必须说 BigTable 是在 GFS 之上构建的,在 GFS 上运行,并且有意识地设计为与大多数 GFS 原则保持一致。因此,可以将其视为沿途进行的主要调整之一,以帮助 GFS 在快速和广泛的变化面前保持可行性。
MCKUSICK 你们现在有了这个叫做 BigTable 的东西。您是否将其视为一个独立的应用程序?
QUINLAN 从 GFS 的角度来看,它是一个应用程序,但它显然更像是一个基础设施组件。
MCKUSICK 如果我理解正确,BigTable 本质上是一个轻量级关系数据库。
QUINLAN 它实际上不是一个关系数据库。我的意思是,我们没有做 SQL,它实际上不支持连接等。但 BigTable 是一个结构化存储系统,可让您拥有大量键值对和一个架构。
MCKUSICK BigTable 的真正客户是谁?
QUINLAN BigTable 越来越多地在 Google 内部用于爬网和索引系统,并且我们在许多面向客户端的应用程序中大量使用它。事实是,有大量的 BigTable 客户端。基本上,任何具有大量小数据项的应用程序都倾向于使用 BigTable。在存在相当结构化数据的地方尤其如此。
MCKUSICK 我想我真正想提出的问题是:BigTable 是否只是作为一种尝试来解决小文件问题而陷入了许多这些应用程序中,基本上是通过将一大堆小东西聚合在一起?
QUINLAN 这当然是 BigTable 的一个用例,但它实际上是为更一般类型的问题而设计的。如果您以这种方式使用 BigTable——也就是说,作为一种解决文件计数问题的方法,否则您可能会使用文件系统来处理该问题——那么您将不会最终使用 BigTable 的所有功能。BigTable 实际上并不适合该目的,因为它需要资源来进行自身的非平凡操作。此外,它有一个并非超级激进的垃圾回收策略,因此这可能不是最有效利用空间的方式。我想说,纯粹使用 BigTable 来处理文件计数问题的人可能不太高兴,但毫无疑问,这是人们处理该问题的一种方式。
MCKUSICK 我读到的关于 GFS 的内容似乎表明,其想法是只拥有两个基本数据结构:日志和 SSTable(排序字符串表)。由于我猜 SSTable 必须用于处理键值对以及类似的东西,那么这与 BigTable 有何不同?
QUINLAN 主要区别在于 SSTable 是不可变的,而 BigTable 提供可变的键值存储,以及更多功能。BigTable 本身实际上是建立在日志和 SSTable 之上的。最初,它将传入数据存储到事务日志文件中。然后它被压缩——我们称之为——成一系列 SSTable,而 SSTable 又随着时间的推移被压缩在一起。在某些方面,它让人想起日志结构文件系统。无论如何,正如您所观察到的,日志和 SSTable 似乎是我们构建大多数数据结构的方式的两个数据结构。我们有用于记录可变内容的日志文件。然后,一旦您拥有足够的日志文件,您就可以对其进行排序并将其放入具有索引的结构中。
即使 GFS 没有提供 Posix 接口,它仍然有一个非常通用的文件系统接口,因此人们基本上可以自由地编写他们喜欢的任何类型的数据。只是随着时间的推移,我们的大多数用户最终都使用了这两种数据结构。我们还有一种叫做协议缓冲区的东西,这是我们的数据描述语言。大多数数据最终都以协议缓冲区的形式存在于这两种结构中。
两者都提供压缩和校验和。即使内部有些人最终会重新发明这些东西,但大多数人还是满足于使用这两种基本构建块。
由于 GFS 最初旨在支持爬网和索引系统,因此吞吐量至关重要。事实上,关于该系统的原始论文明确指出:“持续高带宽比低延迟更重要。我们的大多数目标应用程序都非常重视以高速率批量处理数据,而很少有应用程序对单个读写操作有严格的响应时间要求。”
但是,Google 要么开发要么采用了许多面向用户的互联网服务,对于这些服务而言,情况肯定不是这样。
这立即暴露了 GFS 的一个缺点,与原始的单主节点设计有关。单点故障可能对面向批处理的应用程序来说不是灾难,但对于延迟敏感型应用程序(如视频服务)来说肯定是不可接受的。后来添加的自动故障转移功能有所帮助,但即使如此,服务也可能会中断长达一分钟。
当然,GFS 的另一个主要挑战围绕着如何基于围绕完全不同的一组优先级设计的文件系统构建延迟敏感型应用程序。
MCKUSICK 众所周知,GFS 设计的最初重点是批处理效率,而不是低延迟。现在这已经反过来给您带来了麻烦,尤其是在处理视频等内容方面。您是如何处理的?
QUINLAN GFS 设计模型的出发点完全是为了实现吞吐量,而不是实现吞吐量的延迟。举一个具体的例子,如果您要写入文件,它通常会以三份副本的形式写入——这意味着您实际上将写入三个块服务器。如果其中一个块服务器死机或长时间打嗝,GFS 主节点将注意到问题并调度我们所谓的 pullchunk,这意味着它基本上会复制其中一个块。这将使您恢复到三个副本,然后系统会将控制权传递回客户端,客户端将继续写入。
当我们执行 pullchunk 时,我们将其限制在每秒 5-10 MB 的范围内。因此,对于 64 MB,您谈论的是此恢复需要 10 秒钟才能完成。还有许多其他类似的事情可能需要 10 秒到一分钟,这对于批处理类型的操作来说效果很好。如果您正在进行大型 MapReduce 操作,只要其中一项不是真正的落后者,您就可以正常工作,在这种情况下,您会遇到另一种问题。尽管如此,一般来说,在一个小时的批处理作业过程中,一分钟左右的打嗝实际上不会显现出来。但是,如果您正在处理 Gmail,并且您正在尝试写入代表某些用户操作的突变,那么卡住一分钟真的会让您感到困惑。
我们的主节点故障转移也遇到了类似的问题。最初,GFS 没有自动主节点故障转移的规定。这是一个手动过程。虽然这种情况发生得不多,但每当发生时,单元格可能会停机一个小时。即使我们最初的主节点故障转移实现也需要几分钟的时间。然而,在过去一年中,我们已将其缩短至大约几十秒。
MCKUSICK 尽管如此,对于面向用户的应用程序来说,这是不可接受的。
QUINLAN 是的。虽然这些实例——您必须提供故障转移和错误恢复——在批处理情况下可能是可以接受的,但从面向用户的应用程序的延迟角度来看,它们绝对是不可接受的。这里的另一个问题是,在设计中的某些地方,我们试图通过将数千个操作转储到一个队列中,然后仅处理它们来优化吞吐量。这导致了良好的吞吐量,但对于延迟来说却不太好。您很容易陷入这种情况,即您可能会在队列中卡住几秒钟,只是为了等待到达队列的头部。
我们的用户群肯定已经从基于 MapReduce 的世界迁移到更多依赖 BigTable 等事物的交互式世界。Gmail 就是一个明显的例子。就 GFS 而言,视频并没有那么糟糕,因为您可以流式传输数据,这意味着您可以缓冲。尽管如此,尝试在从一开始就旨在支持更多面向批处理的操作的文件系统之上构建交互式数据库肯定已被证明是一个痛点。
MCKUSICK 您究竟是如何设法处理这个问题的?
QUINLAN 在 GFS 内部,我们已设法在一定程度上改进了情况,主要是通过设计应用程序来处理出现的问题。以 BigTable 为例,这是一个很好的具体例子。BigTable 事务日志实际上是记录事务的最大瓶颈。实际上,我们决定,“好吧,我们将在这些写入中看到打嗝,所以我们要做的是一次打开两个日志。然后我们基本上只需合并这两个日志。我们将写入一个日志,如果该日志卡住,我们将写入另一个日志。一旦我们进行重播,我们将合并这些日志——如果我们需要进行重播,就是这样。”我们倾向于像这样设计我们的应用程序——也就是说,它们基本上试图隐藏延迟,因为它们知道底层的系统实际上并不是那么好。
构建 Gmail 的人采用了多宿主模型,因此如果您的 Gmail 帐户的一个实例卡住了,您基本上会被转移到另一个数据中心。实际上,无论如何都需要此功能来确保可用性。尽管如此,部分动机是他们想隐藏 GFS 问题。
MCKUSICK 我认为可以公平地说,通过迁移到分布式主节点文件系统,您肯定能够解决其中的一些延迟问题。
QUINLAN 这当然是我们的设计目标之一。此外,BigTable 本身是一个非常了解故障的系统,它试图比我们以前更快地响应故障。使用它作为我们的元数据存储也有助于解决其中的一些延迟问题。
从事最早版本的 GFS 工作的工程师在偏离传统的文件系统设计选择时,如果他们认为有必要这样做,他们并不特别害羞。恰好,一致性方法是该系统中特别明显的方面之一。
当然,这部分是出于必要性。由于 Google 的计划在很大程度上依赖于大规模部署商用硬件,因此故障和硬件相关故障是必然的。除此之外,根据最初的 GFS 论文,还存在一些兼容性问题。“我们的许多磁盘向 Linux 驱动程序声称它们支持一系列 IDE 协议版本,但实际上只有更新的版本才能可靠地响应。由于协议版本非常相似,因此这些驱动器大多可以工作,但有时不匹配会导致驱动器和内核在驱动器状态上产生分歧。由于内核中的问题,这会悄无声息地损坏数据。这个问题促使我们使用校验和来检测数据损坏。”
然而,这不仅仅意味着任何校验和,而是严格的端到端校验和,着眼于从磁盘损坏到 TCP/IP 损坏再到机器背板损坏的一切。
有趣的是,尽管进行了所有校验和监督,但 GFS 工程团队也选择了一种在文件系统标准中相对宽松的一致性方法。基本上,GFS 只是接受有时人们最终会读取略微陈旧的数据。由于 GFS 主要用作仅附加系统而不是覆盖系统,因此这通常意味着这些人最终可能会错过在他们已经打开文件后附加到文件末尾的内容。对于 GFS 设计人员来说,这似乎是可以接受的成本(尽管事实证明,对于某些应用程序而言,这会带来问题)。
此外,正如戈比奥夫解释的那样,“在某些情况下,陈旧数据的风险只是高度分布式架构固有的,该架构不要求主节点维护那么多信息。如果我们愿意将更多数据转储到主节点中,然后让它维护更多状态,我们肯定可以使事情变得更加严格。但这对我们来说真的不是那么重要。”
也许这里更重要的问题是,做出此决定的工程师不仅拥有文件系统,而且还拥有旨在在文件系统上运行的应用程序。根据戈比奥夫的说法,“问题是我们同时控制了水平和垂直——文件系统和应用程序。因此,我们可以确保我们的应用程序知道对文件系统有什么期望。我们只是决定将一些复杂性推给应用程序,让他们来处理。”
尽管如此,Google 内部仍有人怀疑这是否是正确的决定,仅仅是因为人们有时在多次读取给定文件的过程中可能会获得不同的数据,这往往与他们对数据存储应该如何工作的整体概念背道而驰。
MCKUSICK 让我们谈谈一致性。问题似乎是,将所有内容完全写入所有副本可能需要一些时间。我认为您早些时候说过,GFS 本质上要求在您可以继续之前,所有这些都必须完全写入。
QUINLAN 是的,没错。
MCKUSICK 如果是那样的话,那么你怎么可能最终得到不一致的东西呢?
QUINLAN 客户端故障总有办法把事情搞砸。基本上,GFS 中的模型是客户端会持续推送写入操作直到成功。如果客户端在操作过程中崩溃了,事情就会处于一种不确定的状态。
早期,这在某种程度上被认为是没问题的,但随着时间的推移,我们收紧了对这种不一致性能容忍的时间窗口,然后我们慢慢地继续减少这个窗口。否则,每当数据处于不一致状态时,你可能会得到不同的文件长度。这可能会导致一些混乱。在这些情况下,我们不得不设置一些后门接口来检查文件数据的一致性。我们还有一种叫做 RecordAppend 的东西,它是一个为多个写入器并发追加到日志而设计的接口。那里的数据一致性被设计得非常宽松。事后看来,这被证明比任何人预期的都要痛苦得多。
MCKUSICK 到底有多宽松?如果主副本为每次写入选择偏移量,然后确保实际发生写入,我不明白不一致性会从哪里来。
QUINLAN 实际发生的情况是,主副本会尝试。它会选择一个偏移量,它会执行写入操作,但其中一个可能实际上没有被写入。然后主副本可能会改变,这时它可以选择不同的偏移量。RecordAppend 也不提供任何重放保护。你最终可能会在文件中多次获得相同的数据。
甚至在某些情况下,你可能会以不同的顺序获得数据。它可能会在一个块副本中出现多次,但不一定在所有副本中都出现。如果你正在读取文件,你可能会在不同的时间以不同的方式发现数据。在记录级别,你可能会根据你恰好读取的块,以不同的顺序发现记录。
MCKUSICK 这是有意设计的吗?
QUINLAN 当时,这一定看起来是个好主意,但事后看来,我认为大家的共识是,它被证明比它带来的价值更痛苦。它只是不符合人们对文件系统的期望,所以他们最终会感到惊讶。然后他们不得不找出解决办法。
MCKUSICK 事后看来,你会如何以不同的方式处理这个问题?
QUINLAN 我认为为每个文件设置一个单独的写入器更有意义。
MCKUSICK 好的,但是当有多个人想要追加到日志时会发生什么?
QUINLAN 你通过一个可以确保副本一致性的单一进程来序列化写入操作。
MCKUSICK 还有这个业务,你基本上对一个块进行快照。据推测,当你基本上要替换一个副本,或者当某个 chunkserver 宕机并且你需要替换它的一些文件时,你会使用它。
QUINLAN 实际上,那里有两件事正在发生。一个,正如你所建议的,是恢复机制,这绝对涉及到复制文件副本。GFS 中的工作方式是,我们基本上撤销锁,这样客户端就不能再写入它了,这是我们之前谈到的延迟问题的一部分。
还有一个单独的问题,那就是支持 GFS 的快照功能。GFS 拥有你能想象到的最通用的快照能力。你可以将任何目录快照到某个地方,然后两个副本将完全等效。它们将共享未更改的数据。你可以更改其中任何一个,并且你可以进一步快照其中任何一个。所以它实际上更像是一个克隆,而不是大多数人认为的快照。这是一件有趣的事情,但它会带来困难——特别是当你试图构建更分布式的系统,并且你可能想要快照文件树的更大块时。
我还认为有趣的是,快照功能并没有被更多地使用,因为它实际上是一个非常强大的功能。也就是说,从文件系统的角度来看,它确实提供了一个非常好的功能。但是将快照放入文件系统中,我相信你知道,真是一件痛苦的事情。
MCKUSICK: 我知道。我做过。这非常痛苦——尤其是在覆盖型文件系统中。
QUINLAN 完全正确。这是我们没有作弊的一个例子,但从实现的角度来看,创建真正的快照是很难的。尽管如此,在这种情况下,全力以赴似乎是正确的决定。尽管如此,这与早期在语义方面做出的一些其他决定形成了有趣的对比。
总而言之,GFS 近 10 年后的成绩单似乎是积极的。肯定存在问题和缺点,但毫无疑问谷歌的成功,GFS 在其中无疑发挥了重要作用。更重要的是,考虑到谷歌的运营规模已经超出系统最初设计处理能力的几个数量级,而谷歌目前支持的应用程序组合也不是任何人能在 90 年代末期想象到的,它的持久力简直是非凡的。
尽管如此,毫无疑问,GFS 现在面临着许多挑战。首先,在一个最初为批处理系统吞吐量设计的系统之上,支持不断增长的面向用户的、对延迟敏感的应用程序的笨拙性是所有人显而易见的。
BigTable 的出现在这方面有所帮助。然而,事实证明,BigTable 实际上并不完全适合 GFS。事实上,它只是让系统单主设计的瓶颈限制比原本情况更明显。
由于这些和其他原因,谷歌的工程师们在过去两年中的大部分时间里一直在开发一个新的分布式主系统,旨在充分利用 BigTable 来解决那些已被证明对 GFS 特别困难的问题。
因此,现在看来,除了为确保 GFS 的持续生存而做出的所有调整之外,进化树上的最新分支将在未来几年继续发展壮大。
问
喜欢它,讨厌它?请告诉我们
© 2009 1542-7730/09/0800 $10.00
最初发表于 Queue vol. 7, no. 7—
在 数字图书馆 中评论这篇文章