|
4.3 Facebook Haystack! h3 g1 Y- L2 T- M# C+ _
Facebook目前存储了2600亿张照片,总大小为20PB,通过计算可以得出每张照
. z( Q2 r4 p5 E5 l3 R片的平均大小为20PB/260GB,约为80KB。用户每周新增照片数为10亿(总大小为9 T4 D6 `6 `8 z
60TB),平均每秒新增的照片数为10 9 /7/40000(按每天40000s计),约为每秒3500
% E- _6 F8 L4 \) k# S次写操作,读操作峰值可以达到每秒百万次。$ X' m: ~! Y1 i- H( X6 o6 Z' x
Facebook相册后端早期采用基于NAS的存储,通过NFS挂载NAS中的照片文件来2 r& R. C/ e/ {
提供服务。后来出于性能和成本考虑,自主研发了Facebook Haystack存储相册数据。
: a: ]% T# W) T C& |- Z4.3.1 系统架构8 e5 h# R! z: H7 _" R5 ]7 u$ U
Facebook Haystack的思路与TFS类似,也是多个逻辑文件共享一个物理文件。
* p% v1 L& r3 d" ?0 pHaystack架构及读请求处理流程如图4-6所示。
+ Q& J& m) F' k$ P/ F8 s图 4-6 Haystack架构图
& B: n) u! M( K) D! L1 LHaystack系统主要包括三个部分:目录(Directory)、存储(Store)以及缓存
, ]0 p l0 I5 Q. u* X5 `( E+ A# \8 o(Cache)。Haystack存储是物理存储节点,以物理卷轴(physical volume)的形式组1 _% j% S0 |7 n
织存储空间,每个物理卷轴一般都很大,比如100GB,这样10TB的数据也只需100个
/ n; Q6 E0 N% o9 G, U1 n物理卷轴。每个物理卷轴对应一个物理文件,因此,每个存储节点上的物理文件元
) A. u1 Z- t/ x( Z数据都很小。多个物理存储节点上的物理卷轴组成一个逻辑卷轴(logical
5 T' y) V3 D6 B0 f5 {* Bvolume),用于备份。Haystack目录存放逻辑卷轴和物理卷轴的对应关系,以及照片
7 A0 d) I; M; b( `4 Eid到逻辑卷轴之间的映射关系。Haystack缓存主要用于解决对CDN提供商过于依赖的1 K+ f5 e& Q5 ]- L3 z- e$ N a
问题,提供最近增加的照片的缓存服务。
3 [/ }/ U5 u0 @9 \Haystack照片读取请求大致流程为:用户访问一个页面时,Web服务器请求7 K- b1 J. v' U8 f4 B
Haystack目录构造一个URL:http://<CDN>/<Cache>/<Machine id>/<Logical: E+ \6 E% V7 y# w; d$ g
volume,Photo>,后续根据各个部分的信息依次访问CDN、Haystack缓存和后端的
' M- {0 n/ }& ]/ N5 k; OHaystack存储节点。Haystack目录构造URL时可以省略<CDN>部分从而使得用户直% b( P# ]5 w, K- [3 f2 q; v# F
接请求Haystack缓存而不必经过CDN。Haystack缓存收到的请求包含两个部分:用户: Z i5 c$ n) M/ G, Y7 n
浏览器的请求及CDN的请求,Haystack缓存只缓存用户浏览器发送的请求且要求请求
6 p( y1 c; O& J5 a8 z$ {; r5 e的Haystack存储节点是可写的。一般来说,Haystack后端的存储节点写一段时间以后
( K' A) v) d. C/ u |9 p: W* `1 G达到容量上限变为只读,因此,可写节点的照片为最近增加的照片,是热点数据。
O, B- c3 b7 u3 E- M本节暂不讨论CDN,只讨论Haystack后端存储系统,包括Haystack目录和Haystack缓
! n8 Q6 h+ a# y1 K1 B) F9 K. L存两个部分。
# o$ l% m" `4 s9 P4 Q* W1.写流程" _4 t! X6 i5 T4 o6 M1 ^) }
如图4-7所示,Haystack的写请求(照片上传)处理流程为:Web服务器首先请求
! h& R2 W' |/ E+ d' @2 a$ hHaystack目录获取可写的逻辑卷轴,接着生成照片唯一id并将数据写入每一个对应的- y) N8 }, y* [* O- ?* g8 I" K
物理卷轴(备份数一般为3)。写操作成功要求所有的物理卷轴都成功,如果中间出& F4 ]9 p$ @0 Z# G c- p
现故障,需要重试。2 ^1 j4 G' O: u) \5 x! I
图 4-7 Haystack写流程* }6 \# p& Y. p
Haystack的一致性模型保证只要写操作成功,逻辑卷轴对应的所有物理卷轴都存
. m, P2 i# Q/ S2 a在一个有效的照片文件,但有效照片文件在不同物理卷轴中的偏移(offset)可能不3 o4 n5 z% A% A5 d" _( w
同。: u5 z& k3 S, K
Haystack存储节点只支持追加操作,如果需要更新一张照片,可以新增一张编号
+ ] H' b* }( d p相同的照片到系统中,如果新增照片和原有的照片在不同的逻辑卷轴,Haystack目录( Y! M6 u/ H: [/ d! x/ F( q& z! s
的元数据会更新为最新的逻辑卷轴;如果新增照片和原有的照片在相同的逻辑卷
- B; N4 {7 g# W \- I9 e' C2 @) q轴,Haystack存储会以偏移更大的照片文件为准。
* h& C: N$ l8 j& Q2.容错处理) _5 _! n2 b+ w8 ?
(1)Haystack存储节点容错
/ E# b# [- i& U. s, W, \; C检测到存储节点故障时,所有物理卷轴对应的逻辑卷轴都被标记为只读。存储1 }. n! l+ j0 n- y. v8 v" y
节点上的未完成的写操作全部失败,写操作将重试;如果发生故障的存储节点不可6 t" ?& S9 {* G% x' ~; \
恢复,需要执行一个拷贝任务,从其他副本所在的存储节点拷贝丢失的物理卷轴的0 a) X' h1 J' S
数据;由于物理卷轴一般很大,比如100GB,所以拷贝的过程会很长,一般为小时! u. v) ^6 D7 J5 z
级别。
2 Z$ C1 d8 {6 ?7 C2 {& Y& t; q(2)Haystack目录容错
1 L* u' G( M2 s5 lHaystack目录采用主备数据库(Replicated Database)做持久化存储,由主备数据
. _# z, y: }+ X库提供容错机制。+ q" e/ m4 s' b
3.Haystack目录( v4 h) N# B+ [9 s
Haystack目录的功能如下:
3 D8 R6 V }; e( i% `1)提供逻辑卷轴到物理卷轴的映射,维护照片id到逻辑卷轴的映射;
+ d8 J4 J- s3 \3 ^6 K& ?+ S+ ?2)提供负载均衡,为写操作选择逻辑卷轴,读操作选择物理卷轴;- I7 n+ ]1 R% [+ Z
3)屏蔽CDN服务,可以选择某些图片请求直接走Haystack缓存;
8 C% g1 e6 w1 k4)标记某些逻辑卷轴为只读。* }: O+ F3 t- c0 |8 W F2 z
根据前面的计算结果可知,Facebook相册系统每秒的写操作大约为3500次,每
( C' l$ [$ v8 R! s1 s7 o秒的读请求大约为100万次。每个写请求都需要通过Haystack缓存获取可写的卷轴,
; N4 Y+ ^) b; r9 u, u5 b1 |: y每个读请求需要通过Haystack缓存构造读取URL。这里需要注意,照片id到逻辑卷轴, h3 I) v3 c3 h+ o
的映射的数据量太大,单机内存无法存放,笔者猜测内部使用了MySQL Sharding集
$ h6 t: }, V U9 @ J+ i群,另外,还增加了一个Memcache集群满足查询需求。 Q& k& ^* ?5 A) O! J3 j: k
4.Haystack存储! e ~6 n5 R/ Q( _' I" ]8 [. {
Haystack存储保存物理卷轴,每个物理卷轴对应文件系统中的一个物理文件,每2 y( a8 s7 x6 [% G: h5 i @
个物理文件的格式如图4-8所示。
$ P+ [3 L0 G- r* S- }图 4-8 Haystack数据块格式
% _# d6 J$ B+ B( T3 ~多个照片文件存放在一个物理卷轴中,每个照片文件是一个Needle,包含实际
$ \8 H' b, _: X2 k! B* G数据及逻辑照片文件的元数据。部分元数据需要装载到内存中用于照片查找,包括( L. q( ~" l- S+ C0 T9 A3 J
Key(照片id,8字节),Alternate Key(照片规格,包括Thumbnail、Small、Medium
' m, e, H$ [3 v" \+ x7 ^+ @2 @$ ?8 y及Large,4字节),照片在物理卷轴的偏移Offset(4字节),照片的大小Size(4字, i; d3 [( U$ p8 s4 Y4 w) n( X5 ^
节),每张照片占用8+8+4=20字节的空间,假设每台机器的可用磁盘为8TB,照片& n6 }0 z, V9 J( L
平均大小为80KB,单机存储的照片数为8TB/80KB=100MB,占用内存
$ s8 k' { C3 w/ y5 C1 w100MB×20=2GB。
8 ]( f: }9 O1 \/ A& f) p存储节点宕机时,需要恢复内存中的逻辑照片查找表,扫描整个物理卷轴耗时
2 X8 ~3 r7 z2 S% m4 i! e9 d太长,因此,对每个物理卷轴维护了一个索引文件(Index File),保存每个Needle- W! l. q& B, L3 a2 @1 D4 N! Z4 ^
查找相关的元数据。写操作首先更新物理卷轴文件,然后异步更新索引文件。由于3 J$ k% E( W1 \( g( E) R R
更新索引文件是异步的,所以可能出现索引文件和物理卷轴文件不一致的情况,不
; x3 z* g8 d+ T" z5 v M3 z" }" E过由于对物理卷轴文件和索引文件的操作都是追加操作,只需要扫描物理卷轴文件
7 V3 {5 G9 t1 a$ B# H5 Y最后写入的几个Needle,然后补全索引文件即可。这种技术在仅支持追加的文件系2 l" v6 f1 @$ l+ Z
统很常见。4 X+ \& P# i1 A3 Y
Haystack Store存储节点采用延迟删除的回收策略,删除照片只是向卷轴中追加9 @4 L$ h, ]1 Y2 J; q2 S
一个带有删除标记的Needle,定时执行Compaction任务回收已删除空间。所谓# e6 @" [' U l
Compaction操作,即将所有老数据文件中的数据扫描一遍,以保留最新一个照片的原4 w, Q% c- t' Y v' ~" G6 l) c
则进行删除,并生成新的数据文件。
& ? o/ E! T" ?3 E9 ]" }7 x4.3.2 讨论
6 M7 i% R2 p( j0 k! R相比TFS,Haystack的一大特色就是磁盘空间回收。Blob文件在TFS中通过<Block. @1 \; ^( A- o% c) G% Q d6 l
id,Block offset>标识,因此,不能对TFS中的数据块进行重整操作;而Haystack中的
: A2 e, x. u4 B2 A0 ], L元信息只能定位到Blob文件所在的逻辑卷轴,Haystack存储节点可以根据情况对物理
- ]: K/ p! N9 u1 f卷轴进行Compaction操作以回收磁盘空间。, C0 @# n% h9 C2 H8 @! S
Facebook Haystack中每个逻辑卷轴的大小为100GB,这样减少了元信息,但是增
2 V( L2 m# D: C6 _2 ?0 ^) V加了迁移的时间。假设限制内部网络带宽为20MB/s,那么迁移100GB的数据需要的
- D. Q; {2 [" ]5 d+ `) x时间为100GB/20MB/s=5000s,大约是一个半小时。而TFS设计的数据规模相比
1 g/ ]- O2 ]- d9 S; j( qHaystack要小,因此,可以选择64MB的块大小,有利于负载均衡。7 I) S% L+ ]" c. R- H$ I
另外,Haystack使用RAID 6,并且底层文件系统使用性能更好的XFS,淘宝TFS+ c5 n, ~6 r* |8 F
不使用RAID机制,文件系统使用Ext3,由应用程序负责管理多个磁盘。Haystack使用
) n$ M* o$ u4 c了Akamai&Limelight的CDN服务,而淘宝已经使用自建的CDN,当然,Facebook也在( B& P5 a M) f) c7 X
考虑自建CDN。* i2 d: D7 |1 d/ ?; ^% ?) F; ]
5 m+ z/ D% M3 I f4 L9 B2 c
8 V$ m; ?8 R9 f' ~ |
|