java自学网VIP

Java自学网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2554|回复: 0

《大规模分布式存储系统》第8章OceanBase架构初探【8.3】

[复制链接]
  • TA的每日心情
    开心
    2021-5-25 00:00
  • 签到天数: 1917 天

    [LV.Master]出神入化

    2025

    主题

    3683

    帖子

    6万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    66345

    宣传达人突出贡献优秀版主荣誉管理论坛元老

    发表于 2017-3-5 00:36:55 | 显示全部楼层 |阅读模式
    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
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|Java自学网

    GMT+8, 2024-11-23 16:24 , Processed in 0.148018 second(s), 30 queries .

    Powered by Javazx

    Copyright © 2012-2022, Javazx Cloud.

    快速回复 返回顶部 返回列表