|
第6章 分布式表格系统
. t7 ^9 K( X9 u( E8 q) q4 }$ ]- B分布式表格系统对外提供表格模型,每个表格由很多行组成,通过主键唯一标
6 W' d8 e3 m% a% f8 Q( R识,每一行包含很多列。整个表格在系统中全局有序,适用3.3.2节中讲的顺序分
" q* E3 N# C5 c2 J" A- n* V1 @布。# a2 c1 v+ g1 K7 ? f7 O2 q( z3 W6 O
Google Bigtable是分布式表格系统的始祖,它采用双层结构,底层采用GFS作为
7 c3 l) [/ E0 t3 ^& D持久化存储层。GFS+Bigtable双层架构是一种里程碑式的架构,其他系统,包括
. n- Z5 h7 b/ Y$ u# o+ t( @Microsoft分布式存储系统Windows Azure Storage以及开源的Hadoop系统,均为其模仿
1 A* X) E& n- ^4 x1 M' ~者。Bigtable的问题在于对外接口不够丰富,因此,Google后续开发了两套系统,一
! G! \! s) ^& l1 t6 x2 g7 I套是Megastore,构建在Bigtable之上,提供更加丰富的使用接口;另外一套是; Z9 f- y" W5 H) l8 o
Spanner,支持跨多个数据中心的数据库事务,下一章会专门介绍。& {' R2 P8 i: z$ x% Z8 y: g
本章首先详细介绍Bigtable的架构及实现,接着分析Megastore的架构,最后介绍
* m! Z6 L9 v; ]. i7 a* s0 h, rMicrosoft Azure Storage的架构。
/ T) P7 p r: R0 O6.1 Google Bigtable1 H2 B" @+ v( P7 `# c2 o
Bigtable是Google开发的基于GFS和Chubby的分布式表格系统。Google的很多数" P% F- Z; O9 M6 a3 y
据,包括Web索引、卫星图像数据等在内的海量结构化和半结构化数据,都存储在
7 M- S5 [: H# _, P' K! _6 LBigtable中。与Google的其他系统一样,Bigtable的设计理念是构建在廉价的硬件之2 c% q; d# N/ d: r/ G8 Z
上,通过软件层面提供自动化容错和线性可扩展性能力。
) s" \" O: D) `6 HBigtable系统由很多表格组成,每个表格包含很多行,每行通过一个主键(Row
2 P; k" Z$ U2 O* B8 H0 lKey)唯一标识,每行又包含很多列(Column)。某一行的某一列构成一个单元& L8 Y- I0 ~$ u$ f
(Cell),每个单元包含多个版本的数据。整体上看,Bigtable是一个分布式多维映
# O' W: U) q6 ~8 ^1 Z- Y射表,如下所示:* ]2 g1 \2 h/ }; l, @
(row:string,column:string,timestamp:int64)->string
5 Q4 {! T0 q- `* C" f1 Y$ O* B% R& ^另外,Bigtable将多个列组织成列族(column family),这样,列名由两个部分
$ u8 M% c( l, A6 N6 [7 m9 O组成:(column family,qualifier)。列族是Bigtable中访问控制的基本单元,也就是1 ]# u; m4 s3 \2 [, X p: V
说,访问权限的设置是在列族这一级别上进行的。Bigtable中的列族在创建表格的时
* @; Q" o9 {3 i$ n4 w" I" e( W候需要预先定义好,个数也不允许过多;然而,每个列族包含哪些qualifier是不需要$ g+ v9 E4 b, T2 b! u6 j* [
预先定义的,qualifier可以任意多个,适合表示半结构化数据。$ A( ^7 l6 L: ^9 t
Bigtable数据的存储格式如图6-1所示。
8 g& P1 v! D2 {7 l5 `5 n. w图 6-1 Bigtable数据存储格式$ Z9 ~& l5 a# p3 U$ G& \
Bigtable中的行主键可以是任意的字符串,最大不超过64KB。Bigtable表中的数/ `/ k+ l' C8 V( Y
据按照行主键进行排序,排序使用的是字典序。图6-1中行主键com.cnn.www是域名$ X- _/ H+ a- N/ _8 t6 M, C0 e
www.cnn.com变换后的结果,这样做的好处是使得所有www.cnn.com下的子域名在系
( L# c: p q# O5 g统中连续存放。这一行数据包含两个列族:"contents"和"anchor"。其中,列
! b( S3 c7 o! }9 _+ b1 F, |5 Z族"anchor"又包含两个列,qualifier分别为"cnnsi.com"和"my:look.ca"。. o+ |! G7 H% U2 l
Google的很多服务,比如Web检索和用户的个性化设置,都需要保存不同时间的0 z- c, O# }1 X8 s! ^3 r, {
数据,这些不同的数据版本必须通过时间戳来区分。图6-1中的t 4 、t 5 和t 6 表示保存了2 A# I6 ]/ k( J( G' S) |$ ]- K
三个时间点获取的网页。为了简化不同版本的数据管理,Bigtable提供了两种设置:4 k/ d6 W+ C9 v
一种是保留最近的N个不同版本,另一种是保留限定时间内的所有不同版本,比如可
: K$ X4 r% T, k以保存最近10天的所有不同版本的数据。失效的版本将会由Bigtable的垃圾回收机制 Q$ p2 `: c; c! H: V
自动删除。1 c1 s/ D+ J, k5 h& I# f
6.1.1 架构
$ ~: V& ~7 e. y! @Bigtable构建在GFS之上,为文件系统增加一层分布式索引层。另外,Bigtable依6 @0 m# J0 n' ?# o5 @
赖Google的Chubby(即分布式锁服务)进行服务器选举及全局信息维护。
" U- m, E( \5 j% j( t如图6-2所示,Bigtable将大表划分为大小在100~200MB的子表(tablet),每个; ]: _- H9 N9 p$ T) e
子表对应一个连续的数据范围。Bigtable主要由三个部分组成:客户端程序库
; a$ Z. z. G! A/ A(Client)、一个主控服务器(Master)和多个子表服务器(Tablet Server)。) `7 L: y$ K/ R) Y& ^ }
图 6-2 Bigtable的整体架构, |8 h6 O% D* h. e
●客户端程序库(Client):提供Bigtable到应用程序的接口,应用程序通过客户
$ D3 _3 [- V( A G( X- f端程序库对表格的数据单元进行增、删、查、改等操作。客户端通过Chubby锁服务+ a% J( A# z- i5 U" ]" R/ q
获取一些控制信息,但所有表格的数据内容都在客户端与子表服务器之间直接传
2 V$ w0 v# ?2 D7 O% E2 K送;
/ C' t- o! v; Z- A2 x6 C, X9 S●主控服务器(Master):管理所有的子表服务器,包括分配子表给子表服务6 q- y. M& N4 F6 w ~/ Q% R
器,指导子表服务器实现子表的合并,接受来自子表服务器的子表分裂消息,监控
) a6 I4 B2 t5 P3 Z* \% A子表服务器,在子表服务器之间进行负载均衡并实现子表服务器的故障恢复等。, L) V$ y& o2 g! ^! E
●子表服务器(Tablet Server):实现子表的装载/卸出、表格内容的读和写,子& K2 N' _5 O' f0 U
表的合并和分裂。Tablet Server服务的数据包括操作日志以及每个子表上的sstable数
8 i: d. l. M, G6 F* [' B据,这些数据存储在底层的GFS中。
i% d+ y: y) l+ M9 aBigtable依赖于Chubby锁服务完成如下功能:! s8 x; I1 V' ^. K
1)选取并保证同一时间内只有一个主控服务器;1 g& U3 r5 { j3 a" ^: ?
2)存储Bigtable系统引导信息;
5 H% m9 Q! u* q! ?0 v8 P! O- V' M3)用于配合主控服务器发现子表服务器加入和下线;; H' @/ f& b g, Y! y: b, D
4)获取Bigtable表格的schema信息及访问控制信息。 Q1 @+ f9 w, n3 s6 j; Q
Chubby是一个分布式锁服务,底层的核心算法为Paxos。Paxos算法的实现过程需8 I) K9 y' K4 G- j/ y5 m) H
要一个“多数派”就某个值达成一致,进而才能得到一个分布式一致性状态。也就是; `8 i0 H% A* w T) i: f
说,只要一半以上的节点不发生故障,Chubby就能够正常提供服务。Chubby服务部
& F9 t' M' S m m1 B/ u3 g署在多个数据中心,典型的部署为两地三数据中心五副本,同城的两个数据中心分* q D' t9 p. H7 G6 n% V
别部署两个副本,异地的数据中心部署一个副本,任何一个数据中心整体发生故障
+ Q8 C0 Q- ?! i) W8 E! d& X都不影响正常服务。( N' u4 Y0 v. q# ^# }& f" ?! q# b
Bigtable包含三种类型的表格:用户表(User Table)、元数据表(Meta Table)
! _2 @1 X$ e# k" k' ^3 c8 H和根表(Root Table)。其中,用户表存储用户实际数据;元数据表存储用户表的元" a7 L) f8 e' w7 I
数据;如子表位置信息、SSTable及操作日志文件编号、日志回放点等,根表用来存
8 _2 {) p8 Y& p' F3 Z/ |+ g1 f( x储元数据表的元数据;根表的元数据,也就是根表的位置信息,又称为Bigtable引导) r( {$ C9 {; |% `) C
信息,存放在Chubby系统中。客户端、主控服务器以及子表服务器执行过程中都需! @' x) N2 |4 c5 ?* S& P1 \
要依赖Chubby服务,如果Chubby发生故障,Bigtable系统整体不可用。
4 z; i( S& h9 f1 i% I9 {, l G6.1.2 数据分布! _/ T% }, ~+ G; G- C
Bigtable中的数据在系统中切分为大小100~200MB的子表,所有的数据按照行) j8 V6 b7 ?% G+ O i# [* u
主键全局排序。Bigtable中包含两级元数据,元数据表及根表。用户表在进行某些操
# w2 g: m& x( [+ n3 ~. ?/ D3 C1 B作,比如子表分裂的时候需要修改元数据表,元数据表的某些操作又需要修改根
/ J! ^: O0 q3 `1 ^( O表。通过使用两级元数据,提高了系统能够支持的数据量。假设平均一个子表大小
G: [4 o2 ]5 u- ~5 h为128MB,每个子表的元信息为1KB,那么一级元数据能够支持的数据量为
9 f% o; U, U3 R7 }+ K$ e& p3 E128MB×(128MB/1KB)=16TB,两级元数据能够支持的数据量为
9 @( A! C" h: y' T3 V16TB×(128MB/1KB)=2048 PB,满足几乎所有业务的数据量需求。如图6-3所示。
+ I: @) N- I2 L9 p: L+ t图 6-3 Bigtable数据结构 ^- |$ l* A: G% z L
客户端查询时,首先从Chubby中读取根表的位置,接着从根表读取所需的元数 u( o$ W) l7 F" i) p) B
据子表的位置,最后就可以从元数据子表中找到待查询的用户子表的位置。为了减
% A! i' j4 s9 A6 n6 d少访问开销,客户端使用了缓存(cache)和预取(prefetch)技术。子表的位置信息4 ]4 G3 m9 N) w% A6 Q& h
被缓存在客户端,客户端在寻址时首先查找缓存,一旦缓存为空或者缓存信息过
& M! t' @/ @7 B0 l: w0 ~期,客户端就需要请求子表服务器的上一级元数据表获取位置信息,比如用户子表
% ^ a+ M, k1 N1 E缓存过期需要请求元数据表,元数据子表缓存过期需要请求根表,根表缓存过期需0 l* {1 C4 n2 \& c% y: F1 K" g
要读取Chubby中的引导信息。如果缓存为空,最多需要三次请求;如果缓存信息过
4 Y6 B* M" c$ ?* P期,最多需要六次请求,其中三次用来确定信息是过期的,另外三次获取新的地7 j+ I& k" Z2 Z! z @
址。预取则是在每次访问元数据表时不仅仅读取所需的子表元数据,而是读取连续
: n( c% }- Q2 _的多个子表元数据,这样查找下一个子表时不需要再次访问元数据表。
. c7 V( i: y1 A+ |9 @& F L9 s6.1.3 复制与一致性
. `% m# X3 g+ wBigtable系统保证强一致性,同一个时刻同一个子表只能被一台Tablet Server服2 M: B+ q' b+ D3 ~$ N! r- D, e* J
务,也就是说,Master将子表分配给某个Tablet Server服务时需要确保没有其他的
6 e( r* `1 t( m, e6 \Tablet Server正在服务这个子表。这是通过Chubby的互斥锁机制保证的,Tablet Server
! f3 B& h5 h; G启动时需要获取Chubby互斥锁,当Tablet Server出现故障,Master需要等到Tablet
, [$ g- O& p8 [8 ]- ~Server的互斥锁失效,才能把它上面的子表迁移到其他Tablet Server。7 d0 J% i* K) q& q; _( A
Bigtable的底层存储系统为GFS(参见前面4.1节)。GFS本质上是一个弱一致性
. q4 n6 Z$ V$ _! v系统,其一致性模型只保证“同一个记录至少成功写入一次”,但是可能存在重复记
* k9 }# c- `- ^% _. P, ~% ]录,而且可能存在一些补零(padding)记录。! w3 B. E6 x' q/ M9 z2 o- j
Bigtable写入GFS的数据分为两种:# C. D7 h* q- [: f
●操作日志。当Tablet Server发生故障时,它上面服务的子表会被集群中的其他
; T0 L* z. e6 O. bTablet Server加载继续提供服务。加载子表可能需要回放操作日志,每条操作日志都, A& {3 U5 ]4 @1 @
有唯一的序号,通过它可以去除重复的操作日志。* C7 ^, I: \6 P* Z# @( ~
●每个子表包含的SSTable数据。如果写入GFS失败可以重试并产生多条重复记
! B# ?4 a$ a) H+ U录,但是Bigtable只会索引最后一条写入成功的记录。
- {0 k" O% M4 ~* t' ABigtable本质上是构建在GFS之上的一层分布式索引,通过它解决了GFS遗留的' {/ k# {8 e; b1 W; M: Y3 D
一致性问题,大大简化了用户使用。! C- M& B6 u% u+ {$ x
6.1.4 容错7 Z/ B7 m7 X& l* y
Bigtable中Master对Tablet Server的监控是通过Chubby完成的,Tablet Server在初始+ y$ p* O- \1 n z
化时都会从Chubby中获取一个独占锁。通过这种方式所有的Tablet Server基本信息被
: S6 @7 Y; B: C" E保存在Chubby中一个称为服务器目录(Server Directory)的特殊目录之中。Master通
" W- i- Y( p, B过检测这个目录以随时获取最新的Tablet Server信息,包括目前活跃的Tablet Server,
! |9 x/ \0 F9 O7 q以及每个Tablet Server上现已分配的子表。对于每个Tablet Server,Master会定期询问其/ t( p P0 p7 w% T8 t3 N
独占锁的状态。如果Tablet Server的锁丢失或者没有回应,则此时可能有两种情况,8 \2 b' f3 e, ~
要么是Chubby出现了问题,要么是Tablet Server出现了问题。对此Master首先自己尝
+ {' O' A+ k% O4 ` Z: h试获取这个独占锁,如果失败说明是Chubby服务出现问题,否则说明是Tablet Server
: U6 c L( f. n2 t* z k7 ~% k出现了问题。Master将中止这个Tablet Server并将其上的子表全部迁移到其他Tablet |# q. Y3 g x0 n
Server。
& h7 `6 l5 g9 Z& Q# q每个子表持久化的数据包含两个部分:操作日志以及SSTable。Tablet Server发生
( _) ]$ s8 S/ v$ t! D" {故障时某些子表的一些更新操作还在内存中,需要通过回放操作日志来恢复。为了
& l5 V! M6 K9 F7 \. V5 i0 |提高性能,Tablet Server没有为它服务的每个子表写一个操作日志文件,而是把所有
7 u& X+ P, F( {! b它服务的子表的操作日志混在一起写入GFS,每条日志通过<表格编号,行主键,日
7 o- _4 ?) K* H5 s, R- g志序列号>来唯一标识。当某个Tablet Server宕机后,Master将该Tablet Server服务的5 L8 \* e' t; l' }! y4 D
子表分配给其他Tablet Server。为了减少Tablet Server从GFS读取的日志数据量,
5 L K% w, m. h$ {* b+ \Master将选择一些Tablet Server对日志进行分段排序。排好序后,同一个子表的操作' C* f- J# [' w$ \
日志连续存放,Tablet Server恢复某个子表时只需要读取该子表对应的操作日志即
1 x1 B% I! e" z可。Master需要尽可能选择负载低的Tablet Server执行排序,并且需要处理排序任务
* v; D( e# h0 D5 ~: g4 j失败的情况。6 A) e) j0 Q c4 p: E4 D9 Z
Bigtable Master启动时需要从Chubby中获取一个独占锁,如果Master发生故障,$ o9 C* l: b' c& r/ d- R
Master的独占锁将过期,管理程序会自动指定一个新的Master服务器,它从Chubby成: ?# @( Q, P) a; N+ m. m1 R& A
功获取独占锁后可以继续提供服务。2 u% {1 ~6 S4 Y) m6 A4 S T
6.1.5 负载均衡9 I$ l0 |8 f* W4 {9 {) E z' |
子表是Bigtable负载均衡的基本单位。Tablet Server定期向Master汇报状态,当状
( [5 T3 X, [9 Z) x/ t+ V% Q( s, n态检测时发现某个Tablet Server上的负载过重时,Master会自动对其进行负载均衡,5 i' p7 t+ n5 u
即执行子表迁移操作。子表迁移分为两步:第一步请求原有的Tablet Server卸载子# Y- G; C o5 C Z& Q6 I* U
表;第二步选择一台负载较低的Tablet Server加载子表。Master发送命令请求原有的
5 I# S3 K W$ F% s) [' L! yTablet Server卸载子表,原有Tablet Server解除加在子表上的互斥锁,而新的Tablet& s* f5 ~- [! H, _( y( O# T# c C) b" X
Server加载子表时需要首先获取互斥锁。如果原有Tablet Server发生故障,新的Tablet/ R3 y8 D' Q; f5 @6 a
Server需要等待原有Tablet Server加在子表上的互斥锁过期。子表迁移前原有的Tablet5 P! r" L0 R; L/ t6 H* P5 p& u8 I
Server会对其执行Minor Compaction操作,将内存中的更新操作以SSTable文件的形式
. J& a, |) ]4 k转储到GFS中,因此,负载均衡带来的子表迁移在新的Tablet Server上不需要回放操
* z% R0 u+ z7 g7 ^. n7 F$ u作日志。7 D2 \3 R1 m. }) Y( y
子表迁移的过程中有短暂的时间需要停服务,为了尽可能减少停服务的时间,
/ u/ r+ _$ u" P$ dBigtable内部采用两次Minor Compaction的策略。具体操作如下:) x1 l* m7 _" {
1)原有Tablet Server对子表执行一次Minor Compaction操作,操作过程中仍然允1 Y8 l A# {+ O; v
许写操作。
' x$ g y6 [; l6 v* u2)停止子表的写服务,对子表再次执行一次Minor Compaction操作。由于第一
( a/ ]# v- C9 o' { [; \次Minor Compaction过程中写入的数据一般比较少,第二次Minor Compaction的时间- \. e0 y9 y6 ~
会比较短。0 O! E ^/ o9 J% K5 Q6 s* E
由于Bigtable负载均衡的过程中会停一会读写服务,负载均衡策略不应当过于激8 O! ?# g4 z' m6 U
进。负载均衡涉及的因素很多,Tablet Server通过心跳定时将读、写个数、磁盘、内
/ `1 ^4 `4 i% B) `. e3 b" W7 L6 I存负载等信息发送给Master,Master根据负载计算公式计算出需要迁移的子表,然后放
7 v5 i* h, E5 y1 ?% I2 ~0 H5 ]入迁移队列中等待执行。
5 J1 l. W9 y. M$ `" Q! m4 _6.1.6 分裂与合并
) _- l- T" {0 I) ~ e) B随着数据不断写入和删除,某些子表可能太大,某些子表可能太小,需要执行
) r* X6 y. C, C, r0 u, A9 [& ^% g子表分裂与合并操作。顺序分布与哈希分布的区别在于哈希分布往往是静态的,而& X. t& a& }% y0 |$ f
顺序分布是动态的,需要通过分裂与合并操作动态调整。
+ G# R6 u1 |% _Bigtable每个子表的数据分为内存中的MemTable和GFS中的多个SSTable,由于9 u5 e1 Z- ~( O: F' h* Q/ t
Bigtable中同一个子表只被一台Tablet Server服务,进行分裂时比较简单。Bigtable上
1 q" q& D* x* H/ s' `执行分裂操作不需要进行实际的数据拷贝工作,只需要将内存中的索引信息分成两) m( k1 F- C: t: O& t$ B
份,比如分裂前子表的范围为(起始主键,结束主键],在内存中将索引分成(起始
. }9 W5 w* e. M& m9 [主键,分裂主键]和(分裂主键,结束主键]两个范围。例如,某个子表(1,10]的分
3 p) l0 H# Z" Z裂主键为5,那么,分裂后生成的两个子表的数据范围为:(1,5]和(5,10]。分裂
; \! z" Q+ }3 c以后两个子表各自写不同的MemTable,等到执行Compaction操作时再根据分裂后的# T8 u8 L% q5 g* ~
子表范围生成不同的SSTable,无用的数据自然成为垃圾被回收。5 h( L+ h' }% h" K( Q4 m
分裂操作由Tablet Server发起,需要修改元数据,即用户表的分裂需要修改元数# b% M! F7 v, ^, y
据表,元数据表的分裂需要修改根表。分裂操作需要增加一个子表,相当于在元数
, f; e! W/ W4 T: [' E; x E据表中增加一行,通过Bigtable的行事务保证原子性。只要修改元数据表成功,分裂
- L, o. \' E/ [操作就算成功。分裂成功后Tablet Server将向Master汇报,如果出现Tablet Server故
( ]" {' i' x w& y9 O6 l障,Master可能丢失汇报分裂消息。新的Tablet Server加载这个子表时将发现它已经
& k) [( N" z) F8 m$ f, q分裂,并通知Master。
* h/ V2 o/ C' O2 h' s/ L合并操作由Master发起,相比分裂操作要更加复杂。由于待合并的两个子表可能
}; e5 q' {, E' F被不同的Tablet Server加载,合并的第一步需要迁移其中一个子表,以使它们在同一5 h1 e8 O: |3 y- `6 F! E+ K& b
个Tablet Server上,接着通知Tablet Server执行子表合并。子表合并操作具体实现时非
2 h( f* o3 g& d$ K* k& `6 i" U常麻烦,有兴趣的读者可以自行思考。( L! t/ i+ V7 Z3 _" G& |
6.1.7 单机存储( l1 z) \) _5 n' `; A4 z
如图6-4所示,Bigtable采用Merge-dump存储引擎。数据写入时需要先写操作日
* M- Y8 d9 J" @7 n8 v" g# x& H志,成功后应用到内存中的MemTable中,写操作日志是往磁盘中的日志文件追加数
6 {& R6 @/ a' @1 Z9 r1 X1 G据,很好地利用了磁盘设备的特性。当内存中的MemTable达到一定大小,需要将
) U6 I, J: \4 b, N) v2 h2 _MemTable转储(Dump)到磁盘中生成SSTable文件。由于数据同时存在MemTable和
9 o2 w8 K8 {/ Y- `# @6 i可能多个SSTable中,读取操作需要按从旧到新的时间顺序合并SSTable和内存中的
2 e) Q. [( `/ f+ D+ x$ i& xMemTable数据。数据在SSTable中连续存放,因此可以同时满足随机读取和顺序读取
1 L5 O2 ~6 N. N0 B. s7 z ~7 i两种需求。为了防止磁盘中的SSTable文件过多,需要定时将多个SSTable通过& m/ E- P0 i/ N( _/ x
compaction过程合并为一个SSTable,从而减少后续读操作需要读取的文件个数。一
( S' Z" J2 Y+ n; q1 u C, R般情况下,如果写操作比较少,我们总是能够使得对每一份数据同时只存在一个3 V. h# M+ f2 p n- w+ b2 `
SSTable和一个MemTable,也就是说,随机读取和顺序读取都只需要访问一次磁盘,$ B6 S C K, L- k0 n
这对于线上服务基本上都是成立的。
6 }+ v' D. \4 v' f" Y7 \7 G6 z图 6-4 Bigtable单机存储引擎/ k7 @ c Y2 P9 |+ o& |9 |7 j9 y
插入、删除、更新、增加(Add)等操作在Merge-dump引擎中都看成一回事,除. V4 ]" i1 r6 h
了最早生成的SSTable外,SSTable中记录的只是操作,而不是最终的结果,需要等到
1 k' c' S. ^2 [$ f4 G4 J读取(随机或者顺序)时才合并得到最终结果。
, @# |* C; U, }4 B) ^7 O" F$ F6 B; @Bigtable中包含三种Compaction策略:Minor Compaction、Merging Compaction和
4 X" m; z% N6 M8 xMajor Compaction。其中,Minor Compaction把内存中的MemTable转储到GFS中,# i2 B4 y! V, G; D7 Q0 k! F
Merging Compaction和Major Compaction合并GFS中的多个SSTable文件生成一个更大
1 q3 g1 p5 a8 u0 M, k的SSTable。Minor Compaction主要是为了防止内存占用过多,Merging和Major
$ e. q; W/ P$ P& Q0 k7 n. q/ T2 RCompaction则是为了防止读取文件个数过多。Major Compaction与Merging Compaction, ^% ]& z5 o+ n# \! E( `
的区别在于Major Compaction会合并所有的SSTable文件和内存中的MemTable,生成
: R' [8 l4 j: f( p最终结果;而Merging Compaction生成的SSTable文件可能包含一些操作,比如删除、; p; R O1 B7 O' X
增加等。
* e0 K& i5 C( h8 u- T数据在SSTable中按照主键有序存储,每个SSTable由若干个大小相近的数据块
: V3 d# h2 K. r% I/ y3 G(Block)组成,每个数据块包含若干行。数据块的大小一般在8~64KB之间,允许7 d1 s5 L+ Z8 F
用户配置。Tablet Server的缓存包括两种:块缓存(Block Cache)和行缓存(Row
. P, j6 j! B) Y7 O" BCache)。其中,块缓存的单位为SSTable中的数据块,行缓存的单位为一行记录。随! `" P: Q( Q7 E9 O/ ]4 {+ \/ G4 c
机读取时,首先查找行缓存;如果行缓存不命中,接着再查找块缓存。另外,% t: D; X; a8 \2 x! X; V& g
Bigtable还支持布隆过滤器(Bloom Filter),如果读取的数据行在SSTable中不存在,/ {$ F. _4 t$ d2 K, N
可以通过布隆过滤器发现,从而避免一次读取GFS文件操作。
: V: K! w$ D- X ~5 E' a! c- k6.1.8 垃圾回收
, W( ~; N5 k2 @$ p$ T, \& M4 OCompaction后生成新的SSTable,原有的SSTable成为垃圾需要被回收掉。每个子, ?0 r! Q) f( _' s. Z& B# E
表正在引用的SSTable文件保存在元数据中。Master定期执行垃圾回收任务,这是一
4 d: X- |6 m" x1 v3 Z个标记删除(mark-and-sweep)过程。首先扫描GFS获取所有的SSTable文件,接着扫
+ g- s' U1 a+ l描根表和元数据表获取所有正在使用的SSTable文件,如果GFS中的SSTable没被任何
; }9 f# \1 s( Q8 ]- r一个子表使用,说明可以被回收掉。这里需要注意,由于Tablet Server执行
4 @0 A! w8 v1 ?. I5 s% u n# yCompaction操作生成一个全新的SSTable与修改元数据这两个操作不是原子的,垃圾
: J1 Y+ b. |/ c( V8 F回收需要避免删除刚刚生成但还没有记录到元数据中的SSTable文件。一种比较简单
5 K6 H# o" f c( A的做法是垃圾回收只删除至少一段时间,比如1小时没有被使用的SSTable文件。
- O2 n- J( w' p, \ K- V5 J6.1.9 讨论. U9 N3 O* P: X w* I, s4 f
GFS+Bigtable两层架构以一种很优雅的方式兼顾系统的强一致性和可用性。底层
5 ]+ [5 [% o- _* i, s" N文件系统GFS是弱一致性系统,可用性和性能很好,但是多客户端追加可能出现重复: {7 i+ G/ ~3 Z
记录等数据不一致问题;上层的表格系统Bigtable通过多级分布式索引的方式使得系+ ^: o b6 W, l7 a. d
统对外整体表现为强一致性。Bigtable最大的优势在于线性可扩展,单台机器出现故
0 m3 X! g" ~2 V. f7 q' V! {, ]" {障可将服务迅速(一分钟以内)迁移到整个集群。Bigtable架构最多可支持几千台的
. e( x" }8 c: f' C T( g6 k8 t' n集群规模,通过自动化容错技术大大降低了存储成本。
- i" x' d% T4 f# ?' l p YBigtable架构也面临一些问题,如下所示:
7 O- N1 A/ v: C2 B●单副本服务。Bigtable架构非常适合离线或者半线上应用,然而,Tablet Server
9 T* t% w3 U9 k节点出现故障时部分数据短时间内无法提供读写服务,不适合实时性要求特别高的% B0 w4 K" Z( _
业务,如交易类业务。8 G* m* ]' _0 W( |6 B( N
●SSD使用。Google整体架构的设计理念为通过廉价机器构建自动容错的大集0 T: X+ n7 O+ ]+ a) ?, d
群,然而,随着SSD等硬件技术的发展,机器宕机的概率变得更小,SSD和SAS混合+ [% l" I" T# X* S6 m" H7 v# A
存储也变得比较常见,存储和服务分离的架构有些不太适应。
+ Q" J V" X7 ?% X! b●架构的复杂性导致Bug定位很难。Bigtable依赖GFS和Chubby,这些依赖系统本5 m2 b# t7 u! U3 J7 S" ~' \
身比较复杂,另外,Bigtable多级分布式索引和容错等机制内部实现都非常复杂,工
( k: R' g/ c6 R. k程量巨大,使用的过程中如果发现问题很难定位。) l+ i' \% e. n" i% x9 r# H: T
总体上看,Bigtable架构把可扩展性和成本做到了极致,但在线实时服务能力有
0 ?" V6 F% G9 ]) ]9 ]% d# p! c8 `一定的改进空间,适合通用的离线和半线上应用场合。
4 t% K- D& {8 h: J$ Q5 H" r
! P. W& x1 q2 [( V( l: n X1 k3 R- X& i8 ?$ o" k
|
|