论文地址
代码实现
相关资料
摘要:本文描述了一种针对Facebook的Photos应用程序优化的对象存储系统HayStack。Facebook目前存储了超过2600亿张图片,这相当于超过20 PB的数据。用户每周上传10亿张新图片(∼60 TB),而峰值时每秒提供超过100万张图片。
Haystack 提供了一种更便宜的,比我们以前的方法性能更高的,解决方案。我们的主要观察是,传统设计会因为太多的查找元数据而导致过多的磁盘操作,所以我们减少了每张图片的元数据,以便 Haystack storage 可以在主内存中执行所有元数据查找。这可节省读取实际数据的磁盘操作,从而增加了总体吞吐量。
分享图片是Facebook最受欢迎的功能之一。到目前为止,用户已经上传了超过650亿张图片,使Facebook成为最大的图片分享网站在世界上。对于每一张上传的图片,Facebook会生成并存储四张不同大小的图片,其中转化为超过2600亿张图像和20多个数PB的数据。用户上传10亿张新图片(∼60TB),Facebook 每周的服务超过最高峰时每秒一百万张图像。正如我们所期望的那样这些数字将在未来增加,图片存储这对Facebook的基础设施构成了重大挑战。
本文介绍了Facebook的图片存储系统HayStack的设计和实现,该系统在过去的24个月里已经投入使用。Hystack是我们为在Facebook上共享图片而设计的对象存储,其中的数据只写入一次,经常读取,从未修改,也很少删除。我们为图片设计了自己的存储系统,因为传统的文件系统在我们的工作负载下性能很差。
根据我们的经验,我们发现传统的基于POSIX[21]的文件系统的缺点是目录和每个文件的元数据。对于图片,大多数元数据(如权限)都未使用,因此浪费了存储容量。
然而,更大的代价是,为了找到文件本身,必须将文件的元数据从磁盘读取到内存中。虽然在小范围内微不足道,成倍增加数十亿张图片和数PB的数据,但访问元数据是吞吐量的瓶颈。我们发现这是在使用挂载在NFS上的网络连接存储(NAS)设备时的关键问题。读取一张图片需要几次磁盘操作:一次(或通常更多)将文件名转换为索引节点号,另一次从磁盘读取索引节点,最后一次读取文件本身。简而言之,对元数据使用磁盘IO是我们读取吞吐量的限制因素。请注意,在实践中,这个问题会带来额外的成本,因为我们必须依赖CDN来为大多数读取流量提供服务。
考虑到传统方法的缺点,我们设计了HayStack来实现四个主要目标:
这项工作描述了我们从构思到实施每天为数十亿张图像提供服务的生产质量系统的经验。我们的三个主要贡献是:
我们对本文的其余部分进行了如下组织。第2节提供了背景,并重点介绍了我们以前的体系结构中的挑战。我们在第3节描述了HayStack的设计和实现。第4节描述了我们的图片读写工作负载,并证明HayStack满足我们的设计目标。我们与第5节中的相关工作进行了比较,并在第6节中总结了本文。
在这一节中,我们将描述HayStack之前存在的体系结构,并重点介绍我们学到的主要经验教训。由于空间限制,我们对此设计的讨论忽略了生产级部署的几个细节。
我们首先简要概述Web服务器、内容交付网络(CDN)和存储系统如何交互以在热门网站上提供图片的典型设计。图1描述了从用户访问包含图像的页面到从其在磁盘上的位置下载该图像的步骤。当访问页面时,用户的浏览器首先向Web服务器发送一个HTTP请求,该服务器负责为浏览器生成要呈现的标记。对于每个图像,Web服务器都会构造一个URL,将浏览器指向下载数据的位置。对于受欢迎的站点,此URL通常指向CDN。如果CDN缓存了镜像,则CDN会立即使用数据进行响应。否则,CDN会检查URL,该URL嵌入了足够的信息,可以从网站的存储系统中检索图片。然后,CDN更新其缓存数据,并将图像发送到用户的浏览器。
在我们的第一个设计中,我们使用基于NFS的方法实现了图片存储系统。虽然这一小节的其余部分提供了关于该设计的更多细节,但我们学到的主要教训是,CDN本身并不提供在社交网站上提供图片的实用解决方案。CDN确实有效地为最热门的图片-头像和最近上传的图片-提供服务,但像Facebook这样的社交网站也会产生大量对不太受欢迎(通常是较老的)内容的请求,我们称之为长尾。来自长尾的请求占我们通信量的很大一部分,几乎所有这些请求都访问支持图片存储主机,因为这些请求通常在CDN中缺失。虽然为这条长尾缓存所有图片会非常方便,但这样做并不划算,因为需要非常大的缓存空间。
我们基于NFS的设计将每张图片存储在一组商业NAS设备上的自己的文件中。一组机器、图片存储服务器,然后通过 NFS挂载这些NAS设备导出的所有卷。图2说明了该体系结构,并显示了处理图像的HTTP请求的图片存储服务器。图片存储服务器从图像的URL中提取文件的卷和完整路径,通过NFS读取数据,并将结果返回给CDN。
最初,我们在一个NFS卷的每个目录中存储了数千个文件,这导致了读取单个图像所需的磁盘操作次数过多。由于NAS设备管理目录元数据的方式,将数千个文件放在一个目录中效率极低,因为该目录的块图太大,设备无法有效地缓存。因此,检索单个图像需要10次以上的磁盘操作是很常见的。在将目录大小减少到每个目录数百个图像之后,所产生的系统通常仍然需要3次磁盘操作来获取图像:一次是从磁盘读目录元数据,第二次是读inode,第三次是读文件内容。
为了进一步减少磁盘操作,我们让 Photo Store 服务器显式缓存 NAS 设备返回的文件句柄。
对于何时或何时不构建自定义存储系统,我们很难提供准确的指导方针。然而,我们相信,它仍然有助于社区深入了解我们为什么决定构建HayStack。
面对我们基于NFS的设计中的瓶颈,我们探索了构建类似于GFS的系统是否有用。由于我们将大部分用户数据存储在MySQL数据库中,因此系统中文件的主要使用案例是工程师用于开发工作、日志数据和图片的目录。NAS设备为开发工作和日志数据提供了非常好的性价比。此外,我们用 Hadoop 处理超大的日志数据。在长尾中处理图片请求是一个无论是MySQL、NAS设备还是Hadoop都不能很好解决的问题。
人们可以用我们面临的困境来形容,因为现有的存储系统缺乏正确的RAM与磁盘比率。然而,没有正确的比例。系统只需要足够的主内存,以便可以一次缓存所有文件系统元数据。在我们基于NAS的方法中,一张图片对应一个文件,每个文件至少需要一个inode,它有数百个字节大。在这种方法中拥有足够的主内存并不划算。为了实现更好的性价比,我们决定构建自定义存储系统,以减少每张图片的文件系统元数据量,以便拥有足够的主内存比购买更多的NAS设备更具成本效益。
Facebook使用CDN为热门图片提供服务,并利用HayStack高效响应长尾图片请求。当一个网站遇到提供静态内容的I/O瓶颈时,传统的解决方案是使用CDN。CDN承担了足够的负担,以便存储系统可以处理剩余的尾部。在Facebook,CDN必须缓存不合理的大量静态内容,才能使传统的(且廉价的)存储方法不受I/O限制。
认识到在不久的将来CDN不会完全解决我们的问题,我们设计了HayStack来解决我们基于NFS的方法中的关键瓶颈:磁盘操作。我们承认,对不太受欢迎的图片的请求可能需要磁盘操作,但我们的目标是将此类操作的数量限制为仅读取实际图片数据所需的操作。Hystack通过显著减少用于文件系统元数据的内存来实现这一目标,从而使将所有这些元数据保存在主内存中变得可行。
回想一下,每个文件存储一张图片会产生比合理缓存更多的文件系统元数据。Hystack采取了一种简单的方法:它将多张图片存储在一个文件中,因此维护着非常大的文件。我们表明,这种直截了当的方法非常有效。此外,我们认为它的简单性是其优势所在,有助于快速实施和部署。我们现在讨论这项核心技术及其周围的体系结构组件如何提供可靠且可用的存储系统。在下面对HayStack的描述中,我们区分了两种元数据。应用程序元数据描述了构造浏览器可以用来检索图片的URL所需的信息。文件系统元数据标识主机检索驻留在该主机磁盘上的图片所需的数据
Haystack 结构由3个核心组件组成:Store、Directory、Cache。
图3说明了 Store、Directory、Cache 组件如何适应用户的浏览器、Web服务器、CDN和存储系统之间的规范交互。在 Haystack 架构中,浏览器可以定向到CDN或缓存。请注意,虽然缓存本质上是一个CDN,但为了避免混淆,我们使用‘CDN’表示外部系统,使用‘Cache’表示缓存图片的内部系统。拥有内部缓存基础设施使我们能够减少对外部CDN的依赖。当用户访问页面时,Web服务器使用 Directory 为每张图片构造一个URL。URL包含多条信息,每条信息对应于从用户浏览器联系CDN(或缓存)到最终从商店中的机器检索图片的一系列步骤。将浏览器指向CDN的典型URL为 http://(CDN)/(Cache)/(Machine id)/(Logical volume, Photo)
URL的第一部分指定向哪个CDN请求图片。CDN可以只使用URL的最后一部分在内部查找图片:逻辑卷和图片ID。如果CDN无法找到图片,则它会从URL中剥离CDN地址,并联系缓存。缓存执行类似的查找来找到图片,如果未命中,则从URL中剥离缓存地址,并从指定的Store机器请求图片。直接进入缓存的图片请求具有类似的工作流程,只是URL缺少CDN特定信息。
图4显示了HayStack中的上传路径。当用户上传照片时,她首先将数据发送到网络服务器。接下来,该服务器从 Directory 请求启用写入的逻辑卷。最后,Web服务器为照片分配唯一ID,并将其上载到映射到分配的逻辑卷的每个物理卷
该 Directory 有四个主要职能。
当我们通过添加新机器来增加存储区的容量时,这些机器是启用写入的;只有启用写入的机器才会接收上载。随着时间的推移,这些机器上的可用容量会减少。当机器耗尽其容量时,我们将其标记为只读。在下一个小节中,我们将讨论这种区别如何对缓存和存储产生微妙的影响。
目录是一个相对简单的组件,它将其信息存储在一个复制的数据库中,该数据库通过利用 Memcache 来减少延迟的 PHP 接口访问。如果存储机器上的数据丢失,我们将删除映射中的相应条目,并在新的存储机器上线时替换它。
Cache 从CDNs和直接从用户的浏览器接收对照片的HTTP请求。我们将缓存组织为分布式哈希表,并使用照片的ID作为关键字来定位缓存的数据。如果缓存不能立即响应请求,则缓存从URL中标识的 Store机器 获取图片,并根据需要回复CDN或用户的浏览器。
现在我们重点介绍缓存的一个重要行为方面。它只在满足两个条件时缓存照片:(A)请求直接来自用户,而不是CDN;以及(B)照片从可写存储机器获取。
存储机器的界面特意是基本的。读取会发出非常具体且包含良好的请求,请求具有给定ID的照片、特定逻辑卷以及来自特定物理存储机器的照片。如果找到照片,机器会将其返回。否则,机器将返回错误。
每台存储机器管理多个物理卷。每一卷都有数百万张照片。具体来说,读者可以将物理卷看作是一个非常大的文件(100 GB),保存为 /hay/haystack<逻辑卷id>
。仅使用相应逻辑卷的ID和照片所在的文件偏移量,存储机器就可以快速访问照片。这一知识是HayStack设计的基础:检索特定照片的文件名、偏移量和大小,而不需要磁盘操作。存储机为其管理的每个物理卷保存打开的文件描述符,并在内存中将照片ID映射到文件系统元数据(即,文件、偏移量和大小,以字节为单位),这些元数据对于检索照片至关重要。
我们现在描述每个物理卷的布局,以及如何从该卷派生内存中映射。存储机将物理卷表示为一个大文件,该文件由一个超级块和一系列 needle(针) 组成。每一根针代表一张储存在 Haystack 中的照片。图5说明了每根针的卷文件和格式。表1描述了每个针中的字段
为了快速检索针,每台存储机器都为其每个卷维护一个内存中的数据结构。该数据结构将(key,Alternate Key)2对映射到相应的针的标志,大小为2。由于历史原因,照片的id对应于Key,而其类型用于Alternate Key。在上传过程中,网络服务器将每张照片缩放成四种不同的大小(或类型),并将它们存储为不同的针,但使用相同的密钥。这些字节之间的重要区别以及卷偏移量。崩溃后,存储机器可以在处理请求之前直接从卷文件重建此映射。现在,我们将介绍Store机器如何在响应读取、写入和删除请求(Store支持的唯一操作)的同时维护其卷和内存映射。
当缓存机器请求照片时,它向存储机器提供逻辑卷ID、密钥、备用密钥和Cookie。Cookie是嵌入到照片URL中的数字。在上传照片时,Cookie的值由目录随机分配并存储在目录中。该Cookie有效地消除了旨在猜测照片的有效URL的攻击。
当Store机器收到来自缓存机器的照片请求时,Store机器会在其内存映射中查找相关的元数据。如果照片尚未删除,存储机器将在卷文件中查找适当的偏移量,从磁盘读取整个指针(其大小可以提前计算),并验证Cookie和数据的完整性。如果这些检查通过,则存储机器将照片返回到缓存机器
在将照片上传到HayStack时,Web服务器向存储机器提供逻辑卷ID、密钥、备用密钥、Cookie和数据。每台机器同步地将针图像附加到其物理卷文件中,并根据需要更新内存中的映射。
虽然简单,但这种仅限附加的限制会使一些修改照片的操作复杂化,例如旋转。由于HayStack不允许覆盖针,因此只能通过添加具有相同键和备用键的更新针来修改照片。如果新的指针被写入与原始指针不同的逻辑卷,则目录将更新其应用程序元数据,并且以后的请求将永远不会获取较旧的版本。如果将新指针写入相同的逻辑卷,则存储机器会将新指针附加到相同的相应物理卷。Haystack 根据它们的偏移量来区分这种重复的针。也就是说,物理卷内的最新版本的针是偏移量最高的那个。
删除照片很简单。存储机器在内存映射中和在卷文件中同步设置删除标志。获取删除照片的请求首先检查内存中的标志,如果该标志被启用,则返回错误。请注意,被删除的针占用的空间暂时会丢失。随后,我们讨论了如何通过压缩卷文件来回收已删除的针空间。
存储机器在重启时使用一个重要的优化–索引文件。虽然理论上机器可以通过读取其所有物理卷来重建其内存中的映射,但这样做非常耗时,因为必须从磁盘读取所有数据量(TB)。索引文件允许存储机器快速构建其内存映射,从而缩短重新启动时间。
存储机器为它们的每个卷维护一个索引文件。索引文件是用于在磁盘上高效定位针的内存数据结构的检查点。索引文件的布局类似于卷文件的布局,包含一个超级块,后跟与超级块中的每个指针对应的一系列索引记录。这些记录的出现顺序必须与相应针在卷文件中出现的顺序相同。图6说明了索引文件的布局,表2说明了每条记录中的不同字段。
重新开始使用索引比仅仅读取索引和初始化内存中的映射稍微复杂一些。出现这种复杂情况是因为索引文件是异步更新的,这意味着索引文件可能代表过时的检查点。当我们写一张新照片时,Store机器「同步」地将一个指针附加到卷文件的末尾,并「异步」地将一条记录附加到索引文件。当我们删除一张照片时,Store机器会在不更新索引文件的情况下同步设置该照片的指针中的标志。这些设计决策使写入和删除操作能够更快地返回,因为它们避免了额外的同步磁盘写入。它们还造成了两个我们必须解决的副作用:针可以在没有相应索引记录的情况下存在,并且索引记录不会反映删除的照片。
我们将没有相应索引记录的针称为孤儿。在重新启动期间,存储机器会按顺序检查每个孤立项,创建匹配的索引记录,并将该记录附加到索引文件中。请注意,我们可以「快速识别」孤立对象,因为索引文件中的最后一条记录对应于卷文件中的最后一个非孤立指针。为了完成重新启动,Store机器 现在仅使用索引文件 来初始化其内存映射。
由于索引记录不反映已删除的照片,因此存储机器可以检索实际上已被删除的照片。为了解决这个问题,在 Store 机器读取照片的整个针之后,该机器可以检查删除的标志。如果指针被标记为已删除,则存储机器会相应地更新其内存中映射,并通知缓存未找到该对象。
我们将 HayStack 描述为使用通用的类Unix文件系统的对象存储,但某些文件系统比其他文件系统更适合HayStack。特别是,存储机器应该使用不需要太多内存的文件系统,以便能够在大文件中快速执行随机查找。目前,每台存储机器都使用XFS,这是一种基于区的文件系统。对于HayStack,XFS有两个主要优势。
使用XFS,HayStack可以在读取照片时消除检索文件系统元数据的磁盘操作。然而,这一好处并不意味着HayStack可以保证每次读取照片都会导致一次磁盘操作。当照片数据跨越区段或RAID边界时,存在文件系统需要多个磁盘操作的特殊情况。Haystack 预分配1 GB的扩展区,并使用256 KB的RAID条带大小,因此在实践中我们很少遇到这样的情况。
像许多在商用硬件上运行的其他大型系统一样,HayStack需要容忍各种故障:故障硬盘驱动器、行为不正常的RAID控制器、损坏的主板等。我们使用两种简单的技术来容忍故障-一种用于检测,另一种用于修复。
为了主动发现有问题的商店机器,我们维护一个称为干草叉的后台任务,该任务定期检查每台商店机器的运行状况。Pitchfork远程测试到每个存储计算机的连接,检查每个卷文件的可用性,并尝试从存储计算机读取数据。如果Shochfork确定某个存储计算机始终未能通过这些运行状况检查,则它会自动将驻留在该存储计算机上的所有逻辑卷标记为只读。我们脱机手动解决检查失败的根本原因。
一旦诊断出来,我们可能很快就能解决这个问题。有时,这种情况需要更繁重的批量同步操作,在此操作中,我们使用副本提供的卷文件重置存储计算机的数据。批量同步很少发生(每个月只有几次),而且简单,尽管执行速度很慢。主要瓶颈是,要批量同步的数据量通常比每台Store计算机上的NIC速度高几个数量级,导致平均恢复时间长达数小时。我们正在积极探索解决这一限制的技术。
我们现在讨论对HayStack的成功非常重要的几个优化。
压缩是一种在线操作,它回收已删除和重复的针(具有相同键和备用键的针)所使用的空间.存储机器通过将针复制到新文件中,同时跳过任何重复或删除的条目来压缩卷文件. 在压缩过程中,删除操作将同时删除这两个文件.一旦此过程到达文件末尾,它就会阻止对卷的任何进一步修改,并自动交换文件和内存中的结构
我们使用压缩来从删除的照片中释放空间。删除的模式类似于照片查看:年轻的照片更有可能被删除。在一年的时间里,大约25%的照片被删除。
如上所述,存储机器维护包括标志的内存中数据结构,但我们当前的系统仅使用标志字段将针标记为已删除。我们通过将已删除照片的偏移量设置为0来消除对标志在内存中表示的需要。此外,存储机器不会跟踪主内存中的Cookie值,而是在从磁盘读取指针后检查提供的Cookie。通过这两种技术,存储机器的主内存占用量减少了20%。
目前,HayStack平均每张照片使用10字节的内存。回想一下,我们将每个上传的图像缩放为四张照片,所有照片都具有相同的密钥(64位)、不同的备用密钥(32位),因此数据大小也不同(16位)。除了这32个字节之外,由于哈希表的原因,HayStack在每个图像上消耗了大约2个字节的开销,使同一图像的四个缩放照片的总开销达到40个字节。作为比较,假设Linux中的XFS inode t结构为536字节。
由于磁盘通常更擅长执行大型顺序写入,而不是小型随机写入,因此我们尽可能将上传批量放在一起。幸运的是,许多用户将整个相册上传到Facebook,而不是单一的照片,这显然提供了一个将相册中的照片批量放在一起的机会。我们在第4节中量化了将写入聚合在一起的改进。
我们将我们的评估分为四个部分.首先,我们对脸书看到的照片请求进行了描述在第二和第三部分中,我们分别展示了目录和缓存的有效性.最后,我们分析了商店使用合成工作负载和生产工作负载时的表现.
照片是用户在Facebook上分享的主要内容之一。用户每天上传数百万张照片,最近上传的照片往往比旧照片更受欢迎。图7说明了每张照片作为照片年龄函数的受欢迎程度。为了理解图表的形状,讨论是什么推动了Facebook的照片请求是很有用的
Facebook 98%的照片请求来自两个功能:新闻订阅和相册。News Feed功能向用户显示他们的朋友分享的最新内容。相册功能允许用户浏览她朋友的照片。她可以查看最近上传的照片,还可以浏览所有个人相册。Facebook 98%的照片请求来自两个功能:新闻订阅和相册。新闻源功能向用户显示他们的朋友分享的最新内容。相册功能允许用户浏览她朋友的照片.她可以查看最近上传的照片,还可以浏览所有个人相册.
图7显示了对几天前的照片的请求急剧上升。新闻提要推动了最近照片的大部分流量,大约在两天左右,当许多故事不再显示在默认的提要视图中时,流量急剧下降。从这个数字来看,有两个关键点值得注意。首先,受欢迎程度的快速下降表明,CDN和缓存中的缓存对于托管流行内容非常有效。其次,该图有一个长尾,这意味着使用缓存数据无法处理大量请求。
表3显示了Facebook上的图片流量。由于我们的应用程序将每个图像缩放为4个大小,并将每个大小保存在3个不同的位置,因此写入的HayStack照片数量是上传照片数量的12倍。该表显示,在CDN发出的所有照片请求中,约有10%得到了HayStack的响应。观察到,查看的照片中大部分都是较小的图像。这一特点强调了我们将元数据开销降至最低的愿望,因为低效可能会很快累积起来。此外,对于Facebook来说,阅读较小的图像通常是一种对延迟更敏感的操作,因为它们显示在News Feed中,而较大的图像显示在相册中,可以预取以隐藏延迟。
干草堆栈目录平衡了所有干草堆栈存储机器的读写操作。如图8所示,目录分发读写的直截了当的散列策略非常有效。该图显示了同时部署到生产中的9台不同存储计算机所看到的多写操作数量。这些盒子中的每一个都存储着一组不同的照片。由于这些行几乎无法区分,我们得出结论,《目录》的书写平衡得很好。比较存储计算机之间的读取流量也显示出类似的良好平衡行为。
图9显示了HayStack缓存的命中率。回想一下,仅当照片保存在支持写的Store计算机上时,缓存才会存储照片。这些照片是相对较新的,这解释了高命中率约80%。由于启用写入的存储计算机也会看到最多的读取次数,因此缓存可以有效地显著降低受影响最大的计算机的读取请求率。
回想一下,HayStack的目标是照片请求的长尾,并旨在保持高吞吐量和低延迟,尽管看起来是随机读取。我们展示了存储机器在合成和生产工作负载下的性能结果。
我们在商用存储刀片上部署存储机器。2U存储刀片的典型硬件配置具有2个超线程四核Intel Xeon CPU、48 GB内存、一个带有256-512MB NVRAM的硬件RAID控制器和12个1TB SATA驱动器。
每个存储刀片提供约9TB的容量,配置为由硬件RAID控制器管理的RAID-6分区。RAID-6可提供足够的冗余和出色的读取性能,同时降低存储成本。控制器的NVRAM回写式高速缓存缓解了RAID-6的S降低的写入性能。由于我们的经验表明,在存储计算机上缓存照片是无效的,因此我们完全保留NVRAM以供写入。我们还禁用 disk cache,以确保在崩溃或断电时的数据一致性。
我们使用两个基准来评估Store机器的性能:Randomio 和 HayStress。Randomio是一个开源的多线程磁盘I/O程序,我们用它来测量存储设备的原始容量。它发出随机的64KB读取,使用直接I/O发出扇区一致的请求,并报告最大可持续吞吐量。我们使用Randomio来建立读取吞吐量的基准,我们可以将其与其他基准测试的结果进行比较。
HayStress是一个定制的多线程程序,我们使用它来评估针对各种合成工作负载的Store机器。它通过HTTP与存储机器通信(就像缓存一样),并评估存储机器可以维持的最大读写吞吐量。HayStress对一大组虚拟映像执行随机读取,以减少机器缓冲区缓存的影响;也就是说,几乎所有读取都需要磁盘操作。在本文中,我们使用七种不同的HayStress工作负载来评估存储机器。
表4描述了在我们的基准测试下,存储机器可以承受的读写吞吐量和相关延迟。工作负载A对具有201个卷的存储计算机上的64KB映像执行随机读取。结果表明,干草堆栈提供了设备85%的原始吞吐量,而延迟仅高出17%。
我们将存储机的开销归因于四个因素:
在工作负载B中,我们再次检查只读工作负载,但更改了70%的读取,以便它们请求更小的图像(8KB而不是64KB)。在实践中,我们发现大多数请求不是对最大尺寸的图像(如相册中所示),而是对缩略图和个人资料照片的请求。
工作负载C、D和E显示存储计算机的写入吞吐量。回想一下,HayStack可以一起成批写入。工作负载C、D和E组1、4和16分别写入单个多次写入。该表显示,在4个和16个映像上摊销写入的固定成本可将吞吐量分别提高30%和78%。正如预期的那样,这也减少了每个映像的延迟。
最后,我们来看看同时存在读操作和写操作时的性能。工作负载F使用98%的读取和2%的多次写入的混合,而G使用96%的读取和4%的多次写入的混合,其中每次多次写入写入16个映像。这些比率反映了生产中经常观察到的情况。该表显示,即使在存在写入的情况下,该存储区也可提供高读取吞吐量。
这一部分考察了Store在生产机器上的性能。如第3节所述,有两种类型的存储区–启用写入和只读。支持写的主机服务于读写请求,只读主机服务于读请求。由于这两个类别具有相当不同的流量特征,因此我们分析每个类别中的一组机器。所有机器都具有相同的硬件配置。
以每秒的粒度来看,Store Box看到的照片读写操作量可能会出现很大的峰值。为了即使在出现这些峰值的情况下也能确保合理的延迟,我们保守地分配了大量支持写操作的计算机,以便它们的平均利用率较低。
图10显示了只读和支持写的Store机器上不同类型的操作的频率。请注意,我们在周日和周一看到了照片上传的高峰期,本周剩下的时间会平稳下降,直到周四到周六才趋于平稳。然后,新的星期天到来了,我们达到了每周的新高峰。一般来说,我们的足迹每天增长0.2%到0.5%。
如第3节所述,在生产计算机上,对存储区的写入操作始终是多次写入,以摊销写入操作的固定成本。查找图像组相当简单,因为每张照片的4个不同大小的照片都存储在HayStack中。用户将一批照片上传到相册中也很常见。作为这两个因素的组合,对于这台支持写入的机器,每次多次写入的平均映像数为9.27。
第4.1.2节解释说,最近上传的照片的阅读率和删除率都很高,而且会随着时间的推移而下降。在图10中也可以观察到这种行为;启用写的机器会看到更多的请求(即使一些读流量由缓存提供服务)。
另一个值得注意的趋势是:随着更多的数据被写入到支持写入的框中,照片的数量也会增加,从而导致读取请求率的提高。图11显示了同一时间段内在与图10相同的两台机器上执行读操作和多写操作的延迟。
即使业务量变化很大,多写操作的延迟也相当低(在1到2毫秒之间)且稳定。干草堆机器有一个NVRAM支持的RAID控制器,可以为我们缓冲写入。如第3节所述,NVRAM允许我们异步写指针,然后在多写操作完成后发出单个fsync来刷新卷文件。多次写入延迟非常平稳且稳定。
只读机箱上的读取延迟也相当稳定,即使流量变化很大(在3周内最高可达3倍)。对于启用写入的计算机,读取性能受三个主要因素的影响。
存储计算机上的CPU利用率较低。CPU空闲时间在92-96%之间变化。
据我们所知,HayStack的目标是一个新的设计点,专注于一家大型社交网站看到的照片请求的长尾。
一些著作[8,19,28]提出了如何更有效地管理小文件和元数据。这些贡献的共同主线是如何智能地将相关文件和元数据分组在一起。Hystack避免了这些问题,因为它在主内存中维护元数据,并且用户经常批量上传相关照片。
基于对象的存储:HayStack的体系结构与Gibson等人提出的对象存储系统有许多相似之处。[10]在网络连接安全磁盘(NASD)中。在将逻辑存储单元与物理存储单元分开的NASD中,HayStack目录和存储可能分别最类似于文件和存储管理器的概念。在OBFS[25]中,Wang et al.构建一个用户级的基于对象的文件系统,其大小是XFS的1/25。尽管OBFS实现了比XFS更大的写吞吐量,但它的读吞吐量(HayStack的主要关注点)略差一些。
管理元数据:Weil等人。[26,27]解决Ceph1 PB级对象存储中的缩放元数据管理问题。Cave通过引入生成函数而不是显式映射,进一步解耦了从逻辑单元到物理单元的映射。客户端可以计算适当的元数据,而不是查找它。在干草堆栈中实现这一技术仍是未来的工作。Hendricks et.Al[13]注意到,传统的元数据预取算法对对象存储的效率较低,因为由唯一编号标识的相关对象缺乏目录隐式施加的语义分组。他们的解决方案是将对象间关系嵌入到对象ID中。这个想法与HayStack是正交的,因为Facebook将这些语义关系明确地存储为社交图的一部分。在SpyGlass[15]中,Leung et al.提出了一种大规模存储系统元数据快速可扩展搜索的设计方案。Manber和Wu还提出了一种快速搜索整个文件系统的方法[17]。Patil等人。[20]使用GIGA+中的复杂算法来管理与每个目录的数十亿个文件相关联的元数据。我们设计了一个比许多现有工作更简单的解决方案,因为HayStack既不需要提供搜索功能,也不需要提供传统的UNIX文件系统语义。
分布式文件系统:HayStack的逻辑卷概念类似于Lee和Thekkath在Petal中的[14]虚拟磁盘。Boxwood项目[16]探索了使用高级数据结构作为存储的基础。虽然对于更复杂的算法来说很有吸引力,但像B树这样的抽象可能不会对HayStack故意精简的接口和语义产生很大影响。同样,Sinfonia的[1]个小事务和PNUTS的[5]个数据库功能提供了比HayStack需要的更多的功能和更强大的保证。Ghemawat等人。[9]针对主要由追加操作和大量顺序读取组成的工作负载,设计了Google文件系统。BigTable[4]为结构化数据提供了存储系统,并为Google的许多项目提供了类似数据库的功能。目前还不清楚,这些功能中的许多在一个针对照片存储进行优化的系统中是否有意义。
本文描述了HayStack,这是一个为Facebook的Photos应用程序设计的对象存储系统。我们设计HayStack是为了服务于在大型社交网络中分享照片所看到的长尾请求。关键的洞察力是在访问元数据时避免磁盘操作。Hystack为照片存储提供了一种容错且简单的解决方案,与使用NAS设备的传统方法相比,成本大大降低,吞吐量更高。此外,HayStack是可增量扩展的,这是我们的用户每周上传数亿张照片所必需的品质。