java自学网VIP

Java自学网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2355|回复: 0

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

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

    [LV.Master]出神入化

    2025

    主题

    3683

    帖子

    6万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    66101

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

    发表于 2017-3-5 00:36:55 | 显示全部楼层 |阅读模式
    8.3 系统架构; Z- x1 j% u% z. c& P' K! `
    8.3.1 整体架构图1 c* V: C( ~+ }+ Y
    OceanBase的整体架构如图8-1所示。$ u% v0 J" V* C! Q
    图 8-1 OceanBase整体架构图$ K( k! ~" \' W
    OceanBase由如下几个部分组成:8 r% ~9 c9 S8 h! R& T" A
    ●客户端:用户使用OceanBase的方式和MySQL数据库完全相同,支持JDBC、 C
    . g+ ~, F' N- a; f/ c; O客户端访问,等等。基于MySQL数据库开发的应用程序、工具能够直接迁移到3 l5 {* T) l6 T  H$ Q+ m% U: `6 N
    OceanBase。
    + }* |$ A# o0 B: M! t●RootServer:管理集群中的所有服务器,子表(tablet)数据分布以及副本管1 K3 g" j( X8 b" a2 i5 T/ P
    理。 RootServer一般为一主一备,主备之间数据强同步。, ]' K; x* q- N6 [7 x6 G  @0 s
    ●UpdateServer:存储OceanBase系统的增量更新数据。UpdateServer一般为一主
    - I: W; l0 R: ]/ h' ^; h4 w一备,主备之间可以配置不同的同步模式。部署时,UpdateServer进程和RootServer- h, p5 e9 |' k$ ?& S4 p) r
    进程往往共用物理服务器。
    ! m9 I0 }) Y& g( D0 l9 a# h5 a●ChunkServer:存储OceanBase系统的基线数据。基线数据一般存储两份或者三
    ( N- W* o; c& r+ a份,可配置。) }* d, o/ q; J( D
    ●MergeServer:接收并解析用户的SQL请求,经过词法分析、语法分析、查询优
      m$ y/ Q: N/ k/ A& m化等一系列操作后转发给相应的ChunkServer或者UpdateServer。如果请求的数据分布7 Z+ g  J: S, \7 q: h7 t% p
    在多台ChunkServer上,MergeServer还需要对多台ChunkServer返回的结果进行合并。
    + [8 K+ @, M3 W* B& p- K客户端和MergeServer之间采用原生的MySQL通信协议,MySQL客户端可以直接访问% {) d! r& K: ~! B) \9 R
    MergeServer。
    & A% z0 G) t. DOceanBase支持部署多个机房,每个机房部署一个包含RootServer、
    $ e; W/ O* ]* n1 f) t4 O% W$ y' qMergeServer、ChunkServer以及UpdateServer的完整OceanBase集群,每个集群由各自& f/ b$ \" }9 `' R" o8 R* |5 Q
    的RootServer负责数据划分、负载均衡、集群服务器管理等操作,集群之间数据同步* Q( |5 c5 Y' @, B. t
    通过主集群的主UpdateServer往备集群同步增量更新操作日志实现。客户端配置了多
    2 z: i* |* [4 K3 J: Z# j1 ~个集群的RootServer地址列表,使用者可以设置每个集群的流量分配比例,客户端根6 \# f" p/ M# }
    据这个比例将读写操作发往不同的集群。图8-2是双机房部署示意图。
    % S, W- _' e9 c# q$ j% x2 @图 8-2 OceanBase双机房部署
    & }, J- |, u6 l6 Z6 [* @8.3.2 客户端4 \& [; M6 c9 n* W0 g' I6 \- B
    OceanBase客户端与MergeServer通信,目前主要支持如下几种客户端:
    8 P! R  C  c- C: B" r; U●MySQL客户端:MergeServer兼容MySQL协议,MySQL客户端及相关工具(如& o; G& X6 Z) I) s' w
    Java数据库访问方式JDBC)只需要将服务器的地址设置为任意一台Merge-Server的地
    ! \  X, X5 H& q9 ]' a址,就可以直接使用。
      m$ g  r6 m( j: s1 u●Java客户端:OceanBase内部部署了多台MergeServer,Java客户端提供对 MySQL
    5 s/ W( Z) H# o1 I; P  @* f标准JDBC Driver的封装,并提供流量分配、负载均衡、MergeServer异常处理等功- W5 _8 _0 a: F+ ^; E  j" H
    能。简单来讲,Java客户端首先按照一定的策略定位到某台MergeServer,接着调用
    " b8 [$ m. Y( k. P+ W1 a5 m/ G7 u, vMySQL JDBC Driver往这台MergeServer发送读写请求。Java客户端实现符合JDBC标" ]9 V7 Q! B6 ?* R: N# t+ P
    准,能够支持Spring、iBatis等Java编程框架。+ |0 p1 M& G3 |/ s0 E1 Q
    ●C客户端:OceanBase C客户端的功能和Java客户端类似。它首先按照一定的策
    % n- q/ I0 d( e- D% u略定位到某台MergeServer,接着调用MySQL标准C客户端往这台MergeServer发送读
    * k* O, G8 t$ |5 _7 e写请求。C客户端的接口和MySQL标准C客户端接口完全相同,因此,能够通过
    . j! U3 r2 W/ GLD_PRELOAD的方式将应用程序依赖的MySQL标准C客户端替换为OceanBase C客户
    , P, N$ Y; Z- y) d% g  d6 R端,而无需修改应用程序的代码。
    ( [3 t: j3 D- C3 j- D# E8 T& k8 b" MOceanBase集群有多台MergeServer,这些MergeServer的服务器地址存储在0 x# \( S9 i9 }# B
    OceanBase服务器端的系统表(与Oracle的系统表类似,存储OceanBase系统的元数: F$ C5 p  H: s8 K. P; Y4 `$ u
    据)内。OceanBase Java/C客户端首先请求服务器端获取MergeServer地址列表,接着
    8 f# d' M+ e1 m, x/ h按照一定的策略将读写请求发送给某台MergeServer,并负责对出现故障的
    " V, |) n, Z2 T- X1 ?+ bMergeServer进行容错处理。/ R% |! i$ p7 A4 j/ D# M
    Java/C客户端访问OceanBase的流程大致如下:: m( N+ \$ v% o7 w
    1)请求RootServer获取集群中MergeServer的地址列表。
    $ H- @6 M3 R# N9 D8 ~1 r3 Z5 K: H3 E2)按照一定的策略选择某台MergeServer发送读写请求。客户端与MergeServer: j; b' j' O; [1 z' M( X6 A4 S- ]
    之间的通信协议兼容原生的MySQL协议,因此,只需要调用MySQL JDBC Driver或者
    1 K2 s! L, ~  M1 MMySQL C客户端这样的标准库即可。客户端支持的策略主要有两种:随机以及一致
    2 `2 j$ `2 k4 ^2 m+ f- U0 s性哈希。一致性哈希的主要目的是将相同的SQL请求发送到同一台MergeServer,方! M' g& d) ~" T5 ]  C
    便MergeServer对查询结果进行缓存。+ A; Q3 `% E) e) V; W8 y4 t
    3)如果请求MergeServer失败,则从MergeServer列表中重新选择一台) c9 Y# }4 Z8 \$ \( f, `
    MergeServer重试;如果请求某台MergeServer失败超过一定的次数,将这台
    3 g- }( m$ M  v- y9 \MergeServer加入黑名单并从MergeServer列表中删除。另外,客户端会定期请求
    9 H( r4 K  A* S! O1 v& eRootServer更新MergeServer地址列表。4 `) Z1 Y# u; L. }3 R9 N
    如果OceanBase部署多个集群,客户端还需要处理多个集群的流量分配问题。使  B7 C0 [2 h" F  {& |
    用者可以设置多个集群之间的流量分配比例,客户端获取到流量分配比例后,按照7 H4 M$ p% h% y' h
    这个比例将请求发送到不同的集群。# m4 h! x7 }! l- v( z: S
    OceanBase程序升级版本时,往往先将备集群的读取流量调整为0,这时所有的
    , m- K9 D  w) n4 N- y' [- T2 N读写请求都只发往主集群,接着升级备集群的程序版本。备集群升级完成后将流量7 d( I/ d" t. H. }4 V) H
    逐步切换到备集群观察一段时间,如果没有出现异常,则将所有的流量切到备集: ^0 v* W0 |% S4 k& [+ }
    群,并将备集群切换为主集群提供写服务。原来的主集群变为新的备集群,升级新
    ( F7 y& @' A  g+ ?2 V- Y的备集群的程序版本后重新分配主备集群的流量比例。5 |, c) t, u; ]5 T
    8.3.3 RootServer
    ; y) n. q* ]3 d  m+ jRootServer的功能主要包括:集群管理、数据分布以及副本管理。) R: U+ ?/ G& a9 `
    RootServer管理集群中的所有MergeServer、ChunkServer以及UpdateServer。每个
    0 @; G) X6 B" C. R  u' [集群内部同一时刻只允许一个UpdateServer提供写服务,这个UpdateServer成为主9 n% ?4 [7 W, A+ c3 h. F
    UpdateServer。这种方式通过牺牲一定的可用性获取了强一致性。RootServer通过租
    2 v5 R1 @  u" x$ I/ ^约(Lease)机制选择唯一的主UpdateServer,当原先的主UpdateServer发生故障后,
    , g9 N) `% `- N6 N8 o3 f/ N" QRootServer能够在原先的租约失效后选择一台新的UpdateServer作为主UpdateServer。
    - Y; j: \" y& `: }: S' D  V另外,RootServer与MergeServer&ChunkServer之间保持心跳(heartbeat),从而能够
    5 D0 x& G1 {! i  D) q感知到在线和已经下线的MergeServer&ChunkServer机器列表。8 I- T7 ?2 S: ~% ~" m( X
    OceanBase内部使用主键对表格中的数据进行排序和存储,主键由若干列组成并0 U' N! J2 }# z# a" C% u
    且具有唯一性。在OceanBase内部,基线数据按照主键排序并且划分为数据量大致相  R' F6 W4 d0 i" s2 `
    等的数据范围,称为子表(tablet)。每个子表的默认大小是256MB(可配置)。
    4 R' q& l, }6 `1 h9 }8 Q% t4 wOceanBase的数据分布方式与Bigtable一样采用顺序分布,不同的是,OceanBase没有
    & j; _' p! g, p采用根表(RootTable)+元数据表(MetaTable)两级索引结构,而是采用根表一级
      P" O2 V! Q! ^! x4 p索引结构。/ @/ I# y) H3 O
    如图8-3所示,主键值在[1,100]之间的表格被划分为四个子表:1~25,26~
    ; q( N7 E# C8 Y50,51~80以及81~100。RootServer中的根表记录了每个子表所在的ChunkServer位/ J- K4 S0 v' L4 Y; H9 ?8 L, R3 k
    置信息,每个子表包含多个副本(一般为三个副本,可配置),分布在多台
    + a8 k3 n) h. ~/ f0 L6 \* K% DChunkServer中。当其中某台ChunkServer发生故障时,RootServer能够检测到,并且触6 J( l' L4 T- C* d4 E
    发对这台ChunkServer上的子表增加副本的操作;另外,RootServer也会定期执行负载
    0 \# j; A% m3 v$ z) r6 b均衡,选择某些子表从负载较高的机器迁移到负载较低的机器上。+ X7 M% H0 `1 q# x) W
    图 8-3 基线数据子表划分
    ; C- {9 {- c$ nRootServer采用一主一备的结构,主备之间数据强同步,并通过Linux
    ) l( V1 M/ U/ \; `! [# I: KHA(http://www.linux-ha.org)软件实现高可用性。主备RootServer之间共享VIP,当
    5 G6 W* d& C) I6 G9 ~, i0 u主RootServer发生故障后,VIP能够自动漂移到备RootServer所在的机器,备
    7 ]3 H0 t8 ?& WRootServer检测到以后切换为主RootServer提供服务。
    / K! m0 c: m: Y8.3.4 MergeServer
      \# c. \, g7 g$ tMergeServer的功能主要包括:协议解析、SQL解析、请求转发、结果合并、多4 t& N9 v& B/ N; W3 H* `7 z( K( O
    表操作等。
    3 h  D3 x0 ?0 G& l; ^) [9 vOceanBase客户端与MergeServer之间的协议为MySQL协议。MergeServer首先解# ^$ O4 O8 K$ X% A) D# V
    析MySQL协议,从中提取出用户发送的SQL语句,接着进行词法分析和语法分析,4 Q6 G: r5 [2 w! |; p$ O. J+ ~
    生成SQL语句的逻辑查询计划和物理查询计划,最后根据物理查询计划调用
    1 J' X1 K$ p: P/ z) t: `OceanBase内部的各种操作符。, w  X: N% i" ~' k7 l+ Y  i
    MergeServer缓存了子表分布信息,根据请求涉及的子表将请求转发给该子表所6 h( k& x( d/ Z3 T+ i2 {  J/ G
    在的ChunkServer。如果是写操作,还会转发给UpdateServer。某些请求需要跨多个子
    6 O, I& }. N3 Q  U. [表,此时MergeServer会将请求拆分后发送给多台ChunkServer,并合并这些
    ; J9 p+ c, {0 T+ u: {+ T+ UChunkServer返回的结果。如果请求涉及多个表格,MergeServer需要首先从$ k0 w! r& |; q' {' D1 a4 h- t
    ChunkServer获取每个表格的数据,接着再执行多表关联或者嵌套查询等操作。; s4 v* N. l, I1 ?) e! s6 m  T
    MergeServer支持并发请求多台ChunkServer,即将多个请求发给多台
    6 z. z# B4 C$ J' ]% mChunkServer,再一次性等待所有请求的应答。另外,在SQL执行过程中,如果某个; V* |' W* x1 r" l3 _
    子表所在的ChunkServer出现故障,MergeServer会将请求转发给该子表的其他副本所6 e0 R7 T* ?, F' D7 K
    在的ChunkServer。这样,ChunkServer故障是不会影响用户查询的。/ |1 V) q6 J8 V8 I8 ]  n3 D& H
    MergeServer本身是没有状态的,因此,MergeServer宕机不会对使用者产生影4 y1 T* m3 O$ V/ L' @6 @
    响,客户端会自动将发生故障的MergeServer屏蔽掉。4 |7 O9 F" [; n
    8.3.5 ChunkServer. f/ V& k+ U1 u7 j9 J+ p
    ChunkServer的功能包括:存储多个子表,提供读取服务,执行定期合并以及数
    & l0 g" e$ I* @6 H4 `2 Y据分发。
    - q7 g/ H, x. N8 T) hOceanBase将大表划分为大小约为256MB的子表,每个子表由一个或者多个0 k! M9 N7 S8 [7 H" Y1 q
    SSTable组成(一般为一个),每个SSTable由多个块(Block,大小为4KB~64KB之" I* {6 _$ X. r* H
    间,可配置)组成,数据在SSTable中按照主键有序存储。查找某一行数据时,需要  r; c' O8 G, Z
    首先定位这一行所属的子表,接着在相应的SSTable中执行二分查找。SSTable支持两4 h, K, i4 M; S0 y2 V
    种缓存模式,块缓存(Block Cache)以及行缓存(Row Cache)。块缓存以块为单位. J. P9 a- }" A4 P8 r; k4 R- d
    缓存最近读取的数据,行缓存以行为单位缓存最近读取的数据。( v( t1 ^" k: J  @9 b' \% W6 B7 t
    MergeServer将每个子表的读取请求发送到子表所在的ChunkServer,ChunkServer首  b! a0 E% ]1 L1 U! N
    先读取SSTable中包含的基线数据,接着请求UpdateServer获取相应的增量更新数据,/ f! W/ o: z# M3 f6 J
    并将基线数据与增量更新融合后得到最终结果。. l& _) o! ~! C( g! z7 J: G4 h
    由于每次读取都需要从UpdateServer中获取最新的增量更新,为了保证读取性
    . R+ s0 Q3 b# Y* i0 ?能,需要限制UpdateServer中增量更新的数据量,最好能够全部存放在内存中。: ?7 z% p& h2 E0 L  x5 L
    OceanBase内部会定期触发合并或者数据分发操作,在这个过程中,ChunkServer将从, G8 W* u+ j* q. |$ n6 Z
    UpdateServer获取一段时间之前的更新操作。通常情况下,OceanBase集群会在每天
    4 w8 t* }. {: @8 n7 q4 ?的服务低峰期(凌晨1:00开始,可配置)执行一次合并操作。这个合并操作往往也称$ I, Z; U: c0 S! [# i
    为每日合并。
    6 H2 \% e, a* f9 U( }# Y- P8.3.6 UpdateServer
    ' O3 a, s4 u. MUpdateServer是集群中唯一能够接受写入的模块,每个集群中只有一个主Update-! ]  m! d, U# C
    Server。UpdateServer中的更新操作首先写入到内存表,当内存表的数据量超过一定
    " k# d) H' e( D2 R值时,可以生成快照文件并转储到SSD中。快照文件的组织方式与ChunkServer中的
    ) v9 w2 Y: m8 g9 B% ySSTable类似,因此,这些快照文件也称为SSTable。另外,由于数据行的某些列被更4 w% F/ R. _8 `9 r) B0 x  y2 Q
    新,某些列没被更新,SSTable中存储的数据行是稀疏的,称为稀疏型SSTable。
    6 [" E7 H0 G% c( D5 f3 y# u为了保证可靠性,主UpdateServer更新内存表之前需要首先写操作日志,并同步2 K. d* L" d' n# Z0 t
    到备UpdateServer。当主UpdateServer发生故障时,RootServer上维护的租约将失效,% b+ r; Y  N2 i, g8 u  j( C
    此时,RootServer将从备UpdateServer列表中选择一台最新的备UpdateServer切换为主+ v" F: C( F# A' Z$ ^, [
    UpdateServer继续提供写服务。UpdateServer宕机重启后需要首先加载转储的快照文* O9 t  w, ~! j" N* r: c3 P7 |
    件(SSTable文件),接着回放快照点之后的操作日志。! \3 j% T9 Y! }9 n2 ~1 ~* v
    由于集群中只有一台主UpdateServer提供写服务,因此,OceanBase很容易地实
    : y( a3 |+ y/ E( b9 j$ p4 R现了跨行跨表事务,而不需要采用传统的两阶段提交协议。当然,这样也带来了一+ C8 y1 P/ n% |1 m0 y
    系列的问题。由于整个集群所有的读写操作都必须经过UpdateServer,UpdateServer的
    ) }# A# W" X& Y5 \7 k性能至关重要。OceanBase集群通过定期合并和数据分发这两种机制将UpdateServer1 [$ I2 f9 j3 j7 q: W" v( h
    一段时间之前的增量更新源源不断地分散到ChunkServer,而UpdateServer只需要服务
    5 C2 d% q+ A7 G. U最新一小段时间新增的数据,这些数据往往可以全部存放在内存中。另外,系统实1 J1 e4 U( E: P
    现时也需要对UpdateServer的内存操作、网络框架、磁盘操作做大量的优化。4 B& l# `* i; N0 z- q$ h7 j- E
    8.3.7 定期合并&数据分发
    ) Y! w' j& F7 ?+ `0 w" t定期合并和数据分发都是将UpdateServer中的增量更新分发到ChunkServer中的手
    " v/ z- l3 p( r9 w# F5 ]段,二者的整体流程比较类似:
    + j  ?! O9 e: j3 @9 `1)UpdateServer冻结当前的活跃内存表(Active MemTable),生成冻结内存
    ) ^5 t4 ~+ z6 D+ @9 g9 i# e& d表,并开启新的活跃内存表,后续的更新操作都写入新的活跃内存表。- o) k' v$ _$ |+ J7 U
    2)UpdateServer通知RootServer数据版本发生了变化,之后RootServer通过心跳  Z  d  d) L0 ]5 ^6 I( m$ G6 U( r
    消息通知ChunkServer。
    4 t: }* O! @9 P4 a' C0 d3)每台ChunkServer启动定期合并或者数据分发操作,从UpdateServer获取每个
    2 M8 C  }) Z  E7 p3 L, y  _子表对应的增量更新数据。
    + G7 H9 a  H3 j- P. e; i定期合并与数据分发两者之间的不同点在于,数据分发过程中ChunkServer只是
    7 i4 \, t3 A  k+ e3 a! z& A将UpdateServer中冻结内存表中的增量更新数据缓存到本地,而定期合并过程中
    3 V" f1 t; B. Y* h- k* KChunkServer需要将本地SSTable中的基线数据与冻结内存表的增量更新数据执行一次# m# e8 @( x+ Y: ]
    多路归并,融合后生成新的基线数据并存放到新的SSTable中。定期合并对系统服务! X: L* X& @: b/ ]& I
    能力影响很大,往往安排在每天服务低峰期执行(例如凌晨1点开始),而数据分发% s; E3 M: v$ C% f) u. [
    可以不受限制。! z- _* `' l; q$ f+ {7 u3 @
    如图8-4,活跃内存表冻结后生成冻结内存表,后续的写操作进入新的活跃内存
    7 e* k. }* }% _+ }# w8 D* t表。定期合并过程中ChunkServer需要读取UpdateServer中冻结内存表的数据、融合后9 j0 s6 L: r9 ]& b' K/ n) k- c
    生成新的子表,即:
    6 x8 |& }/ u( j9 V1 G- v, i  S1 z新子表=旧子表+冻结内存表# K2 {1 W/ d0 X
    图 8-4 定期合并不停读服务9 z" d' L4 d/ v/ S! y3 y4 S
    虽然定期合并过程中各个ChunkServer的各个子表合并时间和完成时间可能都不
    ; L5 C2 H- N# ^5 S, Z# B9 f8 ?相同,但并不影响读取服务。如果子表没有合并完成,那么使用旧子表,并且读取: M, i0 y1 n' ~  d2 X
    UpdateServer中的冻结内存表以及新的活跃内存表;否则,使用新子表,只读取新的5 V7 R( h* ]6 `. R. u
    活跃内存表,即:3 \% X7 C- _# G6 a3 ^0 Q  E
    查询结果=旧子表+冻结内存表+新的活跃内存表6 g- T& q3 T. j1 b
    =新子表+新的活跃内存表6 [; ]6 f) i6 P, M2 V7 I  k% ]$ V

    0 I0 T  r0 s/ K: j: Z! l7 L  t- @5 x' M6 ~
    回复

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-4-29 14:47 , Processed in 0.091758 second(s), 31 queries .

    Powered by Javazx

    Copyright © 2012-2022, Javazx Cloud.

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