云端磁盘:网络巨头如何存储数据(上)

DOSTOR存储在线 4月9日国际报道:细想支持谷歌主页搜索框需要的技术:背后的算法,缓存的搜索词,和其他一些随之而来的特性,比如当你输入一个位于数据存储中的查询时,基本相当于绝大多数网络的一个全文本快照。当你和成千上万的其他人同时提交搜索时,这个快照也正在不断地随着这些变化被更新着。与此同时,数据是由数以千计的独立服务器进程处理的,每个都各司其职,从计算出给你提供的相关联广告,到决定搜索结果的排列顺序。

支持谷歌搜索引擎的存储系统必须能够承受每天由运行于数以千计的服务器上的成千上万的独立进程所发出的数百万计的读写请求,几乎不能停机来备份或维护,还必须不断扩容以容纳由谷歌网页抓取机器人添加的日益扩大的众多页面。总体下来,谷歌每天要处理超过20PB。

这可不是谷歌可以从一个现成的存储架构就能完成的。而且对于运行超大规模的数据中心的其他网络和云计算巨头来说也是如此,比如亚马逊和Facebook。虽然大多数数据中心已经通过在一个存储区网络添加更多硬盘容量来解决扩充存储的问题,更多的存储服务器,通常是更多的数据库服务器,因为云环境的性能限制,这些方法却失效了。在云环境下,任何时候都可能有成千上万的活跃用户的数据,而且数据的读写在任何时刻都能达到数千TB。

这不仅仅是一个关于磁盘读写速度的简单问题。以这些卷上的数据流来讲,主要的问题是存储网络的吞吐量;即使有最好的交换机和存储服务器,传统的SAN架构也能成为数据处理的性能瓶颈。

接下来就是老生常谈的扩大存储的成本问题。超大规模网络公司增加容量的频率(举个例子,亚马逊现在每天为其数据中心增加的容量相当于整个公司在2001年全年的容量,根据亚马逊副总裁杰姆斯·汉密尔顿的说法),用大多数数据中心的同样做法来摆平所需的存储,依照所需的管理,硬件和软件成本,花费将是巨大的。这种花费在关系数据库被添加到混合数据库时甚至更高,这取决于一个组织对它们的分割和复制如何处理。

对于这种不断扩展和持久存储的需求,驱使互联网巨头——谷歌,亚马逊,Facebook,微软等等——采取一种不同的存储解决方案:基于对象存储的分布式文件系统。这些系统至少都部分受到其他分布式集群文件系统的启发,如Red Hat的全局文件系统和IBM的通用并行文件系统。

这些云巨头的分布式文件系统的架构把元数据(关于内容的数据)从它存储的数据中分开。这能通过多个副本对数据进行大量并行读写操作,并且抛掉了像“文件锁定”这样的概念。

这些分布式文件系统的影响远远超出了它们为超大规模数据中心而创建的范畴——它们会直接影响那些使用公共云服务的公司(比如亚马逊的EC2,谷歌的AppEngine和微软的Azure)如何开发和部署程序。公司,大学和政府机构寻找一种快速存储和提供大量数据访问的方法正日益变成受云巨头们启发的数据存储系统的新阶段。因此有必要了解一下它们的发展史和过程中所做的工程折衷方案。

谷歌文件系统

谷歌是最早面对存储容量问题的主流网络公司中的一家。在2003年,谷歌工程师们找到了问题的答案,就是建立一个可为谷歌数据中心战略定制的分布式文件系统——谷歌文件系统(GFS)。

谷歌文件系统几乎是所有公司云服务的基础。它能够处理数据存储,包括公司的BigTable数据库和为谷歌的AppEngine“平台即服务”的数 据储存,并且为谷歌搜索引擎和其他程序提供数据。谷歌创建谷歌文件系统的设计决定推动了大量云架构下的软件工程技术,反之亦然。谷歌往往把程序数据储存在 大量的文件里,并把文件作为“生产者-消费者队列”使用,数以百计的机器收集的数据可能被写入同一个文件。这个文件可能会由另一个合并或分析数据的应用程 序处理——或许甚至是在数据正被写入的时候。

“这当中的某些服务器一定会出错——因此谷歌文件系统被设计为能够容忍这种错误,不会丢失(太多)数据”。

谷歌为自己保留了大量技术细节,原因很明显。但是由谷歌研究员Sanjay Ghemawat,首席工程师Howard Gobioff和高级工程师Shun-Tak Leung在2003首次发表的报告中提到,谷歌文件系统在设计上是带有一些非常具体的优先考虑的:谷歌想把大量便宜的服务器和硬盘驱动器变成一个可以储 存数百TB数据的能够在出错时自行管理可靠的数据存储。并且它需要被设计成按谷歌的方式收集和读取数据,允许多个应用程序同时把大批量数据添加到系统上, 且能以高速访问。

就像是一个RAID 5存储阵列通过多磁盘放置数据进行出错保护,谷歌文件系统把文件分成固定大小的块,复制到整个服务器集群。因为它们是用着廉价硬盘的电脑,其中一些服务器肯定会出错——因此谷歌文件系统被设计为能够容忍这种错误,不会丢失(太多)数据。

