本文共 2416 字,大约阅读时间需要 8 分钟。
Facebook的照片存储系统是其最受欢迎的功能之一。截至目前,用户已上传超过150亿张照片,使Facebook成为全球最大的照片分享网站。每上传一张照片,Facebook都会生成并存储四张不同尺寸的图片,这意味着总共存储了600亿张图片,占用了15PB的存储空间。目前的上传速度为每周新增2.2亿张照片,对应每周新增25TB的存储空间。在高峰时段,每秒会有55万张图片被请求。这些数据对Facebook的照片存储基础设施提出了巨大的挑战。
旧的照片存储架构分为三层:
由于每张图片存储为独立文件,存储层会产生大量元数据,包括文件名和inode目录,这远超NFS的缓存能力。每次上传或读取操作都会带来多次I/O操作,导致照片服务架构瓶颈。为了缓解这一问题,Facebook主要依赖CDN(内容分发网络)来提高照片的访问速度。
为了优化这一问题,Facebook引入了两种解决方案:
新的存储架构将照片服务层和存储层合并为一个物理层,采用基于HTTP的照片服务器存储照片到一个通用的对象存储系统Haystack。Haystack的主要目标是消除读操作中不必要的元数据开销,使每次I/O操作只读取实际图片数据。
Haystack的功能层从下到上包括:
Haystack部署在基于RAID的硬件存储刀片上。每块存储刀片的配置包括:
每块存储刀片提供约10TB的可用空间,通过RAID-6配置实现高冗余和高读取性能。RAID控制器的NVRAM缓存用于缓解写性能问题。为了保证数据一致性,所有硬盘缓存都已禁用。
Haystack对象存储基于文件系统存储,每个文件由inode表示,包含文件的逻辑位置到物理位置的映射。对于大文件,文件系统需要通过多层间接指针定位数据,导致单次读操作可能需要多次I/O。
为了优化读取性能,Facebook选择了一个基于extent的文件系统。这种文件系统只为连续的文件块(extent)维护块映射,减少了间接指针的数量。文件系统还支持主动分配大块空间,减少文件碎片问题。
Haystack是一个基于日志结构的(append-only)对象存储系统,存储称为“针”的对象。每个Haystack由一个存储文件(haystack store file)和一个索引文件(index file)组成。
Haystack的写操作同步地将新针追加到haystack store file中。一旦针被写入,相应的索引记录会被异步写入索引文件。索引文件的异步写入是为了提高写操作性能。
在硬件故障或停电时,若发生数据丢失,系统会截断haystack store file并恢复未处理的针索引记录,使系统恢复到最新完整状态。
读操作需要针的文件偏移量、键、备用键、cookie以及数据大小。Haystack会验证键、备用键和cookie是否匹配,并检查数据完整性。如果针已标记为删除,操作会失败。
删除操作仅在针的Flags字段中设置“删除”位标记。索引文件不会修改相关记录,因此可能存在引用已删除的针的情况。读操作会检查删除标记并报错。空间未被回收,除非进行数据整理操作。
照片存储服务器负责将HTTP请求转换为Haystack存储操作。为了减少I/O操作次数,服务器维护一个内存中的索引,存储所有照片的文件偏移量。启动时,服务器读取haystack index file并填充内存索引。
写操作将照片存入Haystack并更新内存索引。若索引中已存在相同键的记录,系统会将新记录的文件偏移量更新到索引中。系统假设对于重复键的照片,最新的文件偏移量对应的是最新的存储版本。
读操作需要haystack id、照片键、尺寸、cookie。服务器通过内存索引查找照片文件偏移量,成功后调用Haystack读操作获取照片数据。
删除操作调用Haystack删除操作,并更新内存索引,设置照片文件偏移量为零,以指示照片已被删除。
数据整理操作用于回收被删除或重复的针空间。通过在线操作,系统创建新的haystack文件,跳过被删除或重复的针。完成后,系统交换haystack文件和内存索引。
照片存储服务器使用开源的evhttp框架,支持多线程处理HTTP请求。由于工作负载主要是I/O密集型,HTTP服务器的性能不是主要瓶颈。
Haystack通过存储照片为针的方式,消除了传统NFS架构中的元数据开销,使每次读操作仅读取实际图片数据。这种存储架构不仅提升了照片服务的性能,还为未来的扩展提供了更高的灵活性。通过合并照片服务和存储层,Haystack实现了高效的照片存储和访问,成为Facebook照片存储系统的核心技术。
转载地址:http://ufcfk.baihongyu.com/