java自学网VIP

Java自学网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2274|回复: 0

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

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

    [LV.Master]出神入化

    2025

    主题

    3683

    帖子

    6万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    66101

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

    发表于 2017-3-6 14:41:55 | 显示全部楼层 |阅读模式
    9.5 消除更新瓶颈
    0 f9 L: v  M' D; V  f7 W, f( q- N/ lUpdateServer单点看起来像是OceanBase架构的软肋,然而,经过OceanBase团队
    $ e  b1 ?2 Z( w4 a5 \0 v) H持续不断地性能优化以及旁路导入功能的开发,单点的架构在实践过程中经受住了! [  X6 G9 ?# \8 J$ G5 |$ F2 z; p
    线上考验。每年淘宝网“双十一”光棍节,OceanBase系统都承载着核心的数据库业; z$ v5 y/ E" V. m
    务,系统访问量出现5到10倍的增长,而OceanBase只需简单地增加机器即可。. Z! a& b0 M2 r* N  P; @  f# O3 n% ~
    当然,UpdateServer单点架构并不是不可突破。虽然目前UpdateServer单点架构
    ) o3 [/ i; @! ]" l还不是瓶颈,但是OceanBase系统设计时已经留好了“后门”,以后可以通过对系统打! D# T- {& {( Z3 d, D& H/ n
    补丁的方式支持UpdateServer线性扩展。当然,这里可能会做一些牺牲,比如短期内* ^& c2 @1 [2 x* m/ W& ]
    暂不支持全局事务,只支持针对单个用户的事务操作。9 L+ S2 S& a+ A
    本节首先回顾OceanBase已经实现的优化工作,包括读写性能优化以及旁路导入" G( T( ~8 g" b
    功能,接着介绍一种数据分区实现UpdateServer线性扩展的方法。4 d5 z" N- Y( ?9 p+ ]
    9.5.1 读写优化回顾
    " ^( q, u) |+ j4 vOceanBase UpdateServer相当于一个内存数据库,其架构设计和“世界上最快的内
    # n( t0 k% K" P/ `) a& w存数据库”MemSQL比较类似,能够支持每秒数百万次单行读写操作,这样的性能对& Y, u& w. I. |5 l$ c+ l
    于目前关系数据库的应用场景都是足够的。为了达到这样的性能指标,我们已经完
    $ z% h9 j, d% v* q  o+ Z0 O成或正在进行的工作如下。
    - W2 U6 W8 T3 J1.网络框架优化( ?5 `& i# o1 ]% d1 J5 U
    9.2.2 节中提到,如果不经过优化,单机每秒最多能够接收的数据包个数只有
    3 V' W" [% Y6 C. Z( {- D% ~10万个左右,而经过优化后的libeasy框架对于千兆网卡每秒最多收包个数超过50
    4 y0 b3 G4 i- }7 v- d万,对于万兆网卡则超过100万。另外,UpdateServer内部还会在软件层面实现多块
    ' s# {& h  j" j' `4 A* m网卡的负载均衡,从而更好地发挥多网卡的优势。通过网络框架优化,使得单机支- b0 c2 t" q" x' ^
    持百万次操作成为可能。. w" A8 R  e# Z# A- @( `' \
    2.高性能内存数据结构
    0 O: J" N+ A5 [( _UpdateServer的底层是一颗高性能内存B树。为了最大程度地发挥多核的优势,B
    " L  l) ~% Y& d树实现时大部分情况下都做到了无锁(lock-free)。测试数据表明,即使在普通的16& \$ _+ O6 s' B
    核机器上,OceanBase B树每秒支持的单行修改操作都超过150万次。
    8 B  {; q4 y7 Y! c" C3.写操作日志优化
    ' U( N: f' [( g0 k3 t在软件层面,写操作日志涉及的工作主要有如下几点:
    0 l* r. U' v6 \3 Q4 p1)成组提交。将多个写操作聚合在一起,一次性刷入磁盘中。) a5 f4 Z: F1 w; d
    2)降低日志缓冲区的锁冲突。多个线程同时往日志缓冲区中追加数据,实现时
    5 p" a3 O/ S& W需要尽可能地减少追加过程的锁冲突。追加过程包含两个阶段:第一个阶段是占- y0 G# D' O+ [: i4 \8 p
    位,第二个阶段是拷贝数据,相比较而言,拷贝数据比较耗时。实现的关键在于只" N4 E$ _  \2 X
    对占位操作互斥,而允许多线程并发拷贝数据。例如,有两个线程,线程1和线程+ ?5 ?% ]/ R& w
    2,他们分别需要往缓冲区追加大小为100字节和大小为300字节的数据。假设缓冲区) p  M. V$ Z% S& E' P5 v
    初始为空,那么,线程1可以首先占住位置0~100,线程2接着占住100~300。最) x! P9 \" g+ v% U0 K7 \, c" [
    后,线程1和线程2并发将数据拷贝到刚才占住的位置。( z5 @! c) {% B8 A. x
    3)日志文件并发写入。UpdateServer中每个日志缓冲区的大小一般为2MB,如) F0 l5 }( c! n% K
    果写入太快,那么,很快会产生多个日志缓冲区需要刷入磁盘,可以并发地将这些
    3 Z, ^( C2 R1 t% j6 V日志缓冲区刷入不同的磁盘。当然,UpdateServer目前并没有实现2和3这两个优化$ a( I1 o' b8 S" g" K2 t9 p
    点。在硬件层面,UpdateServer机器需要配置较好的RAID卡。这些RAID卡自带缓$ Z' F! Z# g. W6 z$ y- ^
    存,而且容量比较大(例如1GB),从而进一步提升写磁盘性能。
    # I3 q: A8 n9 i3 q9 j, L4.内存容量优化: b9 L- f0 o" ^6 `. v2 m- Y
    随着数据不断写入,UpdateServer的内存容量将成为瓶颈。因此,有两种解决思  Y  V. x! T& d" M4 u
    路。一种思路是精心设计UpdateServer的内存数据结构,尽可能地节省内存使用;另5 x- T- N! m: m4 k/ p5 I
    外一种思路就是将UpdateServer内存中的数据很快地分发出去。
    , ?0 t9 I1 Z3 k1 T6 b( o3 @OceanBase实现了这两种思路。首先,UpdateServer会将内存中的数据编码为精( e2 p7 c& z  n: U
    心设计的格式,从9.3.1节中可以看出,100以内的64位整数在内存中只需要占用两个$ @  e: s/ M- E  ~& _( }1 N' o
    字节。这种编码格式不仅能够有效地减少内存占用,而且往往使得CPU缓存能够容
    + \6 v- `* a$ V4 c3 L" P# s纳更多的数据,从而弥补编码和解码操作造成的性能损失。另外,当UpdateServer的
    9 C& `% ]* P! g$ Y/ ^# U内存使用量到达一定大小时,OceanBase会自动触发数据分发操作,将UpdateServer
    ' v/ @# F  F  R4 `. s4 l# B的数据分发到集群中的ChunkServer中,从而避免UpdateServer的内存容量成为瓶颈。& z/ C( F, }$ V7 N
    当然,随着单机内存容量变得越来越大,普通的2U服务器已经具备1TB内存的扩展' j: ~0 [  k# C- l3 d
    能力,数据分发也可能只是一种过渡方案。' O" p8 j7 q& h" t5 I! f( ?, i
    9.5.2 数据旁路导入; L5 _8 d3 C) W2 U. h( B5 g
    虽然OceanBase内部实现了大量优化技术,但是UpdateServer单点写入对于某些
    8 n+ Q9 [# w! [% D9 u7 zOLAP应用仍然可能成为问题。这些应用往往需要定期(例如每天,每个月)导入大0 V$ M* W; Z1 y/ z7 {5 z( V, D
    批数据,对导入性能要求很高。为此,OceanBase专门开发了旁路导入功能,本节介
    / Q1 R9 i5 y" `& w5 L; `: _绍直接将数据导入到ChunkServer中的方法(即ChunkServer旁路导入)。
    $ f5 d) B0 f9 y; ?) [0 z9 w, t5 vOceanBase的数据按照全局有序排列,因此,旁路导入的第一步就是使用Hadoop
    1 ?+ i2 A; I' NMapReduce这样的工具将所有的数据排好序,并且划分为一个个有序的范围,每个范6 K, ^, @4 I$ w7 [2 y3 S- ?" x( J. {
    围对应一个SSTable文件。接着,再将SSTable文件并行拷贝到集群中所有的6 X. j  D4 I+ l. d2 Q
    ChunkServer中。最后,通知RootServer要求每个ChunkServer并行加载这些SSTable文" F. z$ P# V6 ]4 o0 \2 W0 X0 @2 d
    件。每个SSTable文件对应ChunkServer的一个子表,ChunkServer加载完本地的SSTable
    ) m/ ^4 w+ U# G  n8 w- j文件后会向RootServer汇报,RootServer接着将汇报的子表信息更新到RootTable中。
    4 J4 ?8 V2 V. }: G; n例9-7 有4台ChunkServer:A、B、C和D。所有的数据排好序后划分为6个范7 R& Q2 ~9 I" n# D6 L) c) I: R
    围:r1(0~100]、r2(100~200]、r3(200~300]、r4(300~400]、r5(400~% ~# {. r- x9 |3 j" k/ J% ~: b
    500]、r6(500~600],对应的SSTable文件分别记为sst1,sst2,……,sst6。假设每
    $ Q# Z3 ?/ {9 C个子表存储两个副本,那么,拷贝完SSTable文件后,可能的分布情况为:
    $ @9 p" n% D: }: D2 |A:sst1,sst3,sst4
    . n* k, D, w2 o1 M+ x" ?B:sst2,sst3,sst5% Q% }, F* {9 Y3 ?" t! p
    C:sst1,sst4,sst64 ]! P* J5 ?8 q, M) Z" l
    D:sst2,sst5,sst6
    5 X8 ^1 l8 ^  P- H( B) ?接着,每个ChunkServer分别加载本地的SSTable文件,完成后向RootServer汇* [7 Y! u+ a' D
    报。RootServer最终会将这些信息记录到RootTable中,如下:
    $ [* {. U3 V( }* }& Gr1(0~100]:A、C% k% V2 q8 i# @0 t5 v9 R
    r2(100~200]:B、D
    9 {0 \4 N, i) ur3(200~300]:A、B* n8 S! b4 ^9 C$ Q! }+ Q- ]' p- e
    r4(300~400]:A、C9 z& n; S. V. ~4 D/ K- i
    r5(400~500]:B、D
    + w* o" c) Q1 l7 K2 gr6(500~600]:C、D
    ; b" l/ w, F) I- O8 M( d8 l如果导入的过程中ChunkServer发生故障,例如拷贝sst1到机器C失败,那么,旁
    7 Y# `/ C" S* `/ j! r9 a% E3 L路导入模块会自动选择另外一台机器拷贝数据。
    ' k1 g( u0 g/ k/ W3 d当然,实现旁路导入功能时还需要考虑很多问题。例如,如何支持将数据导入5 O% P3 T9 O1 i, {- R+ L* e# t' Q7 N
    到多个数据中心的主备OceanBase集群,这里不会涉及这些细节。% e0 j8 E) a/ d1 m: ?2 v
    9.5.3 数据分区0 E: ?5 Y5 B# P
    虽然我们坚持认为通过单机性能优化以及硬件性能的提升,UpdateServer单点对
      B, u/ _3 W3 R& o' K% x1 m, I3 U于互联网数据库业务不会成为瓶颈。但是,随着OceanBase的应用场景越来越广,例
      w& X7 ?# \& _1 |如,存储原始日志,我们也可能需要实现更新节点可扩展。本节探讨一种可能的做
    # z4 H* C8 e* t0 \7 i. E3 ]& U法。
    + P6 G+ `# B7 v4 X+ vOceanBase可以借鉴关系数据库中的分区表的概念,将数据划分为多个分区,允' M3 C' `) X9 d  w
    许不同的分区被不同的UpdateServer服务。例如,将所有的数据按照哈希的方式划分& l9 u. h3 W: @6 j
    为4096个分区,这样,同一个集群中最多允许4096个写节点。6 [6 J$ A! U: C. l
    如图9-11所示,可以将Users表格和Albums的user_id列按照相同的规则做哈希,
    % f5 q5 f6 ~* c4 C% r这样,同一个用户的所有数据属于相同的分区。由于同一个分区只会被同一个
    ' H  b! N/ e3 }1 |0 JUpdateServer服务,因此,保证了同一个用户下读写操作的事务性,另外,不同用户
    ! R  _2 }) ?( D& f9 W% w之间的事务可以通过两阶段提交或者最终一致性的方式实现。这种方式实现起来非
    + P* c& J' s& C! j常简单,而且能够完全兼容SQL语法。
    % p# M; C4 S. h% O( r" c& U图 9-11 哈希分区SQL语法8 V# ]/ Z4 j# n8 _  a1 Z
    从图8-1中的整体架构图可以看出,在目前的单更新节点架构中,UpdateServer进* S$ o) B1 A1 w( x' ^# z, O  E% Y' W
    程总是与ChunkServer进程部署到不同的服务器,而且两种服务器对硬件的要求不% ^( P) S! ~( M, h' o* K
    同。如果OceanBase支持哈希分区,还能够将UpdateServer进程和ChunkServer进程部
    ! \/ r& b. Q: v0 u% k% g) j署到一起,这样部署起来会更加方便。( l) ?1 ], P1 Z6 ?5 N% o  [( O
    除了哈希分区,OceanBase还能够通过范围分区实现更新节点可扩展,即不同的
    3 z6 M" K  Q  z2 b% }用户按照user_id有序分布到多台UpdateServer。虽然支持UpdateServer线性可扩展的
    2 U- Y3 b7 Z( b$ J架构看似“比较优雅”,但是,这件事情并不紧急。这是因为,OLTP类应用对性能的: ]- z' x7 R7 R: K7 [1 M( Q/ |
    需求是有天花板的(例如全世界人口共50亿,即使其中五分之一的人都在某一天产
    2 d0 ~! E1 u) H6 I" e% F; V+ E& l生了一笔交易,这一天的总交易笔数也只有10亿笔),单UpdateServer对于OLTP类数# o* e. i; I  G# L. o7 a
    据库业务的性能是足够的。, F$ Y+ y; C% s4 M. w1 I

    3 Y9 H' X( S4 ~" h8 @: p, c# P1 A; K$ d5 F3 {
    回复

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-4-29 13:19 , Processed in 0.092244 second(s), 31 queries .

    Powered by Javazx

    Copyright © 2012-2022, Javazx Cloud.

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