本文是facebook的论文 《Finding a needle in Haystack: Facebook's photo storage》的阅读笔记,该论文旨在解决社交网络中海量小文件且请求具有长尾特性的服务能力问题。本文主要关注论文中前三个section的内容,后面的部分主要是实现细节和benchmark,请自行按需阅读。
https://www.usenix.org/legacy/event/osdi10/tech/full_papers/Beaver.pdfwww.usenix.org早在2010年的时候,facebook就已经存储了2600亿级别的照片了。并且每周都新增大约10亿照片(大约60TB的存储)。在访问峰值,facebook每秒需要serve超过一百万张照片。这些数据还只是十年前。
传统的设计会导致过多的基于磁盘的matadata查询,而haystack通过将metadata缩小,并将其加载到内存中,从而提升metadata lookup的效率。
传统FS存在的问题
传统的POSIX FS给每个文件和每个目录都生成metadata,这些metadata可能很复杂,包含一些permissions啊,访问时间修改时间啊,用户信息啊等等,这些信息对照片存储其实是浪费。此外更麻烦的是,传统文件系统的metadata(inode等等)是存在磁盘上的,这就导致你访问一个文件就要先去磁盘上查metadata,然后才能知道文件在哪儿,然后再去找文件。在海量小文件查询的场景下,metadata lookup就成了瓶颈。如果你是用network attached storage(NAS)的话,读一张图片需要先查询磁盘索引将文件名转成inode号,然后去磁盘读取inode得到文件真实存储位置,最后读取文件。
而Haystack解决的最重要的问题之一就是将读取一张照片的disk operation减到差不多只有一次,论文中提到,haystack达到了NAS的四倍的读处理能力。除此之外,haystack还会在不同的地区replicates每一张照片,以提供更好的容错能力。
传统设计
![ea5b1fae6ed4a096f35a64cb58eeae63.png](https://i-blog.csdnimg.cn/blog_migrate/f7b21be002fabf1a84c8472bd503869f.jpeg)
最常见的设计大概就是这样了,将图片放到cdn上,浏览器通过和CDN交互拿到照片。当然CDN上也是有缓存的,对于热点图片资源,很可能直接从缓存中返回,而缓存中不存在的照片则去后面的storage system查询。
这里的问题在于,CDN只能解决最热的那部分图片的请求,可是对于社交网络来说,其请求分布呈现明显的长尾特性,也就是说,那些不太热门的图片的请求量加起来还是非常非常大的,而它们就用不了CDN了。
![970d32ee6d106f0b8194358fb44d531a.png](https://i-blog.csdnimg.cn/blog_migrate/e0a70e12831dcfae3a189f197bf2f778.jpeg)
一种改进方案中引入了NAS,将一组NAS通过NFS的形式暴露给photo store server,当请求来时,通过查询NFS来读取图片。
这里面也存在一个问题,就是当NFS的一个目录下文件过多时,这个目录的metadata会很大,导致读取一张照片需要很多次的磁盘访问。
为了解决这个问题,首先可以想到减少每个目录下的文件数,以减小需要查询的metadata数。除此之外,还可以通过在photo store server这一层设立缓存,缓存内容为<filename, filehandle>,这样在photo stroe server中缓存主文件句柄,这样后面打开文件就可以直接访问了。
总结一下,CDN无法提供社交网络这种具有明显长尾效应的海量照片数据的服务能力。而基于NAS的方案仍旧需要缓存的支持才能带来有限的磁盘操作次数优化。在Facebook,他们将用户数据都存在mysql中,而对于文件类的存储需求,最主要就是log和photo。对于log这种大文件,hadoop是非常善于处理的,但是像照片这种海量小文件加长尾请求的应用场景,并不是NAS+hadoop能够搞定的。
Haystack的设计
其实说来说去,到底还是为了减少磁盘操作,如果有足够链家而又足够大的缓存,能够将所有的inode信息全部加载到内存中,问题就解决了。haystack的思路就是压缩metadata,让它能被加载到内存中。
首先我们来分析下照片数据的特点:written once, read often, never modified, rarely deleted.一次写,不可变,不太删,经常读。这简直就是日志的另一个名字啊,日志怎么处理的呢?都写进一个大文件呗。
haystack的做法其实也很简单,就是将很多张图片存在同一个文件里面,显然,这将小文件变成了大文件。
总体上来看,haystack包含了三个核心组成部分: the haystack store, haystack directory, haystack cache.
其中,store封装了持久化层,并组织成了逻辑存储和物理存储(当向一个逻辑卷写入一张照片时,会写入与之相关的所有物理卷)。store也是正在在负责根据文件的metadata来找到文件的工作组件。
此外,directory负责维护逻辑存储和物理存储之间的映射关系。cache则扮演内部cdn的角色,用于处理最热的那部分照片请求。
大致的流程就是,首先浏览器请求web server,web server去directory为每张照片生成对应的url。url格式如下
http://<cdn>/<cache>/<machine id>/<logical volume, photo>
然后浏览器拿着url再去CDN请求图片,如果cdn没找到就去haystack找,haystack会先找cache,找不到的话去后面的文件系统中。
![8eab826db0a82af16a4d3c6112a45578.png](https://i-blog.csdnimg.cn/blog_migrate/a65e30bb1526173740de2d9fea8e6373.jpeg)
上传照片的时候,浏览器先将照片传给服务器,服务器从directory请求一个可以写的逻辑卷,然后向store发起写入请求,流程图如下。
![16dabbc623f00d11ae683ae70651e834.png](https://i-blog.csdnimg.cn/blog_migrate/eeac3bd9345bc6daf8e1bc4a06cc1d04.jpeg)