|
10.4 OLAP业务支持' f7 U. X p5 k' m$ @# Z: v
OLAP业务的特点是SQL每次执行涉及的数据量很大,需要一次性分析几百万行
. A) Q. J2 k8 h1 \3 G" f甚至几千万行的数据。另外,SQL执行时往往只读取每行的部分列而不是整行数据。
( S/ R/ ~0 l t- t, o8 }4 O为了支持OLAP计算,OceanBase实现了两个主要功能:并发查询以及列式存
) R4 F" q. S- h3 O8 F$ ~) L储。并行查询功能允许将SQL请求拆分为多个子请求同时发送给多台机器并发执行,8 m8 L0 I( g9 k, K2 E( L6 F% ^$ s
列式存储能够提高压缩率,大大降低SQL执行时读取的数据量。本节首先介绍并发查
. r9 r" J/ E! ^# ~2 z( u3 x询功能,接着介绍OceanBase的列式存储引擎。+ d) c( N+ h" ^3 R' r2 w0 {/ Q
10.4.1 并发查询
' Y4 Z* }; c$ R如图10-13所示,MergeServer将大请求拆分为多个子请求,同时发往每个子请求
! q, i( m5 C9 I+ c所在的ChunkServer并发执行,每个ChunkServer执行子请求并将部分结果返回给5 A: Q& A; O. K& ?- }2 w2 f7 I
MergeServer。MergeServer合并ChunkServer返回的部分结果并将最终结果返回给客户
' H! x6 ?# u& Y$ q1 @端。
* S% B+ I* R: T( d图 10-13 OceanBase并发查询
z# D' u! P: l" YMergeServer并发查询执行步骤如下:
' k# J" y4 W5 H, a( Y, Y8 S1 P1)MergeServer解析SQL语句,根据本地缓存的子表位置信息获取需要请求的
/ i, C- `" m+ |" c8 C* G: GChunkServer。& p+ z p6 c K+ P6 o
2)如果请求只涉及一个子表,将请求发送给该子表所在的ChunkServer执行;如
* ^: h. {- ]. b果请求涉及多个子表,将请求按照子表拆分为多个子请求,每个子请求对应一个子
7 v* W( H/ c4 C, }/ T: c- D1 ^表,并发送给该子表所在的ChunkServer并发执行。MergeServer等待每个子请求的返2 ]2 }1 X b. x) Y
回结果。
' `) O8 ^4 D- P/ f3)ChunkServer执行子请求,计算子请求的部分结果。SQL执行遵从10.2.4节提
( F. a( y; o$ ~! S到的本地化原则,即能让ChunkServer执行的尽量让ChunkServer执行,包括Filter、
1 l" Y/ K2 U$ k: P; G0 y$ ~# [Project、子请求部分结果的GroupBy、OrderBy、聚合运算等。
1 P" `7 K3 M9 Z5 s4)每个子请求执行完成后,ChunkServer将执行结果回复MergeServer,Merge-' ~( l" X& b* O. Y; S4 K
Server首先将每个子请求的执行结果保存起来。如果某个子请求执行失败,
6 j" J& _% Q* l" ~; L5 e( VMergeServer会将该子请求发往子表其他副本所在的ChunkServer执行。% f$ M% @0 Q" w2 K
5)等到所有的子请求执行完成后,MergeServer会对全部数据排序、分组、聚合- K5 N8 c s+ j1 d& P% F7 ^& b
并将最终结果返回给客户。OceanBase还支持批量读取(multiget)操作一次性读取多5 y/ O1 r' j* r- z
行数据,且读取的数据可能在不同的ChunkServer上。对于这样的操作,MergeServer
3 W# t. S; v" O* p+ J会按照ChunkServer拆分子请求,每个子请求对应一个ChunkServer。假设客户端请求58 h2 v0 J0 }5 g0 g4 W) K
行数据,其中第1、3、5行在ChunkServer A上,第2、4行在ChunkServer B上。那么,& f1 _" u; Q& N( N7 ~. z
该请求将被拆分为(1、3、5)和(2、4)两个子请求,分别发往ChunkServer A和
' p5 b1 _- e& qB。
% C: }' T$ i k8 I0 O) p5 eClass ObMsSqlRequest! e, n2 u9 N0 I
{
4 f3 ?/ E, Y6 E$ _& u- s Ypublic:
5 M% q" T0 L5 P* v' }( }8 ~//唤醒正在等待的工作线程
7 y+ h1 V- L; t2 rint signal(ObMsSqlRpcEvent&event);8 _+ l) r( n' f& b' Q8 q( j# k
//等待某个子请求返回
& @+ Z$ J0 M& a( R3 M: p8 W, `0 M( Uint wait_single_event(int64_t&timeout);4 B& G$ s Y3 A/ R
//处理某个子请求的返回结果* ?7 C; ]. i3 O. h1 L/ H
virtual int process_result(const int64_t timeout,ObMsSqlRpcEvent*event,bool&
. a" A1 n5 c% Tfinish)=0;
& ?9 B3 z5 N/ {8 z- R' }: {' }+ P};1 M! a Z. D+ A2 R6 U( E0 }
ObMsSqlRequest类用于实现并发查询,相应地,ObMsSqlScanRequest以及ObMs-
! F( l4 e3 V& u' C( g+ aSqlGetRequest类分别用于实现并发扫描和并发批量读取。MergeServer将大请求拆分
( k. M" \, S. N4 X为多个子请求,每个子请求对应一个子请求事件(ObMsSqlRpcEvent)。工作线程将
' g! q J3 U; R; |4 c子请求发给相应的ChunkServer后开始等待(调用wait_single_event方法),, N3 U( Y1 {& v+ w0 g/ k
ChunkServer执行完子请求后应答MergeServer。MergeServer收到应答包后回调signal
h( o) x; o( C1 D% U) v函数,唤醒工作线程,工作线程接着调用process_result进行处理。: e; h. v/ E; Q) Y
ObMsSqlScanRequest和ObMsSql-GetRequest实现了process_result接口,将每个子请求$ L( a8 w9 R, A) U
返回的部分结果保存到结果合并器merge_operator_中。如果所有的子请求全部执行完% v, b" [' r" b
成,process_result函数返回的finish变量将置为true,这时,merge_operator_中便保存
9 U( [% Z, q+ t) i; i; S了并发查询的最终结果。
8 k6 B( E8 f0 D& h: w+ z7 D% B" R, ^细心的读者可能会发现,OceanBase这种查询模式虽然解决了绝大部分大查询请$ S# O( V. R1 g
求的延时问题,但是,如果查询的返回结果特别大,MergeServer将成为性能瓶颈。
* I9 o: ^2 d4 T# ^' [因此,新版的OceanBase系统将对OLAP查询执行逻辑进行升级,使其能够支持数据. e' T. q7 b9 w+ ^! L( i% I
量更大且更加复杂的SQL查询。
# e6 {+ ?. P, G: e5 k5 c" i10.4.2 列式存储, M8 u: r# Z8 Y4 z& e( B! k
列式存储主要的目的有两个:1)大部分OLAP查询只需要读取部分列而不是全
& O: F; Q. Y. ^8 f0 P部列数据,列式存储可以避免读取无用数据;2)将同一列的数据在物理上存放在一
/ L+ h. `" o" V& d2 }) o; ?起,能够极大地提高数据压缩率。
7 M( P( D( @$ I" a. }列组(Column Group)$ H; K0 q+ I% d6 u
OceanBase通过列组支持行列混合存储,每个列组存储多个经常一起访问的列。
- f' M/ l* I! N2 L# e如图10-14所示,OceanBase SSTable首先按照列组存储,每个列组内部再按行存
) g& r; n' z" x" s. R储。分为几种情况:& n; ]& K6 h: p2 ^" t8 x; U* w
图 10-14 OceanBase列组设计
6 `# G7 @7 ]+ M$ e4 `5 H●所有列属于同一个列组。数据在SSTable中按行存储,OLTP应用往往配置为这
; T8 t1 }8 l! J种方式。
' O' P" y$ Q$ l t1 R8 E+ \●每列对应一个列组。数据在SSTable中按列存储,这种方式在实际应用中比较
# A# J. p0 u! s# l" f9 ? n A" T少见。
+ u9 } p. n. @9 G/ h●每个列组对应一行数据的部分列。数据在SSTable中按行列混合存储,OLAP应4 U2 ]$ W C/ E3 u+ B
用往往配置为这种方式。0 B) I' \" Q& Y; L7 g7 L
OceanBase还允许一个列属于多个列组,通过冗余存储这些列,能够提高访问性
# J+ H3 r) p& D% p F能。例如,某表格总共包含5列,用户经常一起访问(1,3,5)或者(1,2,3,
& S/ t' T9 Y; M- Z% q$ R2 o4)列。如果将(1,3,5)和(1,2,3,4)存储到两个列组中,那么,大部分访
1 I; L& c) p6 u2 `+ |问只需要读取一个列组,避免了多个列组的合并操作。( K7 y' F( q. R( W' |
列式存储提高了数据压缩比,然而,实践过程中我们发现,由于OceanBase最初4 |( i- `" h( |) u+ B0 W
的几个版本内存操作实现得不够精细,例如数据结构设计不合理,数据在内存中膨 x, Z$ B. p: I1 h8 y
胀很多倍,导致大查询的性能瓶颈集中在CPU,列式存储的优势完全没有发挥出- [& Z3 s3 Z, k( D5 S+ h; ~
来。这就告诉我们,列式存储的前提是设计好内存数据结构,把CPU操作优化好,% k% `" n% R \9 K% O
否则,后续的工作都是无用功。为了更好地支持OLAP应用,新版的OceanBase将重
6 Q0 O5 [; F+ n) l1 e0 o. u" Z新设计列式存储引擎。
1 n& l' w8 D0 C+ r c
$ e" s2 E, |: `, S- H
$ U4 |7 M) h3 s# Z" s3 E6 t' B |
|