但是RAID和GFS的相同点就到此为止了,因为那些服务器可以分布于网络——既可以在第一个单独的物理数据中心也可以分散于不同的数据中心,取决 于数据的用途。GFS设计主要用于批量处理大量数据。重点是高速读取数据,而不是到文件中某个部分的访问速度,也不是数据写入到文件系统的速度。GFS提 供如此高输出是以牺牲更高密度的读写和更快速度的数据写入为代价的。正如Ghemawat和公司在文件中所说,“在文件中任意位置的小的写入是支持的,但 不一定非要高效。”

这种分布式的性质,随着GFS处理数据量的庞大——数百万的文件,当中很多都超过100MB而且通常都会变成GB——需要一些取舍,以便让GFS和 你通常安装在一台服务器上的文件系统有很大的不同。因为成百上千的独立进程可能同时对一个文件进行写入和读取,GFS需要支持“原子性”数据——在不影响 其他程序的情况下回滚出错的写入。而且它需要以非常低的同步开销保持数据的完整性以避免拖垮性能。

GFS由三层组成:GFS客户端,处理程序数据请求;管理服务器,用内存中的索引追踪数据文件名和所在区块的位置;还有数据存储服务器本身。最初, 为简单起见,GFS为每个集群使用一个单独的管理服务器,因此系统被设计成让管理服务器尽可能避开数据访问。谷歌已经发开出了一个分布式管理服务器系统, 可以控制数百台管理服务器,每一台都能处理大约1亿个文件。

当GFS客户端收到一个特定数据文件的请求,它需要从管理服务器请求数据的位置。管理服务器提供其中一个副本的位置,之后客户端就可以直接与存储服务器进行沟通,用来读写剩下的其他部分。管理服务器就不再参与其中了,除非有错误发生。

为确保数据是高度可用的,GFS舍弃了其他一些东西——比如各副本间的一致性。GFS确实坚持数据的原子性——如果写入失败,它将返回一个错误,然 后将写入回滚到元数据,并产生一个旧数据的副本。但是管理服务器在数据写入上的介入缺失意味着当数据写入到系统时,它不能立刻让副本遍布整个GFS集群。 在处理对数据同时访问和网络限制的必要性之外,该系统遵循谷歌所谓的“宽松一致性模型”。

这意味着GFS对于在必要时从旧的副本提供陈旧的数据完全不在乎——只要数据最终得以更新。管理服务器的追踪变化,或“突变”,当变化发生时,区块中的数据会用版本号来指示。由于一些副本被留下了(或变“旧了”),GFS管理服务器会确保这些区块在更新前不会送至客户端。

但这并不一定发生在已经连接到那些区块的部分。元数据的变更在管理服务器处理这些变更,并将它们反映在元数据前是不可见的。元数据也需要在多个位置 生成副本,以防管理服务器出错——那样的话整个文件系统就丢失了。而且如果在写入过程中管理服务器有错误发生,变更同样会消失。由于谷歌处理数据的方式, 这并不是一个大问题:程序使用的大部分的数据很少变化,而且当变化发生时,数据通常是扩充的而不是原地修改的。

当GFS在为2003年运行的谷歌应用设计出来时,离谷歌开始遭遇扩展性问题并不远。甚至是在公司收购YouTube之前,GFS开始碰壁——很大 原因是谷歌新添加的应用在64M文件大小下工作的不是很好。为了绕过它,谷歌转向了Bigtable,一种基于表格的数据存储,那依稀类似于数据库,位于 GFS之上。Bigtable大多是一次写入,因此变更被作为对表的扩展进行存储的——谷歌将其用于如对Google Docs进行版本控制的类似应用上。

如果你不是在谷歌工作,那上述内容太过于学术性了(虽然它可以帮助AppEngine,谷歌云存储和谷歌其他服务的用户更好地了解台面下是怎么事 儿)。虽然谷歌云存储通过一个网络接口提供了一个公开方式来储存和访问位于GFS上的文件,但是操控GFS的真正接口和工具并不是公开的。但报告称GFS 引领了更广泛使用的分布式文件系统的发展,如:Hadoop分布式文件系统。

Hadoop分布式文件系统(HDFS)

Hadoop是用Java开发的,作为Apache基金会的一个开源项目,它在网络公司和其他有“大数据”问题的公司间已经有了如下的口碑,它被称 之为“二十一世界的瑞士军刀”。所有这些宣传意味着,你很可能会发现你迟早要以某种形式用Hadoop处理问题而不是用其他的分布式文件系统——特别是当 微软开始将其列入Windows Server的扩展中的时候。

Hadoop是由开发者Doug Cutting在他儿子给一只玩具大象起名后用它命名的,“灵感”来自于GFS和谷歌的MapReduce分布式计算环境。在2004年,Cutting 和其他工作于Apache Nutch搜索引擎项目的人试图寻求一种可以将抓取器和索引带向“网络规模”的方式,Cutting阅读了谷歌关于GFS和MapReduce的论文并开 始动手开发自己的项目。虽然对于Hadoop的大多数热情来自于它由MapReduce启发的分布式处理管理衍生出的分布式数据处理能力,但使用 Hadoop分布式文件系统还是因为它能对大量数据进行处理。

