java自学网VIP

Java自学网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2551|回复: 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 系统架构& m1 ]( i- C+ f! V
    8.3.1 整体架构图  {% o  Z9 v1 S  k# Z
    OceanBase的整体架构如图8-1所示。2 s% p% z6 M; l- g8 [
    图 8-1 OceanBase整体架构图8 C0 u% {1 ^2 h+ ^
    OceanBase由如下几个部分组成:
    . A  v. O2 a$ {6 {$ A●客户端:用户使用OceanBase的方式和MySQL数据库完全相同,支持JDBC、 C9 L/ M4 L/ z. y% A. C
    客户端访问,等等。基于MySQL数据库开发的应用程序、工具能够直接迁移到8 X& E5 |& d6 s. H% R/ v, I
    OceanBase。
    4 l- {1 C3 I9 G6 r●RootServer:管理集群中的所有服务器,子表(tablet)数据分布以及副本管
    ! F& W0 O  ~! f8 Z( f: N- K4 C理。 RootServer一般为一主一备,主备之间数据强同步。
      |6 A9 ?- s$ _$ \8 o●UpdateServer:存储OceanBase系统的增量更新数据。UpdateServer一般为一主
    * u" H$ Z, R6 M6 n一备,主备之间可以配置不同的同步模式。部署时,UpdateServer进程和RootServer  o6 ^4 j" Z+ m
    进程往往共用物理服务器。+ H+ ]" l1 J; F3 |) R
    ●ChunkServer:存储OceanBase系统的基线数据。基线数据一般存储两份或者三& n3 D2 K) L+ c# D/ j- N; [
    份,可配置。
    $ g% f: a5 a& W9 a●MergeServer:接收并解析用户的SQL请求,经过词法分析、语法分析、查询优, i' n3 k  j* U4 g1 w+ x+ ^1 `
    化等一系列操作后转发给相应的ChunkServer或者UpdateServer。如果请求的数据分布
    * I" j/ k" _8 _/ |3 T0 l0 J4 x7 \在多台ChunkServer上,MergeServer还需要对多台ChunkServer返回的结果进行合并。' k* e* w; t8 A# \) Z9 C
    客户端和MergeServer之间采用原生的MySQL通信协议,MySQL客户端可以直接访问
    4 D6 h% V! l; C. A6 }  C) rMergeServer。
    4 E* Q% N8 W9 \OceanBase支持部署多个机房,每个机房部署一个包含RootServer、9 H! S; S/ f. G. X! G
    MergeServer、ChunkServer以及UpdateServer的完整OceanBase集群,每个集群由各自! v% O' r" O/ t
    的RootServer负责数据划分、负载均衡、集群服务器管理等操作,集群之间数据同步9 Z$ P1 `% n5 D" n
    通过主集群的主UpdateServer往备集群同步增量更新操作日志实现。客户端配置了多% y$ x3 j. u6 j" |1 L8 v4 U
    个集群的RootServer地址列表,使用者可以设置每个集群的流量分配比例,客户端根
    0 o( b7 Y% N$ W7 |; W据这个比例将读写操作发往不同的集群。图8-2是双机房部署示意图。
    4 o1 c8 L+ K+ N$ e& B图 8-2 OceanBase双机房部署
    ' ], R& N" C6 n' h! M( i8.3.2 客户端
    0 W. e" J1 n7 ~OceanBase客户端与MergeServer通信,目前主要支持如下几种客户端:
    5 W1 X4 z, ~/ p. k' A6 l1 f+ d●MySQL客户端:MergeServer兼容MySQL协议,MySQL客户端及相关工具(如
    6 W+ U5 e" ^. U7 o% f3 uJava数据库访问方式JDBC)只需要将服务器的地址设置为任意一台Merge-Server的地
    1 `4 B2 f7 E) B+ ?( [/ F; ?址,就可以直接使用。- O0 l2 ~! ~" ~/ ~
    ●Java客户端:OceanBase内部部署了多台MergeServer,Java客户端提供对 MySQL
    : J5 O# D( B6 A3 y2 ]( I) s8 b6 J标准JDBC Driver的封装,并提供流量分配、负载均衡、MergeServer异常处理等功& x9 J% E$ k+ H  w, P% Y
    能。简单来讲,Java客户端首先按照一定的策略定位到某台MergeServer,接着调用
    3 P: J4 b. `- q/ b: vMySQL JDBC Driver往这台MergeServer发送读写请求。Java客户端实现符合JDBC标
    $ J# D: A/ J. P准,能够支持Spring、iBatis等Java编程框架。
    ) ~9 R6 Y7 ~8 a2 c" U! P; y●C客户端:OceanBase C客户端的功能和Java客户端类似。它首先按照一定的策2 j9 O  g1 E: z- N# {9 O
    略定位到某台MergeServer,接着调用MySQL标准C客户端往这台MergeServer发送读0 w4 A: Q3 F. C7 }+ t( B/ O
    写请求。C客户端的接口和MySQL标准C客户端接口完全相同,因此,能够通过9 D7 i/ y3 P  a! U" z' M
    LD_PRELOAD的方式将应用程序依赖的MySQL标准C客户端替换为OceanBase C客户
    8 u5 h4 b* {- m) V$ s9 C3 R端,而无需修改应用程序的代码。
    ( Z/ ]/ |" [! vOceanBase集群有多台MergeServer,这些MergeServer的服务器地址存储在
    # X& m( R& @' u: {: V% s+ s9 B+ A7 uOceanBase服务器端的系统表(与Oracle的系统表类似,存储OceanBase系统的元数
    0 J' x8 W' h# T+ c: r2 X/ X  [据)内。OceanBase Java/C客户端首先请求服务器端获取MergeServer地址列表,接着( y* W! M6 o! p* j2 [( w# d
    按照一定的策略将读写请求发送给某台MergeServer,并负责对出现故障的2 L- o; D' e9 c5 D  Z6 P
    MergeServer进行容错处理。+ j( K& F% v  f5 `( m, H
    Java/C客户端访问OceanBase的流程大致如下:
    : K8 A2 k  \' N1)请求RootServer获取集群中MergeServer的地址列表。* D& P: {5 T0 t5 B* s3 ~! `! ]6 H2 r
    2)按照一定的策略选择某台MergeServer发送读写请求。客户端与MergeServer$ A0 R1 B" E  d7 [
    之间的通信协议兼容原生的MySQL协议,因此,只需要调用MySQL JDBC Driver或者
    , I8 B) Q. z! c  r0 tMySQL C客户端这样的标准库即可。客户端支持的策略主要有两种:随机以及一致* v- c4 p! v, K
    性哈希。一致性哈希的主要目的是将相同的SQL请求发送到同一台MergeServer,方
    6 p/ M0 X8 s# D+ Z9 T0 p便MergeServer对查询结果进行缓存。6 y. B& X) U9 d; l
    3)如果请求MergeServer失败,则从MergeServer列表中重新选择一台
    $ @  V/ J, f/ E; D) {MergeServer重试;如果请求某台MergeServer失败超过一定的次数,将这台
    ' W2 v* Z" Y! X2 `MergeServer加入黑名单并从MergeServer列表中删除。另外,客户端会定期请求
    6 o* }- s" i9 W! ORootServer更新MergeServer地址列表。
    ) F& b1 b6 e* l5 M如果OceanBase部署多个集群,客户端还需要处理多个集群的流量分配问题。使& l$ D4 a! I% w1 E
    用者可以设置多个集群之间的流量分配比例,客户端获取到流量分配比例后,按照! [* {7 [0 t. G# J9 T, H
    这个比例将请求发送到不同的集群。! _0 [* w- |0 D
    OceanBase程序升级版本时,往往先将备集群的读取流量调整为0,这时所有的- O% E) c( d0 W" N% J7 G1 T
    读写请求都只发往主集群,接着升级备集群的程序版本。备集群升级完成后将流量
    6 y# p: B* N4 T% K0 C逐步切换到备集群观察一段时间,如果没有出现异常,则将所有的流量切到备集
    ; @) d- y( q4 `: s9 }1 y群,并将备集群切换为主集群提供写服务。原来的主集群变为新的备集群,升级新  U$ Z; y+ Z9 S/ l5 L; m7 [
    的备集群的程序版本后重新分配主备集群的流量比例。7 j$ G6 [$ D0 i& p4 T6 a- R
    8.3.3 RootServer) Q6 U+ \8 {+ c* ^: r
    RootServer的功能主要包括:集群管理、数据分布以及副本管理。
    ) m& w9 F1 L" |0 t; K( s: gRootServer管理集群中的所有MergeServer、ChunkServer以及UpdateServer。每个
    ' T$ O  B' r9 S& T集群内部同一时刻只允许一个UpdateServer提供写服务,这个UpdateServer成为主) H" \5 ]4 m# ~4 Z1 n. Q
    UpdateServer。这种方式通过牺牲一定的可用性获取了强一致性。RootServer通过租7 a) S/ `) }( B
    约(Lease)机制选择唯一的主UpdateServer,当原先的主UpdateServer发生故障后,
    9 W) P, `3 D; @- A  Q- aRootServer能够在原先的租约失效后选择一台新的UpdateServer作为主UpdateServer。
    8 P  D5 }; L3 |  G. ^$ |; M4 [; T另外,RootServer与MergeServer&ChunkServer之间保持心跳(heartbeat),从而能够0 \# R( `- D7 r( F
    感知到在线和已经下线的MergeServer&ChunkServer机器列表。0 P0 o2 E/ c) @5 |+ A" A5 D
    OceanBase内部使用主键对表格中的数据进行排序和存储,主键由若干列组成并0 R, O1 H; j# S+ Y! s# h* p
    且具有唯一性。在OceanBase内部,基线数据按照主键排序并且划分为数据量大致相
    . u1 h" ^' s, u$ m7 }* E6 E等的数据范围,称为子表(tablet)。每个子表的默认大小是256MB(可配置)。: j5 R  H* @+ x, b  f
    OceanBase的数据分布方式与Bigtable一样采用顺序分布,不同的是,OceanBase没有
    $ M- u5 ^6 W+ @9 Q' e采用根表(RootTable)+元数据表(MetaTable)两级索引结构,而是采用根表一级
    & q4 O& e9 i" p$ S( {% M索引结构。, e: O3 \3 V# Q& O9 x7 Y5 a9 ?3 Q
    如图8-3所示,主键值在[1,100]之间的表格被划分为四个子表:1~25,26~. k4 {$ m' T+ K! c1 z2 k1 _* G# D' U% V
    50,51~80以及81~100。RootServer中的根表记录了每个子表所在的ChunkServer位: ^. f+ o% S& H5 u! q" ]
    置信息,每个子表包含多个副本(一般为三个副本,可配置),分布在多台& k- d+ V% c8 ]: T% e" R
    ChunkServer中。当其中某台ChunkServer发生故障时,RootServer能够检测到,并且触
    # Z9 a& d( x' p, _% P2 A发对这台ChunkServer上的子表增加副本的操作;另外,RootServer也会定期执行负载
    6 s. Q1 n5 J0 g) M/ B& t. d均衡,选择某些子表从负载较高的机器迁移到负载较低的机器上。
    + b/ v% \1 J5 ~1 @图 8-3 基线数据子表划分
    1 Y0 E) z8 O/ k% m3 zRootServer采用一主一备的结构,主备之间数据强同步,并通过Linux& y  B8 A# H$ K/ d6 `$ V1 s" ?
    HA(http://www.linux-ha.org)软件实现高可用性。主备RootServer之间共享VIP,当( \  v8 _( P  ?2 ~
    主RootServer发生故障后,VIP能够自动漂移到备RootServer所在的机器,备: _- y) r' x: N
    RootServer检测到以后切换为主RootServer提供服务。  K$ K; u. T+ |1 x8 B3 r9 b" ~
    8.3.4 MergeServer. Q( x% ~  [9 O+ K. u
    MergeServer的功能主要包括:协议解析、SQL解析、请求转发、结果合并、多( N3 K4 N" f$ \* ~
    表操作等。; G' t6 X1 k2 p3 P7 r* B: }
    OceanBase客户端与MergeServer之间的协议为MySQL协议。MergeServer首先解
    ) y  O& Z$ Z* x; T1 Q: d$ Q析MySQL协议,从中提取出用户发送的SQL语句,接着进行词法分析和语法分析,
    3 s# Z: i! d/ Y& N. k  w生成SQL语句的逻辑查询计划和物理查询计划,最后根据物理查询计划调用
    + |2 k: q3 g; F. c( K# z: S$ O5 |OceanBase内部的各种操作符。* i& v5 I. f; n7 r: X
    MergeServer缓存了子表分布信息,根据请求涉及的子表将请求转发给该子表所
    & @1 [& M! u/ T" T+ m' m- a, u在的ChunkServer。如果是写操作,还会转发给UpdateServer。某些请求需要跨多个子1 s7 j- E4 y8 [; K
    表,此时MergeServer会将请求拆分后发送给多台ChunkServer,并合并这些2 ~* }% z9 }4 b% x
    ChunkServer返回的结果。如果请求涉及多个表格,MergeServer需要首先从: d3 r5 Z3 [. x+ n. H0 g
    ChunkServer获取每个表格的数据,接着再执行多表关联或者嵌套查询等操作。
    " \$ g5 t4 d& C' K4 f% N( TMergeServer支持并发请求多台ChunkServer,即将多个请求发给多台
    0 p% w5 J, J3 MChunkServer,再一次性等待所有请求的应答。另外,在SQL执行过程中,如果某个- j8 y5 g. @) A8 T, H
    子表所在的ChunkServer出现故障,MergeServer会将请求转发给该子表的其他副本所1 @) ~' n7 d- V
    在的ChunkServer。这样,ChunkServer故障是不会影响用户查询的。
    # b; r/ [9 y6 A/ }  S" S3 bMergeServer本身是没有状态的,因此,MergeServer宕机不会对使用者产生影+ Y) q) j8 `- ~
    响,客户端会自动将发生故障的MergeServer屏蔽掉。" M% }. v- z) c1 |) {/ Y
    8.3.5 ChunkServer/ {& w, f4 E6 A, p% W# D
    ChunkServer的功能包括:存储多个子表,提供读取服务,执行定期合并以及数3 _* p! m' W# X$ M; H
    据分发。
    ; G4 E. K/ V; F5 h0 e4 l- ]OceanBase将大表划分为大小约为256MB的子表,每个子表由一个或者多个: S( t" ]! i- D% G
    SSTable组成(一般为一个),每个SSTable由多个块(Block,大小为4KB~64KB之
    9 z# n+ ^( H, d, M4 c8 E2 h间,可配置)组成,数据在SSTable中按照主键有序存储。查找某一行数据时,需要
    - I8 B0 c* U5 S' Q首先定位这一行所属的子表,接着在相应的SSTable中执行二分查找。SSTable支持两( ]& {/ Q; @* @  V, Y
    种缓存模式,块缓存(Block Cache)以及行缓存(Row Cache)。块缓存以块为单位
    7 H) n) X+ A5 Z2 ?缓存最近读取的数据,行缓存以行为单位缓存最近读取的数据。9 l6 S2 q1 q9 {) Q) R  m; c" q! M
    MergeServer将每个子表的读取请求发送到子表所在的ChunkServer,ChunkServer首
    6 Q* e# y. q+ i) B先读取SSTable中包含的基线数据,接着请求UpdateServer获取相应的增量更新数据,
    1 R% f- l9 @) V$ H3 x并将基线数据与增量更新融合后得到最终结果。' h( L  g9 b2 D( s9 _
    由于每次读取都需要从UpdateServer中获取最新的增量更新,为了保证读取性! Z$ c2 x6 l; W: \1 i
    能,需要限制UpdateServer中增量更新的数据量,最好能够全部存放在内存中。3 b$ L+ z+ ]8 c8 D/ F9 d. F8 E
    OceanBase内部会定期触发合并或者数据分发操作,在这个过程中,ChunkServer将从
    1 X1 X3 Y2 w1 C: jUpdateServer获取一段时间之前的更新操作。通常情况下,OceanBase集群会在每天6 @' ^7 X* S" ^5 v8 P9 o9 `( g$ n0 f2 k
    的服务低峰期(凌晨1:00开始,可配置)执行一次合并操作。这个合并操作往往也称
    ! @4 a6 I7 V; h  v为每日合并。
    9 C) ^4 v3 H& x& m% \8.3.6 UpdateServer' {8 y% Y+ F" O5 N! O, e4 Y; f
    UpdateServer是集群中唯一能够接受写入的模块,每个集群中只有一个主Update-9 B' T0 X- m* Q/ |# G' V
    Server。UpdateServer中的更新操作首先写入到内存表,当内存表的数据量超过一定
    & k( W  V1 D% U值时,可以生成快照文件并转储到SSD中。快照文件的组织方式与ChunkServer中的/ l6 L6 u7 t& l, F# _7 f2 p
    SSTable类似,因此,这些快照文件也称为SSTable。另外,由于数据行的某些列被更
    9 w  |* |, }+ K( G, p$ p/ o新,某些列没被更新,SSTable中存储的数据行是稀疏的,称为稀疏型SSTable。: ]5 u& ^& M( }4 Q. S0 x3 R4 G
    为了保证可靠性,主UpdateServer更新内存表之前需要首先写操作日志,并同步
    1 ~; \% `" D3 F! h) m; u( h到备UpdateServer。当主UpdateServer发生故障时,RootServer上维护的租约将失效,
    2 \# z$ J8 R" f$ ?4 S$ h此时,RootServer将从备UpdateServer列表中选择一台最新的备UpdateServer切换为主6 S  j( s% B4 n4 \7 t7 S: u
    UpdateServer继续提供写服务。UpdateServer宕机重启后需要首先加载转储的快照文" {! L7 z5 [! ^( a4 J1 Y; E5 [
    件(SSTable文件),接着回放快照点之后的操作日志。% B; ?; b1 {4 Q; @( Y  @/ U
    由于集群中只有一台主UpdateServer提供写服务,因此,OceanBase很容易地实$ p1 m( @. ]: E. @, H  E' d
    现了跨行跨表事务,而不需要采用传统的两阶段提交协议。当然,这样也带来了一5 g3 {# D7 F+ j3 N% |+ J
    系列的问题。由于整个集群所有的读写操作都必须经过UpdateServer,UpdateServer的" E0 n4 m$ p# s% j2 n
    性能至关重要。OceanBase集群通过定期合并和数据分发这两种机制将UpdateServer
    * ?0 x* S# D, D( ]2 N一段时间之前的增量更新源源不断地分散到ChunkServer,而UpdateServer只需要服务
    + D3 t- i/ k; q- t. D最新一小段时间新增的数据,这些数据往往可以全部存放在内存中。另外,系统实
    1 D4 m9 R; P$ _2 ?现时也需要对UpdateServer的内存操作、网络框架、磁盘操作做大量的优化。
    # `, T" A6 R/ U2 U  K0 i3 G8.3.7 定期合并&数据分发2 c. N8 }6 B" ]- M; o/ ]1 z
    定期合并和数据分发都是将UpdateServer中的增量更新分发到ChunkServer中的手
    $ I, R& r% L0 c段,二者的整体流程比较类似:1 v  g; j9 G4 N5 _
    1)UpdateServer冻结当前的活跃内存表(Active MemTable),生成冻结内存
    : G) b7 G. A7 ]% \表,并开启新的活跃内存表,后续的更新操作都写入新的活跃内存表。1 {0 J# X5 u; q
    2)UpdateServer通知RootServer数据版本发生了变化,之后RootServer通过心跳: V" A& m% E3 s; x4 P+ z
    消息通知ChunkServer。
    . ]; [( Q! P1 n, D1 d3)每台ChunkServer启动定期合并或者数据分发操作,从UpdateServer获取每个# [0 l0 w: D+ f- R
    子表对应的增量更新数据。
      J2 y$ p5 ?! D. h定期合并与数据分发两者之间的不同点在于,数据分发过程中ChunkServer只是
    6 x$ w" R& C& q将UpdateServer中冻结内存表中的增量更新数据缓存到本地,而定期合并过程中+ D/ e1 K& L5 ?$ N0 b" o
    ChunkServer需要将本地SSTable中的基线数据与冻结内存表的增量更新数据执行一次
    " S2 O" H; Y% k& t  @  y, u2 D多路归并,融合后生成新的基线数据并存放到新的SSTable中。定期合并对系统服务' r) k; x6 `$ f7 j, r+ [% p! j
    能力影响很大,往往安排在每天服务低峰期执行(例如凌晨1点开始),而数据分发
      ]* B0 t8 R; f, k* e9 {可以不受限制。2 {2 C4 w1 s3 H! V4 S; f1 X: V/ o
    如图8-4,活跃内存表冻结后生成冻结内存表,后续的写操作进入新的活跃内存' H, s# k5 Z7 b. Y
    表。定期合并过程中ChunkServer需要读取UpdateServer中冻结内存表的数据、融合后
    2 L: f' w4 F2 {) v生成新的子表,即:3 x! M4 \2 Z; ?# [1 T7 B
    新子表=旧子表+冻结内存表
    ; ~! ^$ d; }0 ~0 |- h3 V图 8-4 定期合并不停读服务1 [% r# M. [% }( x" {
    虽然定期合并过程中各个ChunkServer的各个子表合并时间和完成时间可能都不" t7 p* q: Q& U
    相同,但并不影响读取服务。如果子表没有合并完成,那么使用旧子表,并且读取
    # L( J2 d9 s" n8 FUpdateServer中的冻结内存表以及新的活跃内存表;否则,使用新子表,只读取新的4 T0 h. O6 `8 \7 X/ ~
    活跃内存表,即:
    % Y' C1 @; y. n" h  E4 s$ r查询结果=旧子表+冻结内存表+新的活跃内存表
    7 h4 s5 K/ M. \1 r=新子表+新的活跃内存表
    0 m+ Y% k2 b( e, R" N; O, }
    " r( R3 n. j9 M$ A& U4 M. y
    0 L) K; j* p! `7 k6 b
    回复

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-11-21 21:23 , Processed in 0.125026 second(s), 30 queries .

    Powered by Javazx

    Copyright © 2012-2022, Javazx Cloud.

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