|
10.4 OLAP业务支持9 X: h; q1 W/ j% @6 N+ v8 O6 H
OLAP业务的特点是SQL每次执行涉及的数据量很大,需要一次性分析几百万行" g2 R2 s. w1 w5 t1 f, Z
甚至几千万行的数据。另外,SQL执行时往往只读取每行的部分列而不是整行数据。 \& y W+ |: n7 [: r- i+ A6 {
为了支持OLAP计算,OceanBase实现了两个主要功能:并发查询以及列式存
8 ?' ?# [) p$ K. x" @1 X, m4 f储。并行查询功能允许将SQL请求拆分为多个子请求同时发送给多台机器并发执行,
# c9 w1 }) K4 ?/ b7 X7 Y列式存储能够提高压缩率,大大降低SQL执行时读取的数据量。本节首先介绍并发查
- `4 D5 ~( Q; K1 X询功能,接着介绍OceanBase的列式存储引擎。
" ?$ O3 o: n( ]8 G- ~* e10.4.1 并发查询
0 s! H/ s9 u- w/ H+ P如图10-13所示,MergeServer将大请求拆分为多个子请求,同时发往每个子请求
2 t& T3 [6 U' F1 W; k1 D1 n8 Q所在的ChunkServer并发执行,每个ChunkServer执行子请求并将部分结果返回给
* }0 {) K8 F |+ e$ Z6 P9 TMergeServer。MergeServer合并ChunkServer返回的部分结果并将最终结果返回给客户
1 J" _9 w. d4 B. s! M5 ?端。
/ w4 q5 h9 ?' j) e* z( R1 D/ L图 10-13 OceanBase并发查询. P+ X1 S+ r$ R& N; c! D
MergeServer并发查询执行步骤如下:
" W4 L/ U c T4 [1)MergeServer解析SQL语句,根据本地缓存的子表位置信息获取需要请求的* O; e6 m. f6 q; q' h4 [0 o7 G
ChunkServer。
1 W; G5 x& n# ^1 \* n2)如果请求只涉及一个子表,将请求发送给该子表所在的ChunkServer执行;如 A, ?$ D3 p: G+ B- r
果请求涉及多个子表,将请求按照子表拆分为多个子请求,每个子请求对应一个子1 C1 ^: l0 A8 h; B8 R/ \2 D3 b" L$ r
表,并发送给该子表所在的ChunkServer并发执行。MergeServer等待每个子请求的返
- K: t( G- v6 q; c# ^回结果。% q* a0 [6 y$ A- p% G/ ~* R
3)ChunkServer执行子请求,计算子请求的部分结果。SQL执行遵从10.2.4节提
- |# J% w/ Y; V4 V6 R到的本地化原则,即能让ChunkServer执行的尽量让ChunkServer执行,包括Filter、 }4 a1 }% r1 h
Project、子请求部分结果的GroupBy、OrderBy、聚合运算等。
1 c, _9 ^6 R0 o0 D4)每个子请求执行完成后,ChunkServer将执行结果回复MergeServer,Merge-
, g7 d* ~" b) }6 p5 Y3 t& b6 KServer首先将每个子请求的执行结果保存起来。如果某个子请求执行失败,
: g# s& @# e+ d! A. X6 IMergeServer会将该子请求发往子表其他副本所在的ChunkServer执行。; N' X/ ?9 s' W( x
5)等到所有的子请求执行完成后,MergeServer会对全部数据排序、分组、聚合$ t. s* _* v6 p6 c9 G S/ C K+ M
并将最终结果返回给客户。OceanBase还支持批量读取(multiget)操作一次性读取多
8 _7 j/ W9 Y8 N; g2 O行数据,且读取的数据可能在不同的ChunkServer上。对于这样的操作,MergeServer
+ T$ b @0 V. V* d; g4 F会按照ChunkServer拆分子请求,每个子请求对应一个ChunkServer。假设客户端请求5
0 }/ {; t- w% D行数据,其中第1、3、5行在ChunkServer A上,第2、4行在ChunkServer B上。那么,$ u* F, r* ]0 I3 p( i, u
该请求将被拆分为(1、3、5)和(2、4)两个子请求,分别发往ChunkServer A和
3 M N$ s) ?& G+ v; E' [) D' IB。
3 Y U+ _/ n: c; n8 Y4 VClass ObMsSqlRequest
% I' p. a: ?2 {/ G6 @- @: Z( p{+ g) p$ k) {9 g7 N S
public:
: K H1 ~- p" \ f6 d//唤醒正在等待的工作线程2 L$ L1 _- i* w8 e% D# |& l) o
int signal(ObMsSqlRpcEvent&event);- j- O$ |4 t W/ ^# L
//等待某个子请求返回4 |* h/ l+ V' ~# Z
int wait_single_event(int64_t&timeout);" R1 Y+ @" v# d6 V& n
//处理某个子请求的返回结果; w- q/ A* _7 c) A3 z$ }
virtual int process_result(const int64_t timeout,ObMsSqlRpcEvent*event,bool&. f; J3 G0 a' m9 I
finish)=0;
" z7 N' q5 U, p7 v3 @0 N) I};
L6 t7 i: I; ?4 v* [% \7 xObMsSqlRequest类用于实现并发查询,相应地,ObMsSqlScanRequest以及ObMs-
% F' p, V6 W* J: m' N' y" ASqlGetRequest类分别用于实现并发扫描和并发批量读取。MergeServer将大请求拆分
- ]' ]8 |- f9 `- s为多个子请求,每个子请求对应一个子请求事件(ObMsSqlRpcEvent)。工作线程将
5 x: {5 m9 }0 z* N; S* Z1 p3 k子请求发给相应的ChunkServer后开始等待(调用wait_single_event方法),# }0 S" H" f7 r6 `+ n6 W1 m$ l
ChunkServer执行完子请求后应答MergeServer。MergeServer收到应答包后回调signal% V/ I, D7 W7 H( T! P1 C; z5 [
函数,唤醒工作线程,工作线程接着调用process_result进行处理。9 e1 C1 v) m: g, }- ^
ObMsSqlScanRequest和ObMsSql-GetRequest实现了process_result接口,将每个子请求
H4 ^- n6 l. w/ F返回的部分结果保存到结果合并器merge_operator_中。如果所有的子请求全部执行完9 Z8 H5 n- Q" \3 ~. Y. U/ Q) k
成,process_result函数返回的finish变量将置为true,这时,merge_operator_中便保存
" G( v2 r5 i, a$ u. ?$ Z了并发查询的最终结果。
7 N& A9 Z3 u! {5 B细心的读者可能会发现,OceanBase这种查询模式虽然解决了绝大部分大查询请
8 A$ c( ]8 c/ h4 [求的延时问题,但是,如果查询的返回结果特别大,MergeServer将成为性能瓶颈。
f) a" a S) T5 f Y因此,新版的OceanBase系统将对OLAP查询执行逻辑进行升级,使其能够支持数据& @8 J, ?' X: U' T+ P7 g+ d
量更大且更加复杂的SQL查询。
$ [' P8 k+ L! e0 a5 u6 t, i10.4.2 列式存储7 e- Z _" H0 e, w- f
列式存储主要的目的有两个:1)大部分OLAP查询只需要读取部分列而不是全( Z7 u/ [# @ P! t& \
部列数据,列式存储可以避免读取无用数据;2)将同一列的数据在物理上存放在一
! Z) o$ q- E5 u: @9 B4 I. t起,能够极大地提高数据压缩率。* n( U0 k1 r; `, w: `
列组(Column Group)- x' G. j$ ?8 ]5 y3 M4 d( K- L
OceanBase通过列组支持行列混合存储,每个列组存储多个经常一起访问的列。
2 M+ K9 V: Y% M5 E, ^4 @; K如图10-14所示,OceanBase SSTable首先按照列组存储,每个列组内部再按行存, ]( Q5 m. E6 v/ B1 m( G* m
储。分为几种情况:
' K. ?0 u: i4 Y9 u' z图 10-14 OceanBase列组设计
6 X" v& G" Z; o5 T) J5 b3 m●所有列属于同一个列组。数据在SSTable中按行存储,OLTP应用往往配置为这
, w( H$ x! Y1 }2 X种方式。: ^, J; k8 F$ }# ?
●每列对应一个列组。数据在SSTable中按列存储,这种方式在实际应用中比较 y% Y% R# n: J# G6 d1 N8 S) N
少见。! m' i7 m& U! F4 M2 K( R0 J
●每个列组对应一行数据的部分列。数据在SSTable中按行列混合存储,OLAP应
4 z; d& |. E) j* h) j( t. [! T. E用往往配置为这种方式。& E" o! f6 T4 o3 j1 U2 E/ L' k
OceanBase还允许一个列属于多个列组,通过冗余存储这些列,能够提高访问性3 Z0 J+ I! @0 W- o7 ]
能。例如,某表格总共包含5列,用户经常一起访问(1,3,5)或者(1,2,3,* p' Q( Q' I i* z! e
4)列。如果将(1,3,5)和(1,2,3,4)存储到两个列组中,那么,大部分访
! t% O+ x7 n; ^, {问只需要读取一个列组,避免了多个列组的合并操作。, T+ R5 w* W# Q6 X
列式存储提高了数据压缩比,然而,实践过程中我们发现,由于OceanBase最初
5 m; F% a9 }* }" e3 X! u的几个版本内存操作实现得不够精细,例如数据结构设计不合理,数据在内存中膨1 z, }* O$ h; M' j( r. N
胀很多倍,导致大查询的性能瓶颈集中在CPU,列式存储的优势完全没有发挥出
- j7 A2 m) G8 v2 F来。这就告诉我们,列式存储的前提是设计好内存数据结构,把CPU操作优化好,
! O; y" z6 G }( T( O否则,后续的工作都是无用功。为了更好地支持OLAP应用,新版的OceanBase将重$ R, }+ k6 }- w4 ^* N5 E/ B
新设计列式存储引擎。" ?. f' ]1 |3 y" Q7 }- E# `. O
& U7 _) ^! y1 Q! z/ _) y; ~
- b# b# W* z6 M2 H4 }7 V, T) } |
|