Hadoop是在Apache许可证下开发的,有许多商业和自由发行版可用。我用的版本来自Cloudera公司(Doug Cutting现在的东家)——Cloudera发行版包括了Apache Hadoop(CDH),Cloudera企业平台的开源版本,和Cloudera服务和配置特别版,它可免费支持50个节点。

HortonWorks,该公司与微软合作帮助后者把Hadoop移植到Azure和Windows Server,有其自己的基于Hadoop和HortonWorks数据平台,是一个受限的“技术预览版”。同样还有Apache Core的Debian包,和许多其他开源的或商业的基于Hadoop的某种形式的产品。

HDFS可被用于支持在大量廉价硬件和大数据下广泛的应用。但由于其架构,它不完全适合于通用数据存储,并且放弃了一定的灵活性。HDFS必须废除 某些经常与文件系统有关的事情,以确保它能更好地处理在分布着数百甚至数千台物理机器上的大量数据——如对数据交互访问这种事情。

虽然Hadoop运行于Java上,但是除了它的Java API之外还有许多种方式和HDFS进行交互。有一种C语言版本的API,通过Hadoop的命令行界面,文件可以通过HTTP请求浏览。还有 MountableHDFS,一个基于FUSE的扩展,允许HDFS被大多数操作系统作为一个文件系统挂载。开发者们正在制作一个WebDAV接口,让系 统可以进行基于网络的数据写入。

HDFS严格遵循了由谷歌的GFS奠定的架构路线,延续了它的三层,单管理服务器模型。每个Hadoop集群有一个叫做“名字节点”的管理服务器, 它来追踪关于位置和每个64M存储“块”副本的状态的元数据。数据通过集群中的“数据节点”复制——从属系统处理数据的读写。默认情况下每个块都会被复制 三次,而且复制的次数还可以通过改变集群设置来增加。

像GFS一样,HDFS让管理服务器尽可能快地避开读写循环,避免产生性能瓶颈。当从HDFS上访问数据的请求产生时,名字节点发回与这个请求最近 的数据节点上的块的位置信息。名字节点还可以通过一个“心跳”协议追踪每个数据节点的健康度并停止向不响应的数据节点发送请求,把它们标记为“死的”。

在切换后,名字节点就不处理任何更进一步的交互。对数据节点上数据的编辑被报告回名字节点并记录在日志里,之后用变动的数据副本对其他数据节点进行 复制。同GFS一样,这导致了一致性上相应的懒散形式,而且虽然名字节点将为最近修改的数据块发送新的请求,正在进行的工作仍然会碰到它们被分配到的数据 节点上的陈旧数据。

那不应该是经常发生的,然而,因为HDFS数据应该被“写入一次”——变动通常是扩充数据,而不是改动现有数据,为了更简单的一致性。而且由于Hadoop应用的性质,数据往往会大批量地写入HDFS。

当一个客户端发送要写入HDFS的数据时,它首先被客户端程序安置在一个临时的本地文件中,直到写入的数据达到了数据块的大小——默认64MB。之 后客户端联系名字节点并获得一个数据节点和要写入数据的块位置。这一过程对每个块的数据重复进行,一次一个块。这减少了产生网络阻塞的数量,但也减慢了写 入过程。但是HDFS是用于读取的,而不是写入。

HDFS可以减少网络写入流量的另一个办法是在于它处理复制的方式。通过激活一个叫做“机架感知”的HDFS特性来管理分布的副本,管理员可以为每 个节点指定一个机架序号,通过网络配置脚本中的一个变量指定它的物理位置。默认情况下,所有的节点都在同一个“机架”中。但是当机架感知被配置以 后,HDFS把每个块上的一个副本放置于同一个数据中心机架的另一个节点上,另一个则在不同的机架上,来减少网络中数据写入量——基于如下理由,就是一整 个机架出错的几率比一个单一节点出错的几率要小。理论上,它整体改善了HDFS的写入性能而没有牺牲掉可靠性。

与GFS早期版本一样,对于一个要成为高度可用的分布式系统,HDFS的名字节点创建一个单一的故障点。如果名字节点中的元数据丢失了,整个 HDFS环境就变成不可读了——就像一个缺少了文件分配表的硬盘。HDFS支持使用“备份节点”,它能与内存中的名字节点的元数据保持版本同步,并储存前 一系统状态的快照,以便能够在需要时回滚。快照也可以被分开储存在叫做“检查节点”的地方。然而,根据HDFS的文档,目前还不支持自动重启一个破坏的名 字节点,而且备份节点不会自动移除和替代管理服务器。

HDFS和GFS都是用搜索引擎式任务的思想而开发的。但是对于面向更多通用计算类型的云服务,“写入一次”的方法和其他妥协办法使得大数据查询性能不尽理想——这就是为什么亚马逊开发了自己的分布式存储平台,叫做Dynamo。

相关阅读: 云端磁盘:网络巨头如何存储数据(下)