java自学网VIP

Java自学网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2607|回复: 0

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

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

    [LV.Master]出神入化

    2040

    主题

    3698

    帖子

    6万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    66476

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

    发表于 2017-3-5 00:36:55 | 显示全部楼层 |阅读模式
    8.3 系统架构
    1 O! S6 m' b1 _: f! J; j8.3.1 整体架构图
    , f8 I2 T& k6 d8 Z7 L4 f4 Q& Q* H: Z8 rOceanBase的整体架构如图8-1所示。
    & {" d  Z- T) a9 u* \4 U4 @图 8-1 OceanBase整体架构图3 `4 _% U4 \4 F. g
    OceanBase由如下几个部分组成:
    ; ~4 u8 d% b' ~. Y+ F●客户端:用户使用OceanBase的方式和MySQL数据库完全相同,支持JDBC、 C
    5 V1 a9 E& r# s& a客户端访问,等等。基于MySQL数据库开发的应用程序、工具能够直接迁移到2 K: ^' s5 U6 L
    OceanBase。( E* H7 F* L( }- v. N6 O% P$ T
    ●RootServer:管理集群中的所有服务器,子表(tablet)数据分布以及副本管
    # k% K/ r8 C  I( j! l5 z理。 RootServer一般为一主一备,主备之间数据强同步。' j/ _. q/ ?% Z$ _! y# h
    ●UpdateServer:存储OceanBase系统的增量更新数据。UpdateServer一般为一主7 D  i" B! b: ~
    一备,主备之间可以配置不同的同步模式。部署时,UpdateServer进程和RootServer
    ) v) P4 ]) V' K* a% ?- m" T进程往往共用物理服务器。
    4 Q  x6 ~* N. Q# |: q9 J7 c: c●ChunkServer:存储OceanBase系统的基线数据。基线数据一般存储两份或者三3 c; \1 S6 ~! ^5 _" Z# R' S7 D
    份,可配置。
    4 l( r/ z7 n9 C  Z# }; J% W/ ]●MergeServer:接收并解析用户的SQL请求,经过词法分析、语法分析、查询优
    % V) H  Q  m  Y2 W% K& z/ a, h化等一系列操作后转发给相应的ChunkServer或者UpdateServer。如果请求的数据分布
    4 v5 ~: J- P% i4 X, w在多台ChunkServer上,MergeServer还需要对多台ChunkServer返回的结果进行合并。/ i/ C6 [* e8 [/ ^; l/ \0 ]
    客户端和MergeServer之间采用原生的MySQL通信协议,MySQL客户端可以直接访问( {! ~7 D) {. \; W
    MergeServer。
    # u) S3 ~) H6 W, FOceanBase支持部署多个机房,每个机房部署一个包含RootServer、
    & q( D! C7 Y+ K- \! [; z0 G5 Q6 I, mMergeServer、ChunkServer以及UpdateServer的完整OceanBase集群,每个集群由各自/ y& w0 _: k1 @5 P, e
    的RootServer负责数据划分、负载均衡、集群服务器管理等操作,集群之间数据同步6 g/ a+ u4 v1 W& O' ~# R9 a' V$ s) M
    通过主集群的主UpdateServer往备集群同步增量更新操作日志实现。客户端配置了多
    ' d3 |5 |" k; `* F个集群的RootServer地址列表,使用者可以设置每个集群的流量分配比例,客户端根' o/ i+ ?0 V, R5 _) u/ f3 O6 U
    据这个比例将读写操作发往不同的集群。图8-2是双机房部署示意图。& g2 d( T9 b5 y$ Q& {1 i
    图 8-2 OceanBase双机房部署! {+ S1 b8 a9 l& a" A7 o+ s
    8.3.2 客户端
    2 r) M8 U9 }' n9 t" ?) G0 O3 i1 MOceanBase客户端与MergeServer通信,目前主要支持如下几种客户端:% G5 v2 e' x) s: {
    ●MySQL客户端:MergeServer兼容MySQL协议,MySQL客户端及相关工具(如
    ( y- j4 H* x6 V6 ]0 l* mJava数据库访问方式JDBC)只需要将服务器的地址设置为任意一台Merge-Server的地5 y  r  s( I8 B* s
    址,就可以直接使用。
    9 n2 q2 W7 _9 H( l●Java客户端:OceanBase内部部署了多台MergeServer,Java客户端提供对 MySQL4 U3 W9 m1 t/ Z* L; D9 U9 x. z
    标准JDBC Driver的封装,并提供流量分配、负载均衡、MergeServer异常处理等功% F" _" x  G) M% i; o
    能。简单来讲,Java客户端首先按照一定的策略定位到某台MergeServer,接着调用% X1 X  `8 T) [/ L* ^
    MySQL JDBC Driver往这台MergeServer发送读写请求。Java客户端实现符合JDBC标
    6 R, D  [7 t3 W准,能够支持Spring、iBatis等Java编程框架。' W  B  @7 D- U1 ^) c! p7 M
    ●C客户端:OceanBase C客户端的功能和Java客户端类似。它首先按照一定的策
    ; {; T& j9 j# R9 G略定位到某台MergeServer,接着调用MySQL标准C客户端往这台MergeServer发送读
    3 N* D# x0 X5 |0 l  d写请求。C客户端的接口和MySQL标准C客户端接口完全相同,因此,能够通过* P) n9 S: z& }' L  Q; x; |
    LD_PRELOAD的方式将应用程序依赖的MySQL标准C客户端替换为OceanBase C客户
    ( x8 t4 A0 T6 u( `* H1 }8 F* S端,而无需修改应用程序的代码。$ W, j; {: \* {/ H
    OceanBase集群有多台MergeServer,这些MergeServer的服务器地址存储在
    $ l) d: P9 O) a* G# U+ @$ wOceanBase服务器端的系统表(与Oracle的系统表类似,存储OceanBase系统的元数% a1 Z% _. B/ J/ g
    据)内。OceanBase Java/C客户端首先请求服务器端获取MergeServer地址列表,接着% z8 h! }3 k! {3 F
    按照一定的策略将读写请求发送给某台MergeServer,并负责对出现故障的, [/ q+ ]8 e# ]! p
    MergeServer进行容错处理。
    - y' r" `; N  v1 t2 E  dJava/C客户端访问OceanBase的流程大致如下:) r. Y" i/ v0 d& a3 D
    1)请求RootServer获取集群中MergeServer的地址列表。0 v& v+ B  p4 X  f
    2)按照一定的策略选择某台MergeServer发送读写请求。客户端与MergeServer" j9 ~+ k* T7 N
    之间的通信协议兼容原生的MySQL协议,因此,只需要调用MySQL JDBC Driver或者
    , v* d5 c" v" s$ GMySQL C客户端这样的标准库即可。客户端支持的策略主要有两种:随机以及一致
    : M5 R  _) l" [性哈希。一致性哈希的主要目的是将相同的SQL请求发送到同一台MergeServer,方! ~! o& V- C! q
    便MergeServer对查询结果进行缓存。- t/ P' U2 o2 ?$ g1 T6 s
    3)如果请求MergeServer失败,则从MergeServer列表中重新选择一台4 Q+ {5 y. y6 y
    MergeServer重试;如果请求某台MergeServer失败超过一定的次数,将这台$ |  {* a7 Q$ u; D" u0 K
    MergeServer加入黑名单并从MergeServer列表中删除。另外,客户端会定期请求
    # L* b# b6 \" N0 P7 b* V3 GRootServer更新MergeServer地址列表。
    : C/ }2 a' V8 H6 n& |5 B) g+ |如果OceanBase部署多个集群,客户端还需要处理多个集群的流量分配问题。使$ l1 n- }$ _& T
    用者可以设置多个集群之间的流量分配比例,客户端获取到流量分配比例后,按照
      A4 [: A4 p" S- K. L& n# {这个比例将请求发送到不同的集群。8 s$ q7 J% Y: z  }. X7 C* i
    OceanBase程序升级版本时,往往先将备集群的读取流量调整为0,这时所有的
    9 ?; z9 x, d, r; O6 T6 Q- D6 h9 M读写请求都只发往主集群,接着升级备集群的程序版本。备集群升级完成后将流量+ [% D- m. ~2 h1 Y
    逐步切换到备集群观察一段时间,如果没有出现异常,则将所有的流量切到备集) o( `3 i% c9 s3 e
    群,并将备集群切换为主集群提供写服务。原来的主集群变为新的备集群,升级新9 @+ E0 E- ~0 l% G; f4 U
    的备集群的程序版本后重新分配主备集群的流量比例。4 O; W* d, a, d2 \! I3 x# }4 p
    8.3.3 RootServer6 [, K3 ]8 Q, Z& D1 F" W! c% c7 b
    RootServer的功能主要包括:集群管理、数据分布以及副本管理。) ^4 y8 V0 s* ~
    RootServer管理集群中的所有MergeServer、ChunkServer以及UpdateServer。每个" c* K! P) R9 U* s4 X1 G2 J( q7 p  z
    集群内部同一时刻只允许一个UpdateServer提供写服务,这个UpdateServer成为主# ~: a0 R" C, X3 j5 C1 @
    UpdateServer。这种方式通过牺牲一定的可用性获取了强一致性。RootServer通过租, p- y4 M. H6 g
    约(Lease)机制选择唯一的主UpdateServer,当原先的主UpdateServer发生故障后,$ P2 s6 n6 g: G
    RootServer能够在原先的租约失效后选择一台新的UpdateServer作为主UpdateServer。
    4 u& b5 C3 M5 l2 Q6 c. j( h+ b% h# W6 Z另外,RootServer与MergeServer&ChunkServer之间保持心跳(heartbeat),从而能够
    . I+ G! w% w! Y' ?! A感知到在线和已经下线的MergeServer&ChunkServer机器列表。
    ) P7 X% i* B# ^OceanBase内部使用主键对表格中的数据进行排序和存储,主键由若干列组成并
    . F( u: f5 M4 W# S" Q且具有唯一性。在OceanBase内部,基线数据按照主键排序并且划分为数据量大致相) D' V0 s! R9 M
    等的数据范围,称为子表(tablet)。每个子表的默认大小是256MB(可配置)。6 h' F- ~) w6 R5 X6 n
    OceanBase的数据分布方式与Bigtable一样采用顺序分布,不同的是,OceanBase没有8 a$ w( c2 ^, S& d; g
    采用根表(RootTable)+元数据表(MetaTable)两级索引结构,而是采用根表一级6 \1 Q5 D; D! [8 L5 l- i5 y
    索引结构。: R+ L! r* F$ V6 T" L5 r
    如图8-3所示,主键值在[1,100]之间的表格被划分为四个子表:1~25,26~
    # U0 x5 v. `6 O. H1 b. r: R% u50,51~80以及81~100。RootServer中的根表记录了每个子表所在的ChunkServer位
    ' W5 U9 B9 l, K  |9 M: E- ~置信息,每个子表包含多个副本(一般为三个副本,可配置),分布在多台; ^5 T: C+ N- C
    ChunkServer中。当其中某台ChunkServer发生故障时,RootServer能够检测到,并且触" u* l2 u1 e/ E3 I; q
    发对这台ChunkServer上的子表增加副本的操作;另外,RootServer也会定期执行负载! Y$ @( I" d8 g- d3 i
    均衡,选择某些子表从负载较高的机器迁移到负载较低的机器上。* P5 B8 y  F) W% ^0 i( i8 t
    图 8-3 基线数据子表划分. @+ m+ O" |5 Y' o
    RootServer采用一主一备的结构,主备之间数据强同步,并通过Linux+ s  l( \/ ^/ n* h* |* ^0 j) _$ y" I
    HA(http://www.linux-ha.org)软件实现高可用性。主备RootServer之间共享VIP,当. x7 E2 l- G3 a, f6 E7 |/ x3 T6 n
    主RootServer发生故障后,VIP能够自动漂移到备RootServer所在的机器,备, W2 t/ H, V* o0 S1 g' S2 s( K( P
    RootServer检测到以后切换为主RootServer提供服务。2 `7 O! P9 Z- Q$ c& Z
    8.3.4 MergeServer
    * j9 ], k3 L$ l8 oMergeServer的功能主要包括:协议解析、SQL解析、请求转发、结果合并、多& _+ N3 D: f! |: ^6 E5 F
    表操作等。, Z( d9 U4 h) G+ ?
    OceanBase客户端与MergeServer之间的协议为MySQL协议。MergeServer首先解, P3 y, N  g; }/ J
    析MySQL协议,从中提取出用户发送的SQL语句,接着进行词法分析和语法分析,7 q- z2 Y: p1 u
    生成SQL语句的逻辑查询计划和物理查询计划,最后根据物理查询计划调用
    , Q- A, Q- s3 |4 f2 [OceanBase内部的各种操作符。# |/ G+ b5 u& s% e4 S
    MergeServer缓存了子表分布信息,根据请求涉及的子表将请求转发给该子表所
    & t2 z& X& N' j7 t" ~# M, R! M1 A% _在的ChunkServer。如果是写操作,还会转发给UpdateServer。某些请求需要跨多个子
    7 S  R4 t7 u# x7 K# H$ V. b1 e表,此时MergeServer会将请求拆分后发送给多台ChunkServer,并合并这些
    + m; s1 N. V; k) C5 KChunkServer返回的结果。如果请求涉及多个表格,MergeServer需要首先从# f) K% Y& Q9 h5 c
    ChunkServer获取每个表格的数据,接着再执行多表关联或者嵌套查询等操作。
    / \' p7 x3 g9 }! w' H1 @/ R9 ]MergeServer支持并发请求多台ChunkServer,即将多个请求发给多台! w7 l+ u' I+ }2 z9 p) Z* C! o
    ChunkServer,再一次性等待所有请求的应答。另外,在SQL执行过程中,如果某个
    0 v$ f8 v% @. h9 U8 w+ H' q* h子表所在的ChunkServer出现故障,MergeServer会将请求转发给该子表的其他副本所
    6 s6 ]4 K3 P0 ~在的ChunkServer。这样,ChunkServer故障是不会影响用户查询的。" a) ]7 k# d# e' i8 u
    MergeServer本身是没有状态的,因此,MergeServer宕机不会对使用者产生影- a3 Y& H/ e6 [* M: R6 @
    响,客户端会自动将发生故障的MergeServer屏蔽掉。
    $ ~9 u( V7 S5 A2 r! @8.3.5 ChunkServer# T9 Q% [7 c7 \6 j% X3 u$ v
    ChunkServer的功能包括:存储多个子表,提供读取服务,执行定期合并以及数
    9 V+ @+ m1 v! v$ p0 W( l1 ~据分发。. k0 }4 W: T, {2 d0 y5 h4 ]+ _
    OceanBase将大表划分为大小约为256MB的子表,每个子表由一个或者多个
    - x6 m: M5 J% r3 cSSTable组成(一般为一个),每个SSTable由多个块(Block,大小为4KB~64KB之
    7 t9 T) X8 [$ u间,可配置)组成,数据在SSTable中按照主键有序存储。查找某一行数据时,需要
    $ G. p( I3 U! ?% f$ i首先定位这一行所属的子表,接着在相应的SSTable中执行二分查找。SSTable支持两4 {2 J- c! R0 D. U; K
    种缓存模式,块缓存(Block Cache)以及行缓存(Row Cache)。块缓存以块为单位" H* Z5 O% D4 ^* e& w
    缓存最近读取的数据,行缓存以行为单位缓存最近读取的数据。
    1 ^% [; L* e" Z! H. o0 X; E) QMergeServer将每个子表的读取请求发送到子表所在的ChunkServer,ChunkServer首; A; a" l& t7 `" k
    先读取SSTable中包含的基线数据,接着请求UpdateServer获取相应的增量更新数据,; e7 n. o. Z* v; |! H, T
    并将基线数据与增量更新融合后得到最终结果。
    ( C' @  u, t8 q% O由于每次读取都需要从UpdateServer中获取最新的增量更新,为了保证读取性
    ; W6 w5 ]5 T$ P能,需要限制UpdateServer中增量更新的数据量,最好能够全部存放在内存中。" W2 m% i6 N! ], q4 J5 o- g# P
    OceanBase内部会定期触发合并或者数据分发操作,在这个过程中,ChunkServer将从; W2 b& A1 k7 h
    UpdateServer获取一段时间之前的更新操作。通常情况下,OceanBase集群会在每天& e9 x" a! c* c) o6 h( q0 ?5 v
    的服务低峰期(凌晨1:00开始,可配置)执行一次合并操作。这个合并操作往往也称
    ( _8 U, n& E' n+ y: I为每日合并。
    0 N( [( A& o! C& t8.3.6 UpdateServer/ |( H. n* \' k0 X
    UpdateServer是集群中唯一能够接受写入的模块,每个集群中只有一个主Update-6 D' s0 L6 f1 Z) t9 R6 G
    Server。UpdateServer中的更新操作首先写入到内存表,当内存表的数据量超过一定# t1 T  Q3 Z0 b4 j* A
    值时,可以生成快照文件并转储到SSD中。快照文件的组织方式与ChunkServer中的
    5 R- [1 J0 h+ A8 u' GSSTable类似,因此,这些快照文件也称为SSTable。另外,由于数据行的某些列被更8 X$ k$ S+ s0 W- D
    新,某些列没被更新,SSTable中存储的数据行是稀疏的,称为稀疏型SSTable。
    * c" D% R. _9 z为了保证可靠性,主UpdateServer更新内存表之前需要首先写操作日志,并同步
    2 }6 d* V' R. Y- I到备UpdateServer。当主UpdateServer发生故障时,RootServer上维护的租约将失效,/ Y& i  }* f; V% U- t& |" n
    此时,RootServer将从备UpdateServer列表中选择一台最新的备UpdateServer切换为主
    6 s' j$ }1 o. P; X+ l4 S& XUpdateServer继续提供写服务。UpdateServer宕机重启后需要首先加载转储的快照文# e( T. A& i$ T; T- Q5 Y
    件(SSTable文件),接着回放快照点之后的操作日志。  Z8 l  @8 {4 t; q1 R' a! n2 ^5 G
    由于集群中只有一台主UpdateServer提供写服务,因此,OceanBase很容易地实
    7 E' {) ]3 }" E( ?- O8 F& K现了跨行跨表事务,而不需要采用传统的两阶段提交协议。当然,这样也带来了一
    # v, F4 l: h) M- z" P系列的问题。由于整个集群所有的读写操作都必须经过UpdateServer,UpdateServer的. ]/ c, V# L0 E2 N
    性能至关重要。OceanBase集群通过定期合并和数据分发这两种机制将UpdateServer
    . v1 G5 V, O. l+ M: t! N一段时间之前的增量更新源源不断地分散到ChunkServer,而UpdateServer只需要服务
    ; w, C& F' f! A& S9 b( ~最新一小段时间新增的数据,这些数据往往可以全部存放在内存中。另外,系统实
    3 D# ?  W9 `4 p# c0 w( n现时也需要对UpdateServer的内存操作、网络框架、磁盘操作做大量的优化。
    ( T- I( Q6 B, J; F/ \, k; B9 r8.3.7 定期合并&数据分发5 C: j5 _# d: g( `
    定期合并和数据分发都是将UpdateServer中的增量更新分发到ChunkServer中的手' j1 y3 Z9 t$ b7 @
    段,二者的整体流程比较类似:5 M/ x" E  i- ^* {
    1)UpdateServer冻结当前的活跃内存表(Active MemTable),生成冻结内存
    ' |) R% J: E2 u) C, o/ N( X表,并开启新的活跃内存表,后续的更新操作都写入新的活跃内存表。
    * B6 B6 F& V3 H9 x, f2)UpdateServer通知RootServer数据版本发生了变化,之后RootServer通过心跳
    ( N6 t. t7 K: w" h% Q9 D& Q3 ^消息通知ChunkServer。$ [; P6 V# o; z$ a  K" \6 f2 P! r
    3)每台ChunkServer启动定期合并或者数据分发操作,从UpdateServer获取每个
    ! N. v1 W3 o! a! {; s* v子表对应的增量更新数据。- Q; n! ?3 D& {$ W* {% f# ^+ I
    定期合并与数据分发两者之间的不同点在于,数据分发过程中ChunkServer只是2 P( B. [" ]: @* t) [9 d
    将UpdateServer中冻结内存表中的增量更新数据缓存到本地,而定期合并过程中/ p5 A/ X* x$ h' X4 ?
    ChunkServer需要将本地SSTable中的基线数据与冻结内存表的增量更新数据执行一次
    % v1 d9 b$ n9 ~) z4 z多路归并,融合后生成新的基线数据并存放到新的SSTable中。定期合并对系统服务# n3 h+ M2 u4 M# L; W8 y
    能力影响很大,往往安排在每天服务低峰期执行(例如凌晨1点开始),而数据分发4 _4 h; d# ?! q; @* M6 D
    可以不受限制。
    * W8 U' a9 R& f( [2 c; A& H如图8-4,活跃内存表冻结后生成冻结内存表,后续的写操作进入新的活跃内存$ A( e( e+ X' c( @& A
    表。定期合并过程中ChunkServer需要读取UpdateServer中冻结内存表的数据、融合后0 v; e: x& t: d5 I  L3 E- c
    生成新的子表,即:
    8 w0 p) J) D6 z# O- k新子表=旧子表+冻结内存表
    ! c! U# [5 O# ~图 8-4 定期合并不停读服务
    2 S, s, j8 W/ b  [( B虽然定期合并过程中各个ChunkServer的各个子表合并时间和完成时间可能都不4 t6 P$ C# J# b1 G0 l
    相同,但并不影响读取服务。如果子表没有合并完成,那么使用旧子表,并且读取
    9 Z1 t, C4 b9 @' WUpdateServer中的冻结内存表以及新的活跃内存表;否则,使用新子表,只读取新的
    ! x8 @" [( v9 A5 k3 M活跃内存表,即:0 S: Y6 L! U/ y4 Z5 i3 C
    查询结果=旧子表+冻结内存表+新的活跃内存表
    8 [1 O( s# O& P4 r$ l* W=新子表+新的活跃内存表
    + A9 d) X, |6 I3 W; p) [$ P' X
    $ a- \; I9 `  `5 J
    1 b, B4 o4 V) ~
    回复

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2025-1-22 14:55 , Processed in 0.903000 second(s), 30 queries .

    Powered by Javazx

    Copyright © 2012-2022, Javazx Cloud.

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