java自学网VIP

Java自学网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2464|回复: 0

《大规模分布式存储系统》第9章 分布式存储引擎【9.5】

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

    [LV.Master]出神入化

    2025

    主题

    3683

    帖子

    6万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    66345

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

    发表于 2017-3-6 14:41:55 | 显示全部楼层 |阅读模式
    9.5 消除更新瓶颈* v+ \8 M" f7 `
    UpdateServer单点看起来像是OceanBase架构的软肋,然而,经过OceanBase团队
    % z; d1 k7 N  r3 r% b2 Z持续不断地性能优化以及旁路导入功能的开发,单点的架构在实践过程中经受住了1 l  x3 b8 |4 y: D7 n) ^  ?
    线上考验。每年淘宝网“双十一”光棍节,OceanBase系统都承载着核心的数据库业
    0 y- @: e& Y6 t5 S3 B, X务,系统访问量出现5到10倍的增长,而OceanBase只需简单地增加机器即可。
    1 v1 @* A3 y% V$ v( M7 Z当然,UpdateServer单点架构并不是不可突破。虽然目前UpdateServer单点架构" \+ P+ e* c5 D6 v# z
    还不是瓶颈,但是OceanBase系统设计时已经留好了“后门”,以后可以通过对系统打
    : q$ k# y9 \! `4 C$ u3 f4 L补丁的方式支持UpdateServer线性扩展。当然,这里可能会做一些牺牲,比如短期内8 o% O- m' m3 \: C% O
    暂不支持全局事务,只支持针对单个用户的事务操作。
    ; s- C+ B4 i; n. {" S. d! ]; n本节首先回顾OceanBase已经实现的优化工作,包括读写性能优化以及旁路导入: b4 w6 I7 j3 r! [
    功能,接着介绍一种数据分区实现UpdateServer线性扩展的方法。
    9 V0 `. q0 g8 i" U( H9.5.1 读写优化回顾6 {% e* G" O2 P. w5 s
    OceanBase UpdateServer相当于一个内存数据库,其架构设计和“世界上最快的内4 a" [  g. P5 X7 F
    存数据库”MemSQL比较类似,能够支持每秒数百万次单行读写操作,这样的性能对; c* z' [; L# U7 }+ p3 C& {) I
    于目前关系数据库的应用场景都是足够的。为了达到这样的性能指标,我们已经完% c: a6 u* Q( R  u" ~
    成或正在进行的工作如下。4 Y: e- q. c* A2 X) J4 E
    1.网络框架优化: `/ _! l4 D/ Z" t5 ^  p  x, q; A: G/ B
    9.2.2 节中提到,如果不经过优化,单机每秒最多能够接收的数据包个数只有
    / }6 z2 Z) h/ b" J+ G10万个左右,而经过优化后的libeasy框架对于千兆网卡每秒最多收包个数超过50; @% ^$ u5 [! M( i8 }+ T
    万,对于万兆网卡则超过100万。另外,UpdateServer内部还会在软件层面实现多块4 K  w6 q5 p* C5 T- l
    网卡的负载均衡,从而更好地发挥多网卡的优势。通过网络框架优化,使得单机支5 m- i5 ^- E, J4 n# v
    持百万次操作成为可能。& }( n+ G1 d5 k4 y+ c$ d
    2.高性能内存数据结构  K/ [+ ?" K; V& X
    UpdateServer的底层是一颗高性能内存B树。为了最大程度地发挥多核的优势,B0 m# ?# A9 d. h. s- f
    树实现时大部分情况下都做到了无锁(lock-free)。测试数据表明,即使在普通的16
    / H3 X# }$ z4 ]& t( Y# c核机器上,OceanBase B树每秒支持的单行修改操作都超过150万次。4 @" R& C( N4 i0 X6 o  k
    3.写操作日志优化! n9 C4 n4 [* t9 m6 h2 y+ K, D/ i
    在软件层面,写操作日志涉及的工作主要有如下几点:/ D; Z, j5 Q; M2 {; e
    1)成组提交。将多个写操作聚合在一起,一次性刷入磁盘中。5 `: Y- m( y8 l" }2 e% L
    2)降低日志缓冲区的锁冲突。多个线程同时往日志缓冲区中追加数据,实现时: n) g# P+ C, J) z3 Q
    需要尽可能地减少追加过程的锁冲突。追加过程包含两个阶段:第一个阶段是占
      e& k. M7 g7 M4 A位,第二个阶段是拷贝数据,相比较而言,拷贝数据比较耗时。实现的关键在于只
    ! y) g: R2 c4 H! r# E2 `6 g  o' b- M对占位操作互斥,而允许多线程并发拷贝数据。例如,有两个线程,线程1和线程: d* z- w. V. U' F, f' ?
    2,他们分别需要往缓冲区追加大小为100字节和大小为300字节的数据。假设缓冲区
    # q$ p+ N1 f% L' U' Y初始为空,那么,线程1可以首先占住位置0~100,线程2接着占住100~300。最$ T& g0 g+ e) I' r" b: z
    后,线程1和线程2并发将数据拷贝到刚才占住的位置。3 ~2 f' u9 `4 s- k) E0 g
    3)日志文件并发写入。UpdateServer中每个日志缓冲区的大小一般为2MB,如/ T6 z5 \* v* q* p) c
    果写入太快,那么,很快会产生多个日志缓冲区需要刷入磁盘,可以并发地将这些
    2 D! A0 `3 y5 V" _) u" Y日志缓冲区刷入不同的磁盘。当然,UpdateServer目前并没有实现2和3这两个优化; j& j- I4 |; Y$ Q
    点。在硬件层面,UpdateServer机器需要配置较好的RAID卡。这些RAID卡自带缓
    . k/ y  C: T# b7 `" W存,而且容量比较大(例如1GB),从而进一步提升写磁盘性能。
    8 c  d0 r$ X5 z+ _& [6 T4.内存容量优化9 V6 M% ^7 U: C! `0 ^
    随着数据不断写入,UpdateServer的内存容量将成为瓶颈。因此,有两种解决思
    0 a# P4 H1 w3 r! ^: e路。一种思路是精心设计UpdateServer的内存数据结构,尽可能地节省内存使用;另- J# B5 B7 k! e. o
    外一种思路就是将UpdateServer内存中的数据很快地分发出去。, x& Z. p3 `' O6 v% f
    OceanBase实现了这两种思路。首先,UpdateServer会将内存中的数据编码为精
    4 m& G9 e- p. f  l$ K心设计的格式,从9.3.1节中可以看出,100以内的64位整数在内存中只需要占用两个' i' z! |( U& J
    字节。这种编码格式不仅能够有效地减少内存占用,而且往往使得CPU缓存能够容
    ; s' m2 j5 t2 z  s纳更多的数据,从而弥补编码和解码操作造成的性能损失。另外,当UpdateServer的+ B' G$ z) c/ S' e! |
    内存使用量到达一定大小时,OceanBase会自动触发数据分发操作,将UpdateServer
    6 }7 p) m' L  W) o的数据分发到集群中的ChunkServer中,从而避免UpdateServer的内存容量成为瓶颈。
    # ~) g8 J' k6 h# w& P当然,随着单机内存容量变得越来越大,普通的2U服务器已经具备1TB内存的扩展7 Q  X; q( F! h/ T# ?" _2 e
    能力,数据分发也可能只是一种过渡方案。
    7 g; ]3 }) J6 ~+ ]6 m  N0 P% F3 [% m1 r9.5.2 数据旁路导入
    6 }* C* \9 q2 V7 P- G1 K; y6 a2 s虽然OceanBase内部实现了大量优化技术,但是UpdateServer单点写入对于某些
    9 q) b" ]* J+ o, Q) s- IOLAP应用仍然可能成为问题。这些应用往往需要定期(例如每天,每个月)导入大
    9 D0 Z( @* @: b! a# `* b0 S4 L; r批数据,对导入性能要求很高。为此,OceanBase专门开发了旁路导入功能,本节介4 [0 f) ^9 c- {8 U8 O, b7 r
    绍直接将数据导入到ChunkServer中的方法(即ChunkServer旁路导入)。
    8 E2 D% M- g" F8 n  i2 |. `OceanBase的数据按照全局有序排列,因此,旁路导入的第一步就是使用Hadoop3 f5 W  W$ h' o. Y' W
    MapReduce这样的工具将所有的数据排好序,并且划分为一个个有序的范围,每个范
    : E) w8 h9 \; [2 }7 Z围对应一个SSTable文件。接着,再将SSTable文件并行拷贝到集群中所有的
    5 {& ]9 N8 t( {2 ~ChunkServer中。最后,通知RootServer要求每个ChunkServer并行加载这些SSTable文
    " i% t6 N; P" n  s件。每个SSTable文件对应ChunkServer的一个子表,ChunkServer加载完本地的SSTable
    " }1 O# p! ]1 p  E# v4 C文件后会向RootServer汇报,RootServer接着将汇报的子表信息更新到RootTable中。& |5 b/ a8 x( I! M
    例9-7 有4台ChunkServer:A、B、C和D。所有的数据排好序后划分为6个范7 f6 `. d* n0 T; B! K  {
    围:r1(0~100]、r2(100~200]、r3(200~300]、r4(300~400]、r5(400~
    $ M& K; y8 A- b$ @3 D500]、r6(500~600],对应的SSTable文件分别记为sst1,sst2,……,sst6。假设每
      m0 z. _4 v( T" G$ R: F+ M个子表存储两个副本,那么,拷贝完SSTable文件后,可能的分布情况为:4 {; k* l+ {; u" I
    A:sst1,sst3,sst4: \; h5 j( \( s9 u
    B:sst2,sst3,sst56 Z& p8 ~8 u# p, g" j) a, }( a
    C:sst1,sst4,sst6$ k: D, m& ^5 Y8 N: f
    D:sst2,sst5,sst6
    " Y! m* n0 y2 r2 f; |7 P接着,每个ChunkServer分别加载本地的SSTable文件,完成后向RootServer汇
    ; k1 Q* ]2 l$ F1 `6 o: o" [报。RootServer最终会将这些信息记录到RootTable中,如下:& J6 H; K( l# j
    r1(0~100]:A、C; |  \0 M* D# \5 v' C
    r2(100~200]:B、D
      X1 x* R) D# g/ zr3(200~300]:A、B3 R1 J+ O7 f( x+ G' Z! p
    r4(300~400]:A、C! Y) K  G; P3 B, z1 L& v, I
    r5(400~500]:B、D
    - U) Z1 f' ^7 H. t; ~- j# J4 @/ C  u0 l7 tr6(500~600]:C、D
    ; f; z6 h& t5 N4 b如果导入的过程中ChunkServer发生故障,例如拷贝sst1到机器C失败,那么,旁
    % }+ ?8 i. L+ R) C6 _路导入模块会自动选择另外一台机器拷贝数据。
    # b% h6 l/ w3 o当然,实现旁路导入功能时还需要考虑很多问题。例如,如何支持将数据导入8 o; H5 K* K$ E5 Z: H1 D; ?0 ]
    到多个数据中心的主备OceanBase集群,这里不会涉及这些细节。4 R7 h' E  I8 C. {
    9.5.3 数据分区8 F. A/ x: S$ o0 \
    虽然我们坚持认为通过单机性能优化以及硬件性能的提升,UpdateServer单点对: t' m* N" R& W0 r$ I# H
    于互联网数据库业务不会成为瓶颈。但是,随着OceanBase的应用场景越来越广,例
    8 x( W. E& W0 ]) r& d/ Q如,存储原始日志,我们也可能需要实现更新节点可扩展。本节探讨一种可能的做
    : ^4 t- l: a9 o# ~; @法。
    4 u# q0 T4 C7 {OceanBase可以借鉴关系数据库中的分区表的概念,将数据划分为多个分区,允0 m+ s& o  j" Q0 {$ A. |
    许不同的分区被不同的UpdateServer服务。例如,将所有的数据按照哈希的方式划分4 B) _  D6 c7 |) x7 ]: w4 M) u
    为4096个分区,这样,同一个集群中最多允许4096个写节点。6 x, N. L8 }- Y! y! k
    如图9-11所示,可以将Users表格和Albums的user_id列按照相同的规则做哈希,  h  l9 x4 `- L
    这样,同一个用户的所有数据属于相同的分区。由于同一个分区只会被同一个/ n0 z" w7 F4 J$ a  c, x" B+ T
    UpdateServer服务,因此,保证了同一个用户下读写操作的事务性,另外,不同用户
    $ S. R; t. q. f/ ~" \之间的事务可以通过两阶段提交或者最终一致性的方式实现。这种方式实现起来非. q6 \" `- }1 [8 I1 u
    常简单,而且能够完全兼容SQL语法。: U, ^" @- S# I
    图 9-11 哈希分区SQL语法! g: A4 s  m$ C& w; S
    从图8-1中的整体架构图可以看出,在目前的单更新节点架构中,UpdateServer进4 X5 ]* u% v. {. d$ ]% u
    程总是与ChunkServer进程部署到不同的服务器,而且两种服务器对硬件的要求不' X, N: a  V4 F
    同。如果OceanBase支持哈希分区,还能够将UpdateServer进程和ChunkServer进程部
    1 A- s' f% I' J0 Q9 H署到一起,这样部署起来会更加方便。8 n$ ^( ?9 T; U0 {+ G3 z' E
    除了哈希分区,OceanBase还能够通过范围分区实现更新节点可扩展,即不同的* _% w) ?6 U3 L6 H0 W5 k' `; l
    用户按照user_id有序分布到多台UpdateServer。虽然支持UpdateServer线性可扩展的
    ! [9 z! I7 Y9 X架构看似“比较优雅”,但是,这件事情并不紧急。这是因为,OLTP类应用对性能的
    ' u- V- R2 l6 t$ A" F- E需求是有天花板的(例如全世界人口共50亿,即使其中五分之一的人都在某一天产
    9 S4 j( j5 S+ j  U4 k生了一笔交易,这一天的总交易笔数也只有10亿笔),单UpdateServer对于OLTP类数
    # o% |( j$ u7 w5 x- k据库业务的性能是足够的。
    2 d: C- G* w0 ?, r- p% A- W+ m$ K- E' r( w  \+ x4 I

    / t; [' @% G8 |5 i
    回复

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-11-21 20:36 , Processed in 0.127172 second(s), 30 queries .

    Powered by Javazx

    Copyright © 2012-2022, Javazx Cloud.

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