|
第6章 分布式表格系统/ V; `. V e# T% C6 R
分布式表格系统对外提供表格模型,每个表格由很多行组成,通过主键唯一标
; A6 c6 [$ U. M4 u6 x3 \识,每一行包含很多列。整个表格在系统中全局有序,适用3.3.2节中讲的顺序分
i% j# x" ~& h布。
9 j+ S2 D8 ?- \$ y' hGoogle Bigtable是分布式表格系统的始祖,它采用双层结构,底层采用GFS作为
1 ?: a2 _2 N, M6 Z/ ]; n; S持久化存储层。GFS+Bigtable双层架构是一种里程碑式的架构,其他系统,包括
) |6 K! Z4 I' S7 |Microsoft分布式存储系统Windows Azure Storage以及开源的Hadoop系统,均为其模仿
# z1 p. }4 J6 G$ ]者。Bigtable的问题在于对外接口不够丰富,因此,Google后续开发了两套系统,一9 S* v% L- P; o
套是Megastore,构建在Bigtable之上,提供更加丰富的使用接口;另外一套是- {& f$ U( p! ?9 S' e0 B
Spanner,支持跨多个数据中心的数据库事务,下一章会专门介绍。
1 s5 F0 g f! w% r' F. o7 z本章首先详细介绍Bigtable的架构及实现,接着分析Megastore的架构,最后介绍
$ j$ U! X- e- W! b( [) s+ A4 AMicrosoft Azure Storage的架构。
" a3 }+ d. i* y6.1 Google Bigtable+ x9 R# o$ ?+ r
Bigtable是Google开发的基于GFS和Chubby的分布式表格系统。Google的很多数5 {6 i O' l. Y1 z
据,包括Web索引、卫星图像数据等在内的海量结构化和半结构化数据,都存储在' h( ^9 U" q, l* f
Bigtable中。与Google的其他系统一样,Bigtable的设计理念是构建在廉价的硬件之
S; w/ I3 d5 x) w3 D: ^2 _6 i* ]上,通过软件层面提供自动化容错和线性可扩展性能力。8 ^" v# s7 T! W2 b8 o: p) y
Bigtable系统由很多表格组成,每个表格包含很多行,每行通过一个主键(Row2 ~$ j/ Q% f( H/ h7 z
Key)唯一标识,每行又包含很多列(Column)。某一行的某一列构成一个单元: J/ w' u g# u: a+ ~; m2 G
(Cell),每个单元包含多个版本的数据。整体上看,Bigtable是一个分布式多维映$ |9 _+ Q4 L7 K. f* F
射表,如下所示:# s! h' k( B) e" S: U
(row:string,column:string,timestamp:int64)->string
* m2 G% Q3 U1 k% g' Q另外,Bigtable将多个列组织成列族(column family),这样,列名由两个部分8 v6 U! `" h" b- t
组成:(column family,qualifier)。列族是Bigtable中访问控制的基本单元,也就是
3 `6 W, M# f" q* S# U, R. D说,访问权限的设置是在列族这一级别上进行的。Bigtable中的列族在创建表格的时' j5 M v: [4 g ^5 k+ `5 y; |9 N, \! t
候需要预先定义好,个数也不允许过多;然而,每个列族包含哪些qualifier是不需要
Z+ H _# l# ^; G- E预先定义的,qualifier可以任意多个,适合表示半结构化数据。
$ U8 @$ G1 J' _0 m0 N0 p2 @Bigtable数据的存储格式如图6-1所示。/ q6 S/ A( Y8 M. `
图 6-1 Bigtable数据存储格式
/ T, z! r0 s7 g2 `* [. L; gBigtable中的行主键可以是任意的字符串,最大不超过64KB。Bigtable表中的数
4 }" |$ I2 U* a0 Q+ Q: W4 K0 B据按照行主键进行排序,排序使用的是字典序。图6-1中行主键com.cnn.www是域名1 G* ~, m4 v! O/ g k: W
www.cnn.com变换后的结果,这样做的好处是使得所有www.cnn.com下的子域名在系
6 O: C$ a! H7 L* z+ i4 v! R W5 W统中连续存放。这一行数据包含两个列族:"contents"和"anchor"。其中,列
8 v6 ?. p* S: B: Y5 }" W3 d族"anchor"又包含两个列,qualifier分别为"cnnsi.com"和"my:look.ca"。
$ B: }) x5 s# m, s+ c8 e8 aGoogle的很多服务,比如Web检索和用户的个性化设置,都需要保存不同时间的! E+ t6 S. {2 l4 J( P2 Y; p3 w7 \
数据,这些不同的数据版本必须通过时间戳来区分。图6-1中的t 4 、t 5 和t 6 表示保存了
. V- g5 a: [3 s三个时间点获取的网页。为了简化不同版本的数据管理,Bigtable提供了两种设置:
! b) E& e7 q! Z3 _* }一种是保留最近的N个不同版本,另一种是保留限定时间内的所有不同版本,比如可
, O N) J. r+ n4 y6 O以保存最近10天的所有不同版本的数据。失效的版本将会由Bigtable的垃圾回收机制
. @, x/ o, y; D; _7 x! H自动删除。
: j0 x( ?+ T% {. k6.1.1 架构
8 ^; h0 q1 K' jBigtable构建在GFS之上,为文件系统增加一层分布式索引层。另外,Bigtable依* R1 a2 j7 Y" Y- N2 {1 c( m
赖Google的Chubby(即分布式锁服务)进行服务器选举及全局信息维护。
* m$ M, h# A9 M# H如图6-2所示,Bigtable将大表划分为大小在100~200MB的子表(tablet),每个* w* F; z' A9 M' j
子表对应一个连续的数据范围。Bigtable主要由三个部分组成:客户端程序库
1 Q& }; Z7 _$ t8 h% w: Q$ {(Client)、一个主控服务器(Master)和多个子表服务器(Tablet Server)。2 s: \; U- p& x+ P+ V8 U
图 6-2 Bigtable的整体架构
: X8 Q# u9 U( Q2 ~●客户端程序库(Client):提供Bigtable到应用程序的接口,应用程序通过客户
9 {0 b) H" h( h6 S6 `端程序库对表格的数据单元进行增、删、查、改等操作。客户端通过Chubby锁服务' s$ x7 r- H6 T
获取一些控制信息,但所有表格的数据内容都在客户端与子表服务器之间直接传% Z. q8 B* \5 \+ R8 S" `* b
送;, R0 u8 @8 ^( \) m
●主控服务器(Master):管理所有的子表服务器,包括分配子表给子表服务1 A! Q3 A7 Q8 W+ c& V7 O
器,指导子表服务器实现子表的合并,接受来自子表服务器的子表分裂消息,监控
7 g- u$ t Q! H! E( z! U" s6 l8 w子表服务器,在子表服务器之间进行负载均衡并实现子表服务器的故障恢复等。
* X: E9 x; c8 ?+ O●子表服务器(Tablet Server):实现子表的装载/卸出、表格内容的读和写,子' y* X# I- F+ x7 R t
表的合并和分裂。Tablet Server服务的数据包括操作日志以及每个子表上的sstable数
" j! G0 c" |. ^! Q' Z据,这些数据存储在底层的GFS中。
4 h5 W2 G \% J! p" v- _Bigtable依赖于Chubby锁服务完成如下功能:' j' N3 [7 T& j1 L. X5 O
1)选取并保证同一时间内只有一个主控服务器;1 P H, b2 y5 q3 q7 X
2)存储Bigtable系统引导信息;
/ } @4 t: J- ^: R) T" j3)用于配合主控服务器发现子表服务器加入和下线;
9 D# |) l0 c% @, s2 z. {0 `4)获取Bigtable表格的schema信息及访问控制信息。
' E* p: s) ?: IChubby是一个分布式锁服务,底层的核心算法为Paxos。Paxos算法的实现过程需
( u* }+ d2 S% h9 s2 j要一个“多数派”就某个值达成一致,进而才能得到一个分布式一致性状态。也就是/ k6 Z8 [: V2 r4 w. |8 ?9 c: s
说,只要一半以上的节点不发生故障,Chubby就能够正常提供服务。Chubby服务部
2 l( v- k, n$ u( a! n8 l: C# ]署在多个数据中心,典型的部署为两地三数据中心五副本,同城的两个数据中心分+ u0 R/ T3 E: J; L, M' H8 s
别部署两个副本,异地的数据中心部署一个副本,任何一个数据中心整体发生故障
! W, r* P6 N; x1 A. k都不影响正常服务。
8 U, h1 m3 t, R7 `8 ^Bigtable包含三种类型的表格:用户表(User Table)、元数据表(Meta Table)& T* R% b9 U- l+ [( M& ]
和根表(Root Table)。其中,用户表存储用户实际数据;元数据表存储用户表的元
0 o' F- g7 t; o5 _( x' l1 J# m, U数据;如子表位置信息、SSTable及操作日志文件编号、日志回放点等,根表用来存
* k8 d5 g; ^# N* \储元数据表的元数据;根表的元数据,也就是根表的位置信息,又称为Bigtable引导
?- b0 P+ h, A- w( q信息,存放在Chubby系统中。客户端、主控服务器以及子表服务器执行过程中都需
" {, S4 v! r, B1 f要依赖Chubby服务,如果Chubby发生故障,Bigtable系统整体不可用。
* C- y; q$ @" `' V, J, o+ n8 S6.1.2 数据分布
\5 |# D7 K2 y. S) ~' B% xBigtable中的数据在系统中切分为大小100~200MB的子表,所有的数据按照行
4 Z. T" _! d8 E% p" ~主键全局排序。Bigtable中包含两级元数据,元数据表及根表。用户表在进行某些操; o5 t+ |) H' N5 B& r6 D
作,比如子表分裂的时候需要修改元数据表,元数据表的某些操作又需要修改根
* [& g( o+ x+ ?0 u表。通过使用两级元数据,提高了系统能够支持的数据量。假设平均一个子表大小
0 W% q4 z+ h$ M+ _+ {& {& T+ D为128MB,每个子表的元信息为1KB,那么一级元数据能够支持的数据量为
' G1 Z4 }6 Z( z' ^1 e128MB×(128MB/1KB)=16TB,两级元数据能够支持的数据量为
% F, D6 k8 r4 @4 l" N16TB×(128MB/1KB)=2048 PB,满足几乎所有业务的数据量需求。如图6-3所示。* E8 V! j- h* r4 c
图 6-3 Bigtable数据结构
$ J2 n, v- D; D/ C4 d& e客户端查询时,首先从Chubby中读取根表的位置,接着从根表读取所需的元数" Y q$ c! j0 K U
据子表的位置,最后就可以从元数据子表中找到待查询的用户子表的位置。为了减 N3 s* T: _9 w! l
少访问开销,客户端使用了缓存(cache)和预取(prefetch)技术。子表的位置信息
* t. E7 C7 z6 Z7 D8 H% ]被缓存在客户端,客户端在寻址时首先查找缓存,一旦缓存为空或者缓存信息过
$ u2 |! w6 L2 B. \% R! X2 i期,客户端就需要请求子表服务器的上一级元数据表获取位置信息,比如用户子表
9 C8 P% X X0 z- ?! g缓存过期需要请求元数据表,元数据子表缓存过期需要请求根表,根表缓存过期需1 Q1 b# H' E! `/ C& c4 c, _9 O
要读取Chubby中的引导信息。如果缓存为空,最多需要三次请求;如果缓存信息过
6 L$ h0 |/ V- H! `期,最多需要六次请求,其中三次用来确定信息是过期的,另外三次获取新的地+ ~7 T0 a- F5 X; w6 M
址。预取则是在每次访问元数据表时不仅仅读取所需的子表元数据,而是读取连续) _9 g, x' M" \, ?. W: G2 t. e
的多个子表元数据,这样查找下一个子表时不需要再次访问元数据表。
- d- K, o6 ?5 u' ]# z. s6.1.3 复制与一致性
& e/ C- r3 ~1 G. C; ?Bigtable系统保证强一致性,同一个时刻同一个子表只能被一台Tablet Server服
$ _* A& o% t% Z! @1 ]务,也就是说,Master将子表分配给某个Tablet Server服务时需要确保没有其他的
+ j( q+ s- Z1 B7 ^7 w5 fTablet Server正在服务这个子表。这是通过Chubby的互斥锁机制保证的,Tablet Server6 `, y$ J: f$ e" f# Q, l) m" v
启动时需要获取Chubby互斥锁,当Tablet Server出现故障,Master需要等到Tablet" O4 O8 r7 h$ `6 T& M+ T
Server的互斥锁失效,才能把它上面的子表迁移到其他Tablet Server。
+ R4 u% k) [- Z2 X% M1 WBigtable的底层存储系统为GFS(参见前面4.1节)。GFS本质上是一个弱一致性% K% U& D1 u; {' I. V# x( z; C- C$ v
系统,其一致性模型只保证“同一个记录至少成功写入一次”,但是可能存在重复记+ F) Q' i3 B: v7 V% h3 \" l
录,而且可能存在一些补零(padding)记录。% s s' g+ X" ~
Bigtable写入GFS的数据分为两种:
7 o. \* ~& V* }2 ?+ n+ S●操作日志。当Tablet Server发生故障时,它上面服务的子表会被集群中的其他
6 _3 v: a0 w4 {. a8 P- l/ FTablet Server加载继续提供服务。加载子表可能需要回放操作日志,每条操作日志都1 k! ^) n7 Z0 V' C
有唯一的序号,通过它可以去除重复的操作日志。4 y* e9 O( }0 s& |' V5 ~( w
●每个子表包含的SSTable数据。如果写入GFS失败可以重试并产生多条重复记
6 E) q/ m* I5 H8 h5 ^0 Y9 e录,但是Bigtable只会索引最后一条写入成功的记录。
( f$ j' g% S) t' S$ B% u( o# XBigtable本质上是构建在GFS之上的一层分布式索引,通过它解决了GFS遗留的9 R0 u! w M7 u$ y4 i( z
一致性问题,大大简化了用户使用。; e) K9 Q: S- L6 n' d/ w5 Q
6.1.4 容错
+ ~) ^$ s" U+ v" XBigtable中Master对Tablet Server的监控是通过Chubby完成的,Tablet Server在初始
9 v4 I, H; w! E5 {化时都会从Chubby中获取一个独占锁。通过这种方式所有的Tablet Server基本信息被
9 D, S' G% o6 C$ I' f保存在Chubby中一个称为服务器目录(Server Directory)的特殊目录之中。Master通
) G8 |! e$ a5 t" @过检测这个目录以随时获取最新的Tablet Server信息,包括目前活跃的Tablet Server," M( d' I8 G( S6 O
以及每个Tablet Server上现已分配的子表。对于每个Tablet Server,Master会定期询问其9 | }5 l4 q" Z1 {
独占锁的状态。如果Tablet Server的锁丢失或者没有回应,则此时可能有两种情况,
( h) i3 {. s/ P7 |8 @. F7 I& J要么是Chubby出现了问题,要么是Tablet Server出现了问题。对此Master首先自己尝; |6 Z3 j0 o1 }; l3 `3 F# H( P
试获取这个独占锁,如果失败说明是Chubby服务出现问题,否则说明是Tablet Server
0 S1 ^& O/ x7 w% q出现了问题。Master将中止这个Tablet Server并将其上的子表全部迁移到其他Tablet& a) t6 n- _# n0 J c' @7 }
Server。) r6 l3 ]' Z8 R& `. |2 L
每个子表持久化的数据包含两个部分:操作日志以及SSTable。Tablet Server发生
* @; b& r! h1 i5 s' Y故障时某些子表的一些更新操作还在内存中,需要通过回放操作日志来恢复。为了6 V2 H8 T0 @+ Y% r
提高性能,Tablet Server没有为它服务的每个子表写一个操作日志文件,而是把所有6 K6 l! u5 A- I- V" @5 s
它服务的子表的操作日志混在一起写入GFS,每条日志通过<表格编号,行主键,日1 ?+ Q2 m! E. W! j8 f# C. O! s
志序列号>来唯一标识。当某个Tablet Server宕机后,Master将该Tablet Server服务的
' Q$ |% o" t, W4 T1 U子表分配给其他Tablet Server。为了减少Tablet Server从GFS读取的日志数据量, J; |6 k, K/ V/ J I5 _
Master将选择一些Tablet Server对日志进行分段排序。排好序后,同一个子表的操作* g7 L$ W* [7 K! k% Q
日志连续存放,Tablet Server恢复某个子表时只需要读取该子表对应的操作日志即
& L9 s# D1 @2 F" W' Z2 T" a; O) F) Y2 u可。Master需要尽可能选择负载低的Tablet Server执行排序,并且需要处理排序任务2 X% z+ y5 c6 w- _: ^
失败的情况。
% V7 e* h! R+ f2 \- f: i. L6 w8 LBigtable Master启动时需要从Chubby中获取一个独占锁,如果Master发生故障,
% Y! F/ R4 D5 |7 DMaster的独占锁将过期,管理程序会自动指定一个新的Master服务器,它从Chubby成* ^7 m) `9 G5 _* P* S: {
功获取独占锁后可以继续提供服务。
$ V0 n, z* c, J5 a( u6.1.5 负载均衡& ^% h9 }& Q, ~7 D* H. |
子表是Bigtable负载均衡的基本单位。Tablet Server定期向Master汇报状态,当状5 ^! O& _ C5 v- p3 q" ^
态检测时发现某个Tablet Server上的负载过重时,Master会自动对其进行负载均衡,
2 D7 s2 S! V' I1 \- v即执行子表迁移操作。子表迁移分为两步:第一步请求原有的Tablet Server卸载子7 T j: L+ f5 V* G; x
表;第二步选择一台负载较低的Tablet Server加载子表。Master发送命令请求原有的5 L8 x$ y: }- h5 u, d
Tablet Server卸载子表,原有Tablet Server解除加在子表上的互斥锁,而新的Tablet& e/ p5 j% C- l% ^
Server加载子表时需要首先获取互斥锁。如果原有Tablet Server发生故障,新的Tablet8 @% M: k5 r a1 G$ Z* m
Server需要等待原有Tablet Server加在子表上的互斥锁过期。子表迁移前原有的Tablet
, K. {- ?2 `- k8 sServer会对其执行Minor Compaction操作,将内存中的更新操作以SSTable文件的形式
( a2 M& n" z7 w. F a转储到GFS中,因此,负载均衡带来的子表迁移在新的Tablet Server上不需要回放操( _8 \2 c/ H$ V: h4 B) {* o, h
作日志。
3 z/ p/ q' l& z; O# l子表迁移的过程中有短暂的时间需要停服务,为了尽可能减少停服务的时间,
5 E, X4 Y' y8 p9 ~& J" w7 [Bigtable内部采用两次Minor Compaction的策略。具体操作如下:
6 f$ h2 v+ `6 g% O8 H1)原有Tablet Server对子表执行一次Minor Compaction操作,操作过程中仍然允
9 _! Z" I2 Y3 A/ C许写操作。: ~8 Z# W0 ^ c0 L1 j6 U
2)停止子表的写服务,对子表再次执行一次Minor Compaction操作。由于第一: m. z# L4 a) |" o6 w- Z
次Minor Compaction过程中写入的数据一般比较少,第二次Minor Compaction的时间
! B& K& @8 V. J; v会比较短。6 I' e, ?) i B, i' Y* E
由于Bigtable负载均衡的过程中会停一会读写服务,负载均衡策略不应当过于激 J* M8 @% r, [9 I
进。负载均衡涉及的因素很多,Tablet Server通过心跳定时将读、写个数、磁盘、内
4 t2 W, z2 R2 o5 P" g( {2 P存负载等信息发送给Master,Master根据负载计算公式计算出需要迁移的子表,然后放+ H2 c- W5 N: I- u# x
入迁移队列中等待执行。9 c! z) R7 E3 Y, P0 m4 r9 S
6.1.6 分裂与合并
, H# `( m. D) }% s6 L, w# M随着数据不断写入和删除,某些子表可能太大,某些子表可能太小,需要执行
2 R# X/ s0 e: Z4 E( j子表分裂与合并操作。顺序分布与哈希分布的区别在于哈希分布往往是静态的,而) r/ }! ]/ U( q$ D( y# W# E
顺序分布是动态的,需要通过分裂与合并操作动态调整。
5 G6 E+ E- \5 h/ o+ I6 l1 E- ~5 ~4 nBigtable每个子表的数据分为内存中的MemTable和GFS中的多个SSTable,由于
. T6 _+ D9 _% |4 O" qBigtable中同一个子表只被一台Tablet Server服务,进行分裂时比较简单。Bigtable上" U' I# C1 I b/ _7 c' d
执行分裂操作不需要进行实际的数据拷贝工作,只需要将内存中的索引信息分成两
. C7 I% |! Z3 M( m( z. \: Z ^8 e* ~/ O# I份,比如分裂前子表的范围为(起始主键,结束主键],在内存中将索引分成(起始: S' K5 N5 C3 J) _* I, ]
主键,分裂主键]和(分裂主键,结束主键]两个范围。例如,某个子表(1,10]的分
3 q+ C( D5 U; B& L0 q3 e裂主键为5,那么,分裂后生成的两个子表的数据范围为:(1,5]和(5,10]。分裂
! _/ P' Y8 b9 _) K, `- x以后两个子表各自写不同的MemTable,等到执行Compaction操作时再根据分裂后的4 l6 ~. a! |/ C( [ \1 T
子表范围生成不同的SSTable,无用的数据自然成为垃圾被回收。" Y2 [, v* h( A
分裂操作由Tablet Server发起,需要修改元数据,即用户表的分裂需要修改元数9 N( ^( P# e& O, e( z
据表,元数据表的分裂需要修改根表。分裂操作需要增加一个子表,相当于在元数6 r3 Z/ |# B6 T9 K
据表中增加一行,通过Bigtable的行事务保证原子性。只要修改元数据表成功,分裂+ }6 B) _8 X; y p4 [8 U$ b) z0 c. y' c
操作就算成功。分裂成功后Tablet Server将向Master汇报,如果出现Tablet Server故
5 K: E; H! P4 x障,Master可能丢失汇报分裂消息。新的Tablet Server加载这个子表时将发现它已经
& c9 E* e: Y. O6 ?分裂,并通知Master。3 ]$ ^6 M: W9 Z$ \ E
合并操作由Master发起,相比分裂操作要更加复杂。由于待合并的两个子表可能# y1 G2 r( N% }
被不同的Tablet Server加载,合并的第一步需要迁移其中一个子表,以使它们在同一
8 b6 {* w1 Y% R' m个Tablet Server上,接着通知Tablet Server执行子表合并。子表合并操作具体实现时非
3 c% Q' U2 e" p" z3 i" x9 z# N常麻烦,有兴趣的读者可以自行思考。9 U' p6 Q1 b7 U; U7 o9 g
6.1.7 单机存储. f3 c2 F7 ?( v' x
如图6-4所示,Bigtable采用Merge-dump存储引擎。数据写入时需要先写操作日& i- z) E+ F' u3 h. }- P$ D$ }% j/ f1 e
志,成功后应用到内存中的MemTable中,写操作日志是往磁盘中的日志文件追加数
, x& J, C6 x- w# y4 c5 X1 M据,很好地利用了磁盘设备的特性。当内存中的MemTable达到一定大小,需要将
% V! X' S' B. ]# v/ [8 a+ y. uMemTable转储(Dump)到磁盘中生成SSTable文件。由于数据同时存在MemTable和
* `, s5 p- f- B2 w1 c& v可能多个SSTable中,读取操作需要按从旧到新的时间顺序合并SSTable和内存中的: ]1 P9 P! W* l( e- y
MemTable数据。数据在SSTable中连续存放,因此可以同时满足随机读取和顺序读取
5 k1 @/ j* W8 G d; n两种需求。为了防止磁盘中的SSTable文件过多,需要定时将多个SSTable通过- ]: J& E8 T, U/ E, C$ R
compaction过程合并为一个SSTable,从而减少后续读操作需要读取的文件个数。一
+ ?, ?) D) M, b" B般情况下,如果写操作比较少,我们总是能够使得对每一份数据同时只存在一个
8 S' R' x0 C0 W6 v' U* y# \9 |SSTable和一个MemTable,也就是说,随机读取和顺序读取都只需要访问一次磁盘,
7 [7 [2 F9 y7 j4 T4 Y这对于线上服务基本上都是成立的。9 d6 v U7 f. c: v5 U. r1 G
图 6-4 Bigtable单机存储引擎) }" T" J% ?: A* p7 m
插入、删除、更新、增加(Add)等操作在Merge-dump引擎中都看成一回事,除4 V4 x6 a J! h" |
了最早生成的SSTable外,SSTable中记录的只是操作,而不是最终的结果,需要等到( d% A; C X6 i0 W% E5 r6 Z5 }: ?
读取(随机或者顺序)时才合并得到最终结果。8 I& n$ N) b5 r$ Z2 o" ^* u
Bigtable中包含三种Compaction策略:Minor Compaction、Merging Compaction和
3 X- T" H* C7 ?0 x; f9 w$ WMajor Compaction。其中,Minor Compaction把内存中的MemTable转储到GFS中,9 y3 i6 E2 v2 L; w
Merging Compaction和Major Compaction合并GFS中的多个SSTable文件生成一个更大
7 X, d' C% v- J4 b1 O/ ^2 B的SSTable。Minor Compaction主要是为了防止内存占用过多,Merging和Major1 i3 |; m7 _1 G/ j3 b. n0 m. q% o
Compaction则是为了防止读取文件个数过多。Major Compaction与Merging Compaction
! v8 W# u ?& Y4 Y, O的区别在于Major Compaction会合并所有的SSTable文件和内存中的MemTable,生成
* g! x0 [6 u0 t最终结果;而Merging Compaction生成的SSTable文件可能包含一些操作,比如删除、& f# E; t" _# U; ?4 g$ R' F/ n
增加等。 e: N/ W1 e5 U( @1 v2 }
数据在SSTable中按照主键有序存储,每个SSTable由若干个大小相近的数据块
, b4 s" O# Q# n9 z8 T- e6 T" X. { c0 w(Block)组成,每个数据块包含若干行。数据块的大小一般在8~64KB之间,允许2 r# `. t/ h4 r0 x9 a2 m
用户配置。Tablet Server的缓存包括两种:块缓存(Block Cache)和行缓存(Row* `- O2 Y! C2 O. x5 p( H! E' b0 o @
Cache)。其中,块缓存的单位为SSTable中的数据块,行缓存的单位为一行记录。随
$ z r' R" P/ i7 r r/ B0 d! t; _ \7 O机读取时,首先查找行缓存;如果行缓存不命中,接着再查找块缓存。另外,+ [/ `) B' \- i
Bigtable还支持布隆过滤器(Bloom Filter),如果读取的数据行在SSTable中不存在,
( ~. V/ A% j7 I, P% M" G* a可以通过布隆过滤器发现,从而避免一次读取GFS文件操作。
G7 F" n9 a" |& {+ d4 T) ^6.1.8 垃圾回收/ w$ e* Q9 j% x+ E; ?
Compaction后生成新的SSTable,原有的SSTable成为垃圾需要被回收掉。每个子$ {" q( g; N/ V1 C. i, i/ m4 Z
表正在引用的SSTable文件保存在元数据中。Master定期执行垃圾回收任务,这是一) V1 R. u; W: G$ V8 v ~
个标记删除(mark-and-sweep)过程。首先扫描GFS获取所有的SSTable文件,接着扫
& ?2 k4 k# [4 X8 P描根表和元数据表获取所有正在使用的SSTable文件,如果GFS中的SSTable没被任何
# Y; g( S0 N0 m: J9 Y一个子表使用,说明可以被回收掉。这里需要注意,由于Tablet Server执行
* e& J" O3 }% r v# _$ l5 }! xCompaction操作生成一个全新的SSTable与修改元数据这两个操作不是原子的,垃圾0 W h( B w' c2 `' U: b
回收需要避免删除刚刚生成但还没有记录到元数据中的SSTable文件。一种比较简单3 l( Z$ O3 c2 H4 J! A; G% M! t; Q0 u% s
的做法是垃圾回收只删除至少一段时间,比如1小时没有被使用的SSTable文件。1 {+ m4 @. Y6 u% T) U3 X, s# d
6.1.9 讨论: C0 t" E# f6 f0 c/ ~7 S
GFS+Bigtable两层架构以一种很优雅的方式兼顾系统的强一致性和可用性。底层3 i! C" f, `, {! |# U& |
文件系统GFS是弱一致性系统,可用性和性能很好,但是多客户端追加可能出现重复
7 a5 l/ L- ?, N4 C记录等数据不一致问题;上层的表格系统Bigtable通过多级分布式索引的方式使得系
+ ]4 u/ L4 E$ A- A- A# P6 s- ~统对外整体表现为强一致性。Bigtable最大的优势在于线性可扩展,单台机器出现故
. U1 m: G- N- N) `5 {6 Q障可将服务迅速(一分钟以内)迁移到整个集群。Bigtable架构最多可支持几千台的
# e5 o) L; t" c5 J3 E集群规模,通过自动化容错技术大大降低了存储成本。6 }0 n& M* v. ~/ L
Bigtable架构也面临一些问题,如下所示:# i6 n% P2 c$ |- ^& w; D0 V
●单副本服务。Bigtable架构非常适合离线或者半线上应用,然而,Tablet Server- Y& i: l0 K, U4 F0 {7 K6 T: O
节点出现故障时部分数据短时间内无法提供读写服务,不适合实时性要求特别高的, _% s) ?& ~) A. p4 S
业务,如交易类业务。
! a: X5 m5 c' b4 [& m●SSD使用。Google整体架构的设计理念为通过廉价机器构建自动容错的大集* c' l4 Q. m- ^0 M3 H& R% q7 l1 ~
群,然而,随着SSD等硬件技术的发展,机器宕机的概率变得更小,SSD和SAS混合
; r; i& [6 D0 \6 ]) ~存储也变得比较常见,存储和服务分离的架构有些不太适应。( e3 j: l. c. P3 i
●架构的复杂性导致Bug定位很难。Bigtable依赖GFS和Chubby,这些依赖系统本
' h' ]4 t: F* U2 N+ v2 K身比较复杂,另外,Bigtable多级分布式索引和容错等机制内部实现都非常复杂,工
$ y8 T% |- E4 L9 r( F# B9 P程量巨大,使用的过程中如果发现问题很难定位。
( T& M" h7 X% m8 I# x总体上看,Bigtable架构把可扩展性和成本做到了极致,但在线实时服务能力有
3 q$ `( h. T) [* b- B+ m一定的改进空间,适合通用的离线和半线上应用场合。
/ O& t( h, Q0 T' L% d) r$ F% u3 A& O" o! `; ]8 r8 R
2 E% k& ?6 B6 c. u$ ] ?
|
|