|
9.5 消除更新瓶颈
/ c( }! G6 e1 i. s* TUpdateServer单点看起来像是OceanBase架构的软肋,然而,经过OceanBase团队
# r; Q* ?, g# ~; \# p1 i! l持续不断地性能优化以及旁路导入功能的开发,单点的架构在实践过程中经受住了
0 Q& W, `9 u# [8 G. ~9 A' c- ?6 Z" P线上考验。每年淘宝网“双十一”光棍节,OceanBase系统都承载着核心的数据库业1 A4 O$ N9 b% }0 F9 D- J
务,系统访问量出现5到10倍的增长,而OceanBase只需简单地增加机器即可。 s2 ]1 Z. d& T0 @! u8 `* `) ]5 O- m
当然,UpdateServer单点架构并不是不可突破。虽然目前UpdateServer单点架构6 H( n% I$ @" ^6 O$ D
还不是瓶颈,但是OceanBase系统设计时已经留好了“后门”,以后可以通过对系统打7 k" f# |5 M2 c$ F$ {# O
补丁的方式支持UpdateServer线性扩展。当然,这里可能会做一些牺牲,比如短期内
& [6 e2 t. t/ D: i/ @' z暂不支持全局事务,只支持针对单个用户的事务操作。
6 m, e N* [9 y7 {8 |5 n* c本节首先回顾OceanBase已经实现的优化工作,包括读写性能优化以及旁路导入
$ l9 L ?! r4 j6 v1 D* F功能,接着介绍一种数据分区实现UpdateServer线性扩展的方法。
8 x' ~- c) x/ i) U9.5.1 读写优化回顾
$ {& y# Z, W- X" tOceanBase UpdateServer相当于一个内存数据库,其架构设计和“世界上最快的内
) ?4 P! ?0 U: B2 m# |7 `存数据库”MemSQL比较类似,能够支持每秒数百万次单行读写操作,这样的性能对
; j1 n$ D1 `4 a B" u% `于目前关系数据库的应用场景都是足够的。为了达到这样的性能指标,我们已经完
: u8 Y4 ?; D5 }# ^$ ^# c" }3 b成或正在进行的工作如下。; ?4 X; k7 l b0 r1 U" q: I0 B6 }
1.网络框架优化
7 G" X* z% ^4 r) |6 J) k9.2.2 节中提到,如果不经过优化,单机每秒最多能够接收的数据包个数只有' r- _9 s' }7 e0 J8 O( n9 E
10万个左右,而经过优化后的libeasy框架对于千兆网卡每秒最多收包个数超过50
! j6 v) P4 ?: e) }) @# q/ O( g万,对于万兆网卡则超过100万。另外,UpdateServer内部还会在软件层面实现多块8 n9 q) n" `. g6 Z6 [
网卡的负载均衡,从而更好地发挥多网卡的优势。通过网络框架优化,使得单机支
# Y9 D ]8 S8 A& D- j/ E5 |持百万次操作成为可能。5 G) m! V. R) u7 M! j
2.高性能内存数据结构# ^; G# b2 T% N' K/ }/ m% `* C' V
UpdateServer的底层是一颗高性能内存B树。为了最大程度地发挥多核的优势,B0 c8 |9 o3 z$ M# K
树实现时大部分情况下都做到了无锁(lock-free)。测试数据表明,即使在普通的16
5 D$ \3 G3 s) Q4 m' K# X核机器上,OceanBase B树每秒支持的单行修改操作都超过150万次。
* g- f6 R3 q" ]3.写操作日志优化. D; j" d9 b3 X! T: z; @
在软件层面,写操作日志涉及的工作主要有如下几点:4 K! r3 r+ I2 u9 X
1)成组提交。将多个写操作聚合在一起,一次性刷入磁盘中。
* G0 Q. }: M( A6 ?/ _& w( c2)降低日志缓冲区的锁冲突。多个线程同时往日志缓冲区中追加数据,实现时
& B, ? Z. c. [* C4 X, o需要尽可能地减少追加过程的锁冲突。追加过程包含两个阶段:第一个阶段是占
- D6 Y0 w+ g& G f: A; [位,第二个阶段是拷贝数据,相比较而言,拷贝数据比较耗时。实现的关键在于只 g: M( i* k8 E4 [$ `# u! A+ j5 X5 E
对占位操作互斥,而允许多线程并发拷贝数据。例如,有两个线程,线程1和线程. y* U0 j) u. N4 M, E
2,他们分别需要往缓冲区追加大小为100字节和大小为300字节的数据。假设缓冲区6 l# Y7 U$ d) E+ g7 G2 H) w
初始为空,那么,线程1可以首先占住位置0~100,线程2接着占住100~300。最- E8 R2 j+ t5 n' i
后,线程1和线程2并发将数据拷贝到刚才占住的位置。( i8 i4 v# A* o5 ]8 S; h) Z
3)日志文件并发写入。UpdateServer中每个日志缓冲区的大小一般为2MB,如
- W: V) S& [" e' ]4 F1 r" U+ p果写入太快,那么,很快会产生多个日志缓冲区需要刷入磁盘,可以并发地将这些, F9 g0 D4 @2 p; ?+ ~7 C& f
日志缓冲区刷入不同的磁盘。当然,UpdateServer目前并没有实现2和3这两个优化
# D' P1 Q) k+ X3 Y2 b' u! W点。在硬件层面,UpdateServer机器需要配置较好的RAID卡。这些RAID卡自带缓
+ c: l/ d1 ^" H" A* {0 b$ n$ r存,而且容量比较大(例如1GB),从而进一步提升写磁盘性能。
& T% p* ?! j! X( }6 j% I$ G& o4.内存容量优化9 Q" I6 P( n0 d1 B0 h
随着数据不断写入,UpdateServer的内存容量将成为瓶颈。因此,有两种解决思* w" p$ a5 F4 c
路。一种思路是精心设计UpdateServer的内存数据结构,尽可能地节省内存使用;另8 u* f' y# Z# M4 t' h
外一种思路就是将UpdateServer内存中的数据很快地分发出去。; _* D0 g* e3 q: ]
OceanBase实现了这两种思路。首先,UpdateServer会将内存中的数据编码为精2 D o+ \" L& [! W: s L
心设计的格式,从9.3.1节中可以看出,100以内的64位整数在内存中只需要占用两个- z. f1 p) Z t0 y: x$ Y# j
字节。这种编码格式不仅能够有效地减少内存占用,而且往往使得CPU缓存能够容
+ V$ P& w5 R: R/ K纳更多的数据,从而弥补编码和解码操作造成的性能损失。另外,当UpdateServer的
% |( V7 u) i i8 m) w+ M* j内存使用量到达一定大小时,OceanBase会自动触发数据分发操作,将UpdateServer2 Q9 w' |) _ @: I: ~5 e
的数据分发到集群中的ChunkServer中,从而避免UpdateServer的内存容量成为瓶颈。
* h1 a' B G4 l1 o B当然,随着单机内存容量变得越来越大,普通的2U服务器已经具备1TB内存的扩展- `6 L5 g9 O) @+ S5 A- L
能力,数据分发也可能只是一种过渡方案。+ g+ l) G" `8 V- w) t2 E
9.5.2 数据旁路导入 |4 l% G3 u% m
虽然OceanBase内部实现了大量优化技术,但是UpdateServer单点写入对于某些: s( A( u, Q2 @: a/ {. `
OLAP应用仍然可能成为问题。这些应用往往需要定期(例如每天,每个月)导入大) t, J0 h/ Z# I$ T) t* }/ x
批数据,对导入性能要求很高。为此,OceanBase专门开发了旁路导入功能,本节介
% N% p% p5 b9 w1 m绍直接将数据导入到ChunkServer中的方法(即ChunkServer旁路导入)。
8 l) {, r9 e- {3 D6 W- n9 D& iOceanBase的数据按照全局有序排列,因此,旁路导入的第一步就是使用Hadoop
1 b: Q$ \3 u. C% n3 y" a( q- lMapReduce这样的工具将所有的数据排好序,并且划分为一个个有序的范围,每个范. C( [. G0 [$ y6 \
围对应一个SSTable文件。接着,再将SSTable文件并行拷贝到集群中所有的
; V7 C& F5 q3 _6 G mChunkServer中。最后,通知RootServer要求每个ChunkServer并行加载这些SSTable文6 q0 _# i, M* z, W( a- w5 z
件。每个SSTable文件对应ChunkServer的一个子表,ChunkServer加载完本地的SSTable
. Z: T/ b. U1 \% v文件后会向RootServer汇报,RootServer接着将汇报的子表信息更新到RootTable中。
8 v; |" Y$ d5 X' Z/ }例9-7 有4台ChunkServer:A、B、C和D。所有的数据排好序后划分为6个范
" m4 G$ {% `' u5 j/ Z围:r1(0~100]、r2(100~200]、r3(200~300]、r4(300~400]、r5(400~8 Y2 ^2 f" O% B, r! R* t
500]、r6(500~600],对应的SSTable文件分别记为sst1,sst2,……,sst6。假设每4 I- x0 d% p* j u# b
个子表存储两个副本,那么,拷贝完SSTable文件后,可能的分布情况为:4 z- Q& {' J2 P _% H$ H
A:sst1,sst3,sst4
3 o- d/ o7 F- X! P' G6 @, LB:sst2,sst3,sst5 D. Q7 s$ N& {' P! w W
C:sst1,sst4,sst6
/ G: [' w8 D& r& w: V% E- nD:sst2,sst5,sst6
, | |; i" V" ~% a5 L- j) v- L' X接着,每个ChunkServer分别加载本地的SSTable文件,完成后向RootServer汇9 B2 W g: m3 D+ y7 W' G3 Y4 D2 f8 ]
报。RootServer最终会将这些信息记录到RootTable中,如下:
1 z6 N" {: M* f+ _! B. ?r1(0~100]:A、C7 k' c2 ~6 c. ^# Y7 b) z% ?+ ?( ?
r2(100~200]:B、D
' }( G ? a& n- }- Br3(200~300]:A、B
5 w, `# i; f2 }1 `0 Ur4(300~400]:A、C
( `3 U! {( H2 ~" J/ h5 X/ Y4 Sr5(400~500]:B、D
4 R7 F+ ]% W+ B) ?5 c) E0 l, Cr6(500~600]:C、D- a5 G# O3 o0 a7 V! U4 g
如果导入的过程中ChunkServer发生故障,例如拷贝sst1到机器C失败,那么,旁0 N" |% M d! `, a3 J
路导入模块会自动选择另外一台机器拷贝数据。
8 U. \" n1 A& c' O9 o当然,实现旁路导入功能时还需要考虑很多问题。例如,如何支持将数据导入
, p/ o+ j# d* x- H. i到多个数据中心的主备OceanBase集群,这里不会涉及这些细节。
3 o* R3 r- u% s& Z6 Z9.5.3 数据分区
0 h+ d1 B) E+ V* m ]2 F3 k1 `虽然我们坚持认为通过单机性能优化以及硬件性能的提升,UpdateServer单点对7 H* `9 Z5 H6 _+ A: r& ?
于互联网数据库业务不会成为瓶颈。但是,随着OceanBase的应用场景越来越广,例
8 e0 w0 ]% g; L4 i/ M1 m; i. ?如,存储原始日志,我们也可能需要实现更新节点可扩展。本节探讨一种可能的做! ^ S! \# U3 T
法。
4 C. F% M9 W: m( T- N$ K% m3 \OceanBase可以借鉴关系数据库中的分区表的概念,将数据划分为多个分区,允
+ W) Y; @" ?2 f; v5 w# f9 {4 D& k! g许不同的分区被不同的UpdateServer服务。例如,将所有的数据按照哈希的方式划分# a/ g1 k e$ M- {! K/ }
为4096个分区,这样,同一个集群中最多允许4096个写节点。
! O' \& Z+ m9 ~8 y! s4 M8 ]: u如图9-11所示,可以将Users表格和Albums的user_id列按照相同的规则做哈希,: ?4 v8 K! J4 K$ Z# b: N
这样,同一个用户的所有数据属于相同的分区。由于同一个分区只会被同一个: b! Q# ?% d; d& N2 g `) @
UpdateServer服务,因此,保证了同一个用户下读写操作的事务性,另外,不同用户- I3 _8 W0 M: u6 R. d
之间的事务可以通过两阶段提交或者最终一致性的方式实现。这种方式实现起来非! i P* q& ?8 R% D" X* g" a
常简单,而且能够完全兼容SQL语法。( ~+ }0 f9 k1 v" N% D2 S* }
图 9-11 哈希分区SQL语法
" b% A, v5 O4 p+ U( I从图8-1中的整体架构图可以看出,在目前的单更新节点架构中,UpdateServer进6 X. h: _# C5 {& z) l
程总是与ChunkServer进程部署到不同的服务器,而且两种服务器对硬件的要求不
# r( L+ C% ]# U0 y同。如果OceanBase支持哈希分区,还能够将UpdateServer进程和ChunkServer进程部
. x0 L- M, O% t& g署到一起,这样部署起来会更加方便。
+ z0 r& ^. D7 T: v) V; j; x除了哈希分区,OceanBase还能够通过范围分区实现更新节点可扩展,即不同的* G' V9 h" Q* }, J) S7 I& m, e0 X
用户按照user_id有序分布到多台UpdateServer。虽然支持UpdateServer线性可扩展的
2 u0 t- L, M5 u3 d6 S! G: x架构看似“比较优雅”,但是,这件事情并不紧急。这是因为,OLTP类应用对性能的
3 P+ T: v/ v( `/ b需求是有天花板的(例如全世界人口共50亿,即使其中五分之一的人都在某一天产
0 U6 L% ?# Q% q N+ a- W生了一笔交易,这一天的总交易笔数也只有10亿笔),单UpdateServer对于OLTP类数4 D5 u8 c6 m) a: z
据库业务的性能是足够的。* z6 _* l2 ~1 V; Y5 O0 a9 N- @. `* V
* l; q; _/ y/ x3 X
6 o7 J. c9 Q4 e& V( m) X |
|