|
8.3 系统架构
# f7 T6 y7 v: i+ y2 q8.3.1 整体架构图
+ C" i( E n) b L r2 {, FOceanBase的整体架构如图8-1所示。
1 M Y' C1 H) R: E图 8-1 OceanBase整体架构图0 U) w' _3 } I/ o3 k5 v$ u
OceanBase由如下几个部分组成:
' s$ g& r+ L' C# z% B8 X3 j1 Q, E●客户端:用户使用OceanBase的方式和MySQL数据库完全相同,支持JDBC、 C
* e+ d( y4 w/ y客户端访问,等等。基于MySQL数据库开发的应用程序、工具能够直接迁移到
/ j; O# K: d! S9 OOceanBase。
; d" e- C, x/ m. c& I9 w●RootServer:管理集群中的所有服务器,子表(tablet)数据分布以及副本管: [& R7 {* l+ z$ b ?1 L2 E9 Q
理。 RootServer一般为一主一备,主备之间数据强同步。
0 U- s1 k% p0 g$ [7 v●UpdateServer:存储OceanBase系统的增量更新数据。UpdateServer一般为一主) ] g5 G# ?6 L) ]
一备,主备之间可以配置不同的同步模式。部署时,UpdateServer进程和RootServer1 O8 ~$ c/ @. e+ a
进程往往共用物理服务器。- b- u' Q3 }6 l- ?9 C7 r' ~
●ChunkServer:存储OceanBase系统的基线数据。基线数据一般存储两份或者三
$ t5 \$ y# c0 T& J+ D5 R份,可配置。
0 G3 c7 c* ?: h* M' D1 I●MergeServer:接收并解析用户的SQL请求,经过词法分析、语法分析、查询优
" H9 g2 V/ v2 K化等一系列操作后转发给相应的ChunkServer或者UpdateServer。如果请求的数据分布2 F1 F! E5 Y' \% ]1 g5 A
在多台ChunkServer上,MergeServer还需要对多台ChunkServer返回的结果进行合并。% C" e3 W) R" ?3 H+ o
客户端和MergeServer之间采用原生的MySQL通信协议,MySQL客户端可以直接访问
3 O1 C: I) G7 Y1 S" h6 {" A3 {MergeServer。
: _' _) s @+ I3 g/ v+ iOceanBase支持部署多个机房,每个机房部署一个包含RootServer、
& ^: T d4 d! |3 N( vMergeServer、ChunkServer以及UpdateServer的完整OceanBase集群,每个集群由各自
1 [' N) U" v* w. a* q的RootServer负责数据划分、负载均衡、集群服务器管理等操作,集群之间数据同步9 |1 @ B; ~4 f" n- m
通过主集群的主UpdateServer往备集群同步增量更新操作日志实现。客户端配置了多0 d: M3 B4 K) ]3 F% C1 j2 y; Q
个集群的RootServer地址列表,使用者可以设置每个集群的流量分配比例,客户端根* R1 W; U+ l8 E# l9 C+ H
据这个比例将读写操作发往不同的集群。图8-2是双机房部署示意图。
/ g5 F' I, O2 Q! e图 8-2 OceanBase双机房部署
% J l6 f" }$ j- z9 O- _8.3.2 客户端
$ l( X9 C. R) T; q4 _9 a- J9 G9 Z0 ?OceanBase客户端与MergeServer通信,目前主要支持如下几种客户端:
; U, i+ u: {( g( D. f9 h/ P●MySQL客户端:MergeServer兼容MySQL协议,MySQL客户端及相关工具(如
& H% U) h" r1 u3 W2 ZJava数据库访问方式JDBC)只需要将服务器的地址设置为任意一台Merge-Server的地
# u/ B1 W$ p% h0 s4 x! B! Y址,就可以直接使用。
- T4 _0 V2 l2 _8 s- M●Java客户端:OceanBase内部部署了多台MergeServer,Java客户端提供对 MySQL. w T d5 o$ L+ ^0 P
标准JDBC Driver的封装,并提供流量分配、负载均衡、MergeServer异常处理等功
F7 X$ h9 k, P, V+ ~* |7 K能。简单来讲,Java客户端首先按照一定的策略定位到某台MergeServer,接着调用$ W. ~6 G! \8 @, N
MySQL JDBC Driver往这台MergeServer发送读写请求。Java客户端实现符合JDBC标" ?; f( I! R' ~9 {" H
准,能够支持Spring、iBatis等Java编程框架。/ Y3 Q" u5 _$ {* } F- A. X5 Y( E
●C客户端:OceanBase C客户端的功能和Java客户端类似。它首先按照一定的策' U) A! }) p) t9 P8 O) [
略定位到某台MergeServer,接着调用MySQL标准C客户端往这台MergeServer发送读
2 T0 I0 C' s3 k5 {, p- x写请求。C客户端的接口和MySQL标准C客户端接口完全相同,因此,能够通过+ b; m7 g& {2 n) e% P5 @
LD_PRELOAD的方式将应用程序依赖的MySQL标准C客户端替换为OceanBase C客户
- X `* _9 u* J9 i端,而无需修改应用程序的代码。
2 T: P0 P" x( x8 g! sOceanBase集群有多台MergeServer,这些MergeServer的服务器地址存储在# E0 g! s5 M8 Q5 l* O4 K
OceanBase服务器端的系统表(与Oracle的系统表类似,存储OceanBase系统的元数1 M) Y% P3 t c, E7 m1 w _5 }* B
据)内。OceanBase Java/C客户端首先请求服务器端获取MergeServer地址列表,接着7 A/ O2 W$ W7 N7 H+ p
按照一定的策略将读写请求发送给某台MergeServer,并负责对出现故障的3 h3 I! O8 p. n* G( T
MergeServer进行容错处理。
! G6 Y7 `* j6 O1 H+ H. ZJava/C客户端访问OceanBase的流程大致如下:
$ s+ F2 v9 E: D) r; ~) a3 R$ {* [1)请求RootServer获取集群中MergeServer的地址列表。7 t; p+ |. y0 Z1 Z
2)按照一定的策略选择某台MergeServer发送读写请求。客户端与MergeServer. Z1 `0 M, s, |$ I9 r W
之间的通信协议兼容原生的MySQL协议,因此,只需要调用MySQL JDBC Driver或者 Q1 Y/ J4 c$ a
MySQL C客户端这样的标准库即可。客户端支持的策略主要有两种:随机以及一致
3 S* F* P: C; {( D K$ x4 _性哈希。一致性哈希的主要目的是将相同的SQL请求发送到同一台MergeServer,方8 c" X$ @& |& l7 T$ z7 U
便MergeServer对查询结果进行缓存。+ Y, u8 S5 G; b2 y
3)如果请求MergeServer失败,则从MergeServer列表中重新选择一台 j% l K0 L, _* O- E/ _( ~
MergeServer重试;如果请求某台MergeServer失败超过一定的次数,将这台, `4 r' j/ S1 M& g t
MergeServer加入黑名单并从MergeServer列表中删除。另外,客户端会定期请求
, L( t( ]- Z1 C% I0 c7 ORootServer更新MergeServer地址列表。0 k1 J( q- W0 o, M4 v( P
如果OceanBase部署多个集群,客户端还需要处理多个集群的流量分配问题。使
2 e. \% v2 ]% ~" ^/ z用者可以设置多个集群之间的流量分配比例,客户端获取到流量分配比例后,按照
# G. B2 o$ v5 n5 j( ~6 y( n8 `这个比例将请求发送到不同的集群。
' X! g9 K& u! D6 I$ `+ wOceanBase程序升级版本时,往往先将备集群的读取流量调整为0,这时所有的
) H& ]6 s. _( o( [读写请求都只发往主集群,接着升级备集群的程序版本。备集群升级完成后将流量4 V6 }/ @8 x/ _, o" l# s
逐步切换到备集群观察一段时间,如果没有出现异常,则将所有的流量切到备集& o' `. f8 X# |4 C1 s
群,并将备集群切换为主集群提供写服务。原来的主集群变为新的备集群,升级新
7 g4 O9 H( b+ n! K+ |( M5 e* g s1 i! g的备集群的程序版本后重新分配主备集群的流量比例。
4 T; Q5 f/ z6 D3 }8.3.3 RootServer
, a9 |9 y' J, P }. T/ k( |RootServer的功能主要包括:集群管理、数据分布以及副本管理。+ t+ T! f1 q8 `
RootServer管理集群中的所有MergeServer、ChunkServer以及UpdateServer。每个
- ]; M. s9 s' E; G5 o6 y集群内部同一时刻只允许一个UpdateServer提供写服务,这个UpdateServer成为主
$ N: v6 q. A7 _" w: T9 A& d6 RUpdateServer。这种方式通过牺牲一定的可用性获取了强一致性。RootServer通过租8 J8 U( t; l4 |
约(Lease)机制选择唯一的主UpdateServer,当原先的主UpdateServer发生故障后,
8 Q/ D* a$ o( _4 q* r) m' h5 URootServer能够在原先的租约失效后选择一台新的UpdateServer作为主UpdateServer。. V8 s8 p0 N! i6 t+ b3 w( r) h9 y
另外,RootServer与MergeServer&ChunkServer之间保持心跳(heartbeat),从而能够# u. A. B: X6 k0 I# v/ c5 H+ P5 r
感知到在线和已经下线的MergeServer&ChunkServer机器列表。
B0 E1 I9 G% O& LOceanBase内部使用主键对表格中的数据进行排序和存储,主键由若干列组成并
5 q1 L- m; p: X2 u3 J$ X9 ?且具有唯一性。在OceanBase内部,基线数据按照主键排序并且划分为数据量大致相
0 w- m5 h" m: l; R. m0 ]等的数据范围,称为子表(tablet)。每个子表的默认大小是256MB(可配置)。4 Y" o1 F4 O& p1 M8 S( M
OceanBase的数据分布方式与Bigtable一样采用顺序分布,不同的是,OceanBase没有$ O6 K2 `, l' o, U4 p5 B$ V$ W( @
采用根表(RootTable)+元数据表(MetaTable)两级索引结构,而是采用根表一级! ?! [& |0 S8 d: |( C+ {
索引结构。
0 B5 ~/ d3 A/ U2 `如图8-3所示,主键值在[1,100]之间的表格被划分为四个子表:1~25,26~$ [4 `8 m# a- Z$ V
50,51~80以及81~100。RootServer中的根表记录了每个子表所在的ChunkServer位
% |$ _- r0 w4 T* [/ M/ t: ^置信息,每个子表包含多个副本(一般为三个副本,可配置),分布在多台! a* t7 B+ @8 f) L' `1 o$ ]
ChunkServer中。当其中某台ChunkServer发生故障时,RootServer能够检测到,并且触
J' ~# x k* M, B8 g* k' b发对这台ChunkServer上的子表增加副本的操作;另外,RootServer也会定期执行负载
- Q! I. o; s2 l1 E/ v+ G- h均衡,选择某些子表从负载较高的机器迁移到负载较低的机器上。+ a7 h; ]. T1 {6 t1 l' H3 S
图 8-3 基线数据子表划分/ V9 D& L; ?! W" M' U# u. ~9 i
RootServer采用一主一备的结构,主备之间数据强同步,并通过Linux# J1 ~1 K; H1 ~1 T; u1 L& I( U: I5 c
HA(http://www.linux-ha.org)软件实现高可用性。主备RootServer之间共享VIP,当0 L; i1 \/ o$ @0 F
主RootServer发生故障后,VIP能够自动漂移到备RootServer所在的机器,备1 F, K: F, Q% \) ^
RootServer检测到以后切换为主RootServer提供服务。6 g- g( F- Q! H u& q3 d5 Q
8.3.4 MergeServer
5 v1 b, Z! ~! ] N2 gMergeServer的功能主要包括:协议解析、SQL解析、请求转发、结果合并、多8 F, F, |$ j) T x
表操作等。' D7 K, d. G( u: M$ h4 \
OceanBase客户端与MergeServer之间的协议为MySQL协议。MergeServer首先解
5 ]" m) k6 b1 s `析MySQL协议,从中提取出用户发送的SQL语句,接着进行词法分析和语法分析,+ A3 u* }) q, G) \$ q0 l, w
生成SQL语句的逻辑查询计划和物理查询计划,最后根据物理查询计划调用
; W! C1 s0 F$ J5 B4 e' X# Z8 YOceanBase内部的各种操作符。
' D* {, l+ r& oMergeServer缓存了子表分布信息,根据请求涉及的子表将请求转发给该子表所8 L# P" @( p2 r
在的ChunkServer。如果是写操作,还会转发给UpdateServer。某些请求需要跨多个子
: ~$ v; A; g2 Q表,此时MergeServer会将请求拆分后发送给多台ChunkServer,并合并这些, x3 p. C( o/ K& m, ?
ChunkServer返回的结果。如果请求涉及多个表格,MergeServer需要首先从
" H3 c0 x5 U3 j0 S# E0 sChunkServer获取每个表格的数据,接着再执行多表关联或者嵌套查询等操作。
7 G* u) H5 B4 y9 vMergeServer支持并发请求多台ChunkServer,即将多个请求发给多台
5 L# o; f4 j" y' F( wChunkServer,再一次性等待所有请求的应答。另外,在SQL执行过程中,如果某个( i5 G% }# _: d; X* t9 w. X
子表所在的ChunkServer出现故障,MergeServer会将请求转发给该子表的其他副本所
2 v, Y, s, E0 E7 h在的ChunkServer。这样,ChunkServer故障是不会影响用户查询的。% B/ O9 v# J3 }3 f4 V: z
MergeServer本身是没有状态的,因此,MergeServer宕机不会对使用者产生影
1 Z6 @* N" N! {& k8 \4 g! E5 d& V响,客户端会自动将发生故障的MergeServer屏蔽掉。5 c0 J$ e# h! S" X$ R7 C
8.3.5 ChunkServer
# i1 X G$ I* Y0 S: `% mChunkServer的功能包括:存储多个子表,提供读取服务,执行定期合并以及数
* E; F& M) z3 M! c/ E6 E) o据分发。2 Y7 t9 i* `& w6 U) R
OceanBase将大表划分为大小约为256MB的子表,每个子表由一个或者多个" I ~) L7 x% z
SSTable组成(一般为一个),每个SSTable由多个块(Block,大小为4KB~64KB之
4 b7 X8 X9 C" g2 t0 A4 S$ T间,可配置)组成,数据在SSTable中按照主键有序存储。查找某一行数据时,需要5 F2 K/ R% I' N1 B$ v, j% u
首先定位这一行所属的子表,接着在相应的SSTable中执行二分查找。SSTable支持两; }& b# X; S8 Y( a
种缓存模式,块缓存(Block Cache)以及行缓存(Row Cache)。块缓存以块为单位; z$ ~7 o0 c3 e: x- B+ c5 [4 @
缓存最近读取的数据,行缓存以行为单位缓存最近读取的数据。
6 g5 k0 e$ J0 n1 Q, Q* {; @" _MergeServer将每个子表的读取请求发送到子表所在的ChunkServer,ChunkServer首- W5 f. k' Q1 f
先读取SSTable中包含的基线数据,接着请求UpdateServer获取相应的增量更新数据,7 Z" A' ^* l6 z- o9 C: g
并将基线数据与增量更新融合后得到最终结果。
5 K% R$ e& \& {5 u `( B由于每次读取都需要从UpdateServer中获取最新的增量更新,为了保证读取性. w# C4 o3 i3 s6 t. f. `- ~) Q: d
能,需要限制UpdateServer中增量更新的数据量,最好能够全部存放在内存中。
' v6 t. Y! f7 YOceanBase内部会定期触发合并或者数据分发操作,在这个过程中,ChunkServer将从
; [9 \ r+ z" j9 Y' |! E/ BUpdateServer获取一段时间之前的更新操作。通常情况下,OceanBase集群会在每天
- e, `' L# |8 ?: o的服务低峰期(凌晨1:00开始,可配置)执行一次合并操作。这个合并操作往往也称% T3 E2 K; ^" \
为每日合并。
) d5 o. V/ e- Q% h C* o. c$ K8.3.6 UpdateServer/ f- Q* E( j5 t& R4 U" @
UpdateServer是集群中唯一能够接受写入的模块,每个集群中只有一个主Update-6 U& T+ m0 t! T) K4 l0 ^% `
Server。UpdateServer中的更新操作首先写入到内存表,当内存表的数据量超过一定
* Y' J" |, w0 l/ o2 G值时,可以生成快照文件并转储到SSD中。快照文件的组织方式与ChunkServer中的, |8 h: b' g( t6 k, z+ X
SSTable类似,因此,这些快照文件也称为SSTable。另外,由于数据行的某些列被更
4 H1 u' T- m2 a0 g1 u8 v; }$ y新,某些列没被更新,SSTable中存储的数据行是稀疏的,称为稀疏型SSTable。& b: c. K4 {- _
为了保证可靠性,主UpdateServer更新内存表之前需要首先写操作日志,并同步
* w4 }9 C% n8 s: G e7 M到备UpdateServer。当主UpdateServer发生故障时,RootServer上维护的租约将失效,
, w7 H! I- h) t/ K/ \, Y; `: l# A) c此时,RootServer将从备UpdateServer列表中选择一台最新的备UpdateServer切换为主
% E7 b* Q9 G4 D/ d* @6 xUpdateServer继续提供写服务。UpdateServer宕机重启后需要首先加载转储的快照文9 S, p$ \1 g8 G3 S( j+ u
件(SSTable文件),接着回放快照点之后的操作日志。
6 q7 c* n, e# S( [由于集群中只有一台主UpdateServer提供写服务,因此,OceanBase很容易地实$ L) L# z1 U; t1 \5 q9 X5 v/ Z
现了跨行跨表事务,而不需要采用传统的两阶段提交协议。当然,这样也带来了一/ u6 k0 [; o6 O6 g% x2 O: Z8 z
系列的问题。由于整个集群所有的读写操作都必须经过UpdateServer,UpdateServer的- v8 o; W2 C- P# U) l
性能至关重要。OceanBase集群通过定期合并和数据分发这两种机制将UpdateServer1 u6 e8 D8 Z! S
一段时间之前的增量更新源源不断地分散到ChunkServer,而UpdateServer只需要服务
6 s( q0 }! k- C最新一小段时间新增的数据,这些数据往往可以全部存放在内存中。另外,系统实
6 x2 {* d* L* o4 Z0 g; r/ }现时也需要对UpdateServer的内存操作、网络框架、磁盘操作做大量的优化。( [9 G) ]/ K4 T/ c% \1 W
8.3.7 定期合并&数据分发
7 E1 B0 j8 a- i定期合并和数据分发都是将UpdateServer中的增量更新分发到ChunkServer中的手6 E: Q# u! e# `, Z
段,二者的整体流程比较类似:$ X; _6 D F9 B4 P
1)UpdateServer冻结当前的活跃内存表(Active MemTable),生成冻结内存) g$ ^- ]+ d8 T: h6 x$ Y
表,并开启新的活跃内存表,后续的更新操作都写入新的活跃内存表。) b, Z* r% Z# G; y
2)UpdateServer通知RootServer数据版本发生了变化,之后RootServer通过心跳3 V& R1 y3 t# x4 c, Z
消息通知ChunkServer。0 X3 B( M: |+ H9 j
3)每台ChunkServer启动定期合并或者数据分发操作,从UpdateServer获取每个2 W' q. z6 f) j( X {% x$ u/ x
子表对应的增量更新数据。
2 z. e6 s$ _( N* E8 `% d定期合并与数据分发两者之间的不同点在于,数据分发过程中ChunkServer只是
" y/ ^$ v$ v' }8 n5 U% }将UpdateServer中冻结内存表中的增量更新数据缓存到本地,而定期合并过程中, v) }0 r$ q/ ]0 \" `! y6 N! p
ChunkServer需要将本地SSTable中的基线数据与冻结内存表的增量更新数据执行一次
& c3 x+ E& N) `# p; |多路归并,融合后生成新的基线数据并存放到新的SSTable中。定期合并对系统服务
: Q' F: {3 `5 v3 g5 `能力影响很大,往往安排在每天服务低峰期执行(例如凌晨1点开始),而数据分发 m+ F8 @" J/ [5 X7 k3 |
可以不受限制。; m: c- f, t, M1 V. U; V
如图8-4,活跃内存表冻结后生成冻结内存表,后续的写操作进入新的活跃内存% J- h# g# l) d4 Y
表。定期合并过程中ChunkServer需要读取UpdateServer中冻结内存表的数据、融合后
8 w; s9 K( z' P/ F$ R生成新的子表,即:
, T5 b- V. {+ z新子表=旧子表+冻结内存表
. M0 S* H- v) ^" ]9 | q- p图 8-4 定期合并不停读服务/ N; a1 m" _4 A* N) s% s
虽然定期合并过程中各个ChunkServer的各个子表合并时间和完成时间可能都不( S- B$ \/ F! R; ? G
相同,但并不影响读取服务。如果子表没有合并完成,那么使用旧子表,并且读取$ m0 v. l2 u2 @
UpdateServer中的冻结内存表以及新的活跃内存表;否则,使用新子表,只读取新的
& ]" o" l/ G t8 ?9 y, h9 h8 N3 t0 t活跃内存表,即:& l* f& | C' O
查询结果=旧子表+冻结内存表+新的活跃内存表7 @: V' b# T# F9 ]
=新子表+新的活跃内存表
1 @3 Y* {- c. `7 Y
9 t" t2 Z9 ?7 g' }4 c- j l! m$ F, }+ H; P% v% l, O
|
|