|
10.4 OLAP业务支持
( `8 ~# k& n/ zOLAP业务的特点是SQL每次执行涉及的数据量很大,需要一次性分析几百万行
$ u3 e" Y; g5 @% K甚至几千万行的数据。另外,SQL执行时往往只读取每行的部分列而不是整行数据。1 b6 }- o" b: v4 f
为了支持OLAP计算,OceanBase实现了两个主要功能:并发查询以及列式存
; P- c" b+ F- @4 _) L) a6 g( {- o储。并行查询功能允许将SQL请求拆分为多个子请求同时发送给多台机器并发执行,8 e' H# ]- F- K8 u& n
列式存储能够提高压缩率,大大降低SQL执行时读取的数据量。本节首先介绍并发查2 `; h/ G- X+ e- c. ^
询功能,接着介绍OceanBase的列式存储引擎。9 y# P1 B: ~2 G8 K- X
10.4.1 并发查询
6 g9 B/ b: d. ]% q: V如图10-13所示,MergeServer将大请求拆分为多个子请求,同时发往每个子请求
. l, t3 q. q6 _: l所在的ChunkServer并发执行,每个ChunkServer执行子请求并将部分结果返回给
$ u3 }6 C. E% V2 @+ wMergeServer。MergeServer合并ChunkServer返回的部分结果并将最终结果返回给客户 U7 }$ {1 J, X7 d, _9 S3 \8 A& S2 S; N
端。! B' F3 Y9 R3 ]2 A8 k
图 10-13 OceanBase并发查询
{3 y- \, m2 _( F) f# Z% SMergeServer并发查询执行步骤如下:. ?! s: R( b) D. H8 M1 q
1)MergeServer解析SQL语句,根据本地缓存的子表位置信息获取需要请求的2 _& w* u; U6 W% R' T- q; u7 ^8 S
ChunkServer。
$ [" p, y( o# o0 c0 r9 r* c) a2)如果请求只涉及一个子表,将请求发送给该子表所在的ChunkServer执行;如
. k3 j, X0 j0 N; Z( c% w# b果请求涉及多个子表,将请求按照子表拆分为多个子请求,每个子请求对应一个子. \) k" J0 p6 f/ V5 R
表,并发送给该子表所在的ChunkServer并发执行。MergeServer等待每个子请求的返
, W( d) ~ ]; D8 n3 ]/ J回结果。
" b+ Y; T6 u+ N, c1 R6 `' d3)ChunkServer执行子请求,计算子请求的部分结果。SQL执行遵从10.2.4节提
E/ ]+ I2 g: H7 P% v0 [. ~( u到的本地化原则,即能让ChunkServer执行的尽量让ChunkServer执行,包括Filter、$ K0 ~7 A0 y G- D; C
Project、子请求部分结果的GroupBy、OrderBy、聚合运算等。' r% [& n. f6 D" }8 b7 @3 p7 m
4)每个子请求执行完成后,ChunkServer将执行结果回复MergeServer,Merge-5 v" o5 w& M& q% u+ v9 J( o, ^
Server首先将每个子请求的执行结果保存起来。如果某个子请求执行失败,8 j { k$ ~$ S* j
MergeServer会将该子请求发往子表其他副本所在的ChunkServer执行。
7 S% f" E8 p! j% w# l( [ C1 i5)等到所有的子请求执行完成后,MergeServer会对全部数据排序、分组、聚合
" U' x: L5 d5 w3 i, L; i8 s5 z并将最终结果返回给客户。OceanBase还支持批量读取(multiget)操作一次性读取多2 C; D n3 u. {8 d/ ^& R
行数据,且读取的数据可能在不同的ChunkServer上。对于这样的操作,MergeServer
7 |' b- }" [! w3 D( r会按照ChunkServer拆分子请求,每个子请求对应一个ChunkServer。假设客户端请求5
6 j: [6 F1 o" ?, n3 G行数据,其中第1、3、5行在ChunkServer A上,第2、4行在ChunkServer B上。那么,
( }" H. c0 i, Z该请求将被拆分为(1、3、5)和(2、4)两个子请求,分别发往ChunkServer A和) O0 v0 U3 d+ B9 x' E# N
B。
) R3 ^ ~3 G! `9 C4 Q8 {4 Y6 n3 h0 vClass ObMsSqlRequest4 x. {) C3 u: k6 j& x0 k
{
$ n' C+ j& m9 x! f/ x( Y& ]4 wpublic:" p+ ?0 O$ ~# s; N3 _ [
//唤醒正在等待的工作线程0 R! \( A0 ^, r. A3 O9 J' O
int signal(ObMsSqlRpcEvent&event);
$ f; d. |8 p, F' r//等待某个子请求返回
9 s. O& e) m' s6 {! ^/ Uint wait_single_event(int64_t&timeout);2 D0 M1 v' y; F* P" w8 l
//处理某个子请求的返回结果
+ z$ q9 L$ c+ p3 [ V2 N3 l' ]* x; nvirtual int process_result(const int64_t timeout,ObMsSqlRpcEvent*event,bool&& j1 {! L y( T) u* e4 d
finish)=0;
0 ^2 {) c+ E N6 {4 }) t/ B};
5 h2 h& K: G. [ObMsSqlRequest类用于实现并发查询,相应地,ObMsSqlScanRequest以及ObMs-
6 m3 @8 Z$ m* a! ESqlGetRequest类分别用于实现并发扫描和并发批量读取。MergeServer将大请求拆分4 x, J; i$ r( G
为多个子请求,每个子请求对应一个子请求事件(ObMsSqlRpcEvent)。工作线程将
, T/ J. P( |- E) P! m+ A5 Z, C& Y子请求发给相应的ChunkServer后开始等待(调用wait_single_event方法),0 x9 _6 L- R6 q! W
ChunkServer执行完子请求后应答MergeServer。MergeServer收到应答包后回调signal* K3 }! g/ ?. J0 U( [% e) J
函数,唤醒工作线程,工作线程接着调用process_result进行处理。; q$ K) H2 f( P/ G9 J! S
ObMsSqlScanRequest和ObMsSql-GetRequest实现了process_result接口,将每个子请求1 w$ d# R9 s9 c3 G0 p
返回的部分结果保存到结果合并器merge_operator_中。如果所有的子请求全部执行完
0 t5 R: {( U9 E% ^" V成,process_result函数返回的finish变量将置为true,这时,merge_operator_中便保存. V9 l- N* W t5 }$ Y
了并发查询的最终结果。
G8 c- A9 R6 G0 H. n细心的读者可能会发现,OceanBase这种查询模式虽然解决了绝大部分大查询请
3 z# h1 [2 P5 T' T. F- P3 s求的延时问题,但是,如果查询的返回结果特别大,MergeServer将成为性能瓶颈。
, p( c& N; y' o2 f' Q3 H0 S因此,新版的OceanBase系统将对OLAP查询执行逻辑进行升级,使其能够支持数据
4 d$ `) z2 Q7 v6 {( n量更大且更加复杂的SQL查询。- I# P5 x/ }4 i0 s
10.4.2 列式存储) i6 s% n3 [( n" p4 G
列式存储主要的目的有两个:1)大部分OLAP查询只需要读取部分列而不是全" A/ \+ o9 V. g2 d7 E
部列数据,列式存储可以避免读取无用数据;2)将同一列的数据在物理上存放在一
' ~# ?( s9 _7 r% {起,能够极大地提高数据压缩率。
6 A Q( d9 I% q7 j' H列组(Column Group)
. D! C5 S& I) o% pOceanBase通过列组支持行列混合存储,每个列组存储多个经常一起访问的列。
$ y6 `' G" ]! Q2 P如图10-14所示,OceanBase SSTable首先按照列组存储,每个列组内部再按行存2 ~, U6 T$ }' R) n
储。分为几种情况:5 k& J# d! g& m. N# o8 b) M
图 10-14 OceanBase列组设计
$ n& B2 |) c2 r' e●所有列属于同一个列组。数据在SSTable中按行存储,OLTP应用往往配置为这3 I" B( A! ^1 L* ^
种方式。5 f' _+ ^/ R2 @; M# G
●每列对应一个列组。数据在SSTable中按列存储,这种方式在实际应用中比较
1 ?4 `0 t: H+ x. F少见。
8 W6 Q$ l- S) P●每个列组对应一行数据的部分列。数据在SSTable中按行列混合存储,OLAP应: {3 @$ W2 V; |; ?! T5 m3 f
用往往配置为这种方式。
+ J2 e& M( b6 k1 g+ c+ OOceanBase还允许一个列属于多个列组,通过冗余存储这些列,能够提高访问性' S7 K& R: j* z. Y
能。例如,某表格总共包含5列,用户经常一起访问(1,3,5)或者(1,2,3,
2 O8 N$ R/ w1 I) ]* A2 P4)列。如果将(1,3,5)和(1,2,3,4)存储到两个列组中,那么,大部分访
6 B) f4 q3 |) }7 { H7 E问只需要读取一个列组,避免了多个列组的合并操作。
l4 _; W% \+ m) t3 ~列式存储提高了数据压缩比,然而,实践过程中我们发现,由于OceanBase最初. M$ W% |, K% ?, H+ q
的几个版本内存操作实现得不够精细,例如数据结构设计不合理,数据在内存中膨! ` l1 U: H, }8 c
胀很多倍,导致大查询的性能瓶颈集中在CPU,列式存储的优势完全没有发挥出4 X. @, i$ Y h( N: \
来。这就告诉我们,列式存储的前提是设计好内存数据结构,把CPU操作优化好,9 w- @/ C1 v/ l9 I! M, M
否则,后续的工作都是无用功。为了更好地支持OLAP应用,新版的OceanBase将重
% j u9 l& p: ~新设计列式存储引擎。5 \' l) y" j9 T1 y
$ d& u8 j% j8 ]# g; `: A1 u% `; I5 k/ v; P, X5 n' o. c
|
|