|
第11章 质量保证、运维及实践
3 S! m8 i2 D. T. Y* ]$ I0 wOceanBase系统一直在不断演化,需要在代码不断变化的过程中保持系统的稳定
7 V* R: }- P; D& t% [4 j; `性。因此,合理的质量保证体系关乎系统的成败。为了保证系统质量,OceanBase做
: D* T1 Z5 b/ t5 h了大量工作,在RD(指开发工程师)开发、QA(指测试工程师)测试、上线试运行
; u# h4 H# u; o3 ?; z& [2 Y各个阶段对系统质量把关。
1 r; }5 t* N9 {) v. X& E; ^系统的性能和稳定性得到保障后,还需要具备良好的可运维性。OceanBase借鉴
0 z* w% F x2 \; j了Oracle数据库中的“系统表”机制,将表格Schema、监控数据、系统内部状态等信息7 }9 m$ B. ^+ v" l+ D7 a- F
保存到内部系统表中,从而能够基于系统表构建监控界面、运维管理界面以及运维' W( f Q& K# t/ Y
工具。# F3 ~* Q+ X: u7 W( g$ ?' ]) U" y
最后,系统只有通过上线使用才能证明自己并发现设计和实现上的不足。本章
8 p5 r. p4 }; O首先介绍OceanBase的质量保证体系和运维体系,接着以收藏夹、天猫评价和直通车
% f' I; }0 ~# L6 c- H# L报表为例介绍OceanBase系统的使用情况。最后,笔者总结了实践过程中的经验教
+ j" N" b6 `. y8 }- {$ d8 H训。8 b; Q4 M9 C# @. L5 b2 P
11.1 质量保证
' z/ D+ M/ a* x" i4 M互联网基础产品的质量保证不只是QA的事情,从RD设计、编码开始,系统提
/ j8 h! G( w, t. @; A测,直至最后上线,每个环节都需要重视质量保证工作。OceanBase的质量保证体系
* Q4 f* y2 }. E. N& r9 a. k X2 F如图11-1所示。
. h8 r( _/ C- O图 11-1 OceanBase质量保证体系
/ Z0 `( @* N& Q一个新版本需要经过开发=>单元测试&快速测试=>RD(开发工程师)压力测
. M2 s: P4 F% W/ u e K试=>系统提测=>QA(测试工程师)接口、功能、容灾、压力测试=>兼容性测试=2 X" R' G, k' M8 t- \% K& b+ R4 N
>Benchmark测试才能最终发布,其中,RD压力测试和兼容性测试是可选的。发布的& I0 w. L& S, Z$ R* N8 `9 ^6 N
新版本还需要经过业务压力测试或者线上流量回放才能上线试运行,试运行一段时
9 W7 q8 w9 I% O4 b/ ?0 N0 h: V间后没有发现问题才能最终上线。8 _. _$ U) h4 e* i r: Z
11.1.1 RD开发
0 G# @7 U5 f& Y# m: x% r% X* `1 Z系统Bug暴露越早修复代价越低,开发工程师是产生Bug的源头,开发阶段主要
8 k0 [; m1 K# N8 {' Y2 ~! H9 z通过编码规范、代码审核(Code Review)、单元测试保证代码质量。另外,系统提* {& ?. k1 p) \- D+ @3 D
测前RD需要主动执行快速测试(quicktest),从而避免返工。
: q" B8 q/ p! h+ L* C9 k$ V8 z1.编码规范
- q! l H5 u% k6 s" ~编码规范规定了函数、变量、类型的命名规则,保证统一的注释和排版风格。
1 W, S( O- J6 L" C( J, v除此之外,为了避免C/C++服务器端编程常见缺陷,OceanBase编码规范还制定了一! s; E( t0 \0 z' H B2 q
些规则,如下所示:
; _; a+ J, g. i4 ~5 ^ u$ l1)一个函数只能有一个入口和一个出口。不允许在函数中使用goto语句,也不
4 z% F/ G- `* o% _+ E- T允许函数中途return返回。* h* ?1 k' m2 d
如图11-2所示,左边的代码中途调用了return,在OceanBase编码规范中是不允许
8 V h0 _. ~- G& P的,可以修改为右边的方式。这条规定有一定的争议,很多优秀的开源项目都允许
2 A: J! K% r) p+ H: e* o$ f函数中途return。之所以这么规定,是为了确保函数执行过程中申请的资源被释放
; |1 }! r4 S; u ^8 R5 y掉。对于分布式存储系统,代码稳定运行的重要性远远高于代码写得更漂亮。
) A6 |" |) H7 {2 [) m0 W' ^2 Y% P# R图 11-2 单入口单出口; S9 u4 F8 ^- o3 ]/ I7 X* E. P
2)禁止在函数中抛异常,谨慎使用STL、boost。C/C++编程的麻烦之处在于资
: O0 t2 Q7 Z4 G' N9 n& ]/ W3 L源管理,尤其是内存管理。STL、boost库接口容易使用,能够提高编码效率,但是. |" ]- n) @' ?9 T: d
内存管理混乱,不易调试,且大多数开发工程师不了解其内部实现,不适用于高性
- g; R' }3 k/ t# z. @( I能服务器的开发。& A2 s2 Q/ D: X; K
3)资源管理做到可控。所有的内存申请操作都需要经过OceanBase全局内存管
* a* s6 W1 K) i1 r; h% s j理器,不允许直接在代码中调用new/malloc申请内存。另外,系统初始化时启动所有% L4 z0 a* a# k8 o! y" C
线程,执行过程中不允许动态启动额外的线程。
, d& F. G- R! t" S" A4)每个可能失败的函数都必须返回错误码,0表示成功,其他值表示出错。调2 v8 S; U& H/ A' J! T% N* H+ k
用者需要仔细、全面地处理调用函数返回的每个错误码。+ }1 T/ X0 i7 y" K' Q; c- L! I+ ]" P7 q$ k
5)所有的指针使用前都必须判空,不允许使用assert [1] 语句替代错误检查。这条
; v3 R- M: x) H5 i7 o) Z: V* M规定是为了保证程序执行过程中出现异常情况时能够打印错误日志而不是core
5 |* A: ]! S# D* xdump。9 ?$ Z9 |, u: Y) k3 n8 \7 X
6)不允许使用strcpy/strcat/strcpy/sprintf等字符串操作函数,而改用对应的限制
& Z7 o# ]2 D: i# T6 j# J- {/ n- K字符串长度函数:strncpy/strncat/strncpy/snprintf,从而防止字符串操作越界。, F$ |1 W+ r! M1 c1 H6 y$ M0 Q
7)严格要求自己,编译时要开启GCC所有报警开关,例如:-Wall-Werror-' [) k+ ]/ \: z- C
Wextra-Wunused-parameter-Wformat-Wconversion-Wdeprecated。代码提交前需要确保0 b7 e: |1 s b; A$ J+ R; ~
解决所有的报警。
) `- n# {! }* L2.代码审核
! ^: J/ C1 i$ w, A( K, \$ Z0 {OceanBase开发时要求所有代码提交前至少由一人审核,对于关键代码改动,例
- d; w( g" M! A' y如,紧急修复线上Bug,需要架构师和各个小组的技术负责人参与。& `7 S( Q$ j4 p3 a5 j- A
代码审核工作主要包含两个部分:编码风格审核,比如是否符合编码规范,接7 u- d: r; o" F8 e, P; T# z% x( T+ H
口设计是否合理,以及实现逻辑审核。其中,实现逻辑审核是难点,要求理解每个9 N. y% j4 k h( v* O/ u1 P' Y) ]
代码实现细节,并给出建设性意见。每个刚刚加入团队的新人都会分配一个师兄,* m6 p: a& ^1 ]: W* ]' b
师兄的其中一项职责就是审核新人的代码,与新人一起共同对代码质量负责。5 t7 m$ m$ M/ M9 n/ _# K
OceanBase采用开源的ReviewBoard(http://www.reviewboard.org/)作为代码审核
2 H' T! r( w) H- S+ N7 E系统,如图11-3所示。; _ B( J4 _" _
图 11-3 OceanBase ReviewBoard$ Z7 t4 Y2 B/ ~9 e' y
3.单元测试
+ x. f) j! Y# `6 J" P! K' POceanBase采用google test以及google mock进行单元测试。单元测试的关键点在于
: O6 _& } I2 {1 c. [% O2 F" `9 W系统接口设计时考虑可测性,并提高每个开发人员的单元测试意识。4 u) _4 d7 E& ?4 Z" _8 R( \
OceanBase单元测试已接入一淘网内部开发的Toast平台,每天晚上会自动回归所
) |/ I' Y" c( B5 u% A有的单元测试用例。Toast平台说明文档见:
# c' _! I( x/ B5 @9 Xhttp://testing.etao.com/book/export/html/285。0 f* Z, X% X1 S- x
4.快速测试(quicktest)9 U) S! X2 m4 K: J0 D
快速测试选取所有测试用例的一个子集,这个子集中的每个用例执行都很快,
* I# Y! q: n; [8 G. G, C从而做到快速回归。快速测试部署成定时任务,每天自动回归,RD提交某个功能的
0 y2 _) j( L" r; [. F. o' O5 A/ H4 y代码之前也会主动运行快速测试,从而使得主干代码保持基本稳定。
1 T5 h8 d4 Y* x# S" e: h1 O+ A! q. [5.RD压力测试- F$ x/ M0 G$ Y+ P2 A B1 s
(1)分布式存储引擎压力测试1 e' F4 x0 Y& ^3 c& d
分布式存储引擎压力测试工具包含两个:syschecker以及mixed_test。
9 ?5 j8 s2 I/ N1 ?* l在syschecker工具中,多个客户端并发读写一行或者多行数据,并对读取到的每
/ \" z8 b8 p' E" u& a行数据进行校验。对于每行数据,其中的每一列都对应一个辅助列,二者数据之和; D1 \; A5 E/ ^% ]5 S$ K
为0。假设某列数据出错,syschecker能够很快检测出来。
& J+ B, ?3 p6 Psyschecker写入速度很快,能够发现分布式存储引擎中的大部分问题,然而,
% \; m5 N. e. l. ~. \! i3 Fsyschecker只校验单行数据,不校验多行数据之间的关系。因此,syschecker无法发现1 R% f, T4 z) k$ `/ l( b% `
某行数据全部丢失的情况。mixed_test正是用来解决这个问题的,它不仅对每行数据0 N- b# @5 N# O
进行校验,还校验多行数据之间的关系,能够检测出某行数据全部丢失的情况。当
. L! F! \' k7 m- Z5 v5 V* K5 a" {' y然,mixed_test写入速度较慢,syschecker和mixed_test两个工具总是配合使用,各有优9 K' k n" P9 g }, R
势。
5 s3 e3 M0 F7 J4 W- [3 U(2)数据库功能压力测试
! t1 v2 B) j. X数据库功能压力测试工具包含两个:sqltest以及bigquery。
! @1 [4 ?: \) [( X/ q3 a1 M# q●sqltest工具测试时将指定一些SQL语句,sqltest工具会将这些语句分别发送给; m' j7 Y5 b8 b6 S0 b' T
MySQL以及OceanBase数据库。如果二者的执行结果相同,则认为sqltest测试通过;. r/ t( m: y% i6 e( F
否则,测试失败。
( V" q. D ]6 E0 R: c. p●bigquery工具是sqltest工具的补充,专门用于测试OLAP并发查询功能。
B6 c: H. @/ @* Obigquery中每个查询涉及的数据往往跨多个子表,能够触发OceanBase的并发查询功/ u1 N( x, z2 H# P/ Y) G! J
能。当然,bigquery灵活性不够,只能执行特定的SQL语句,而sqltest能够执行
4 c5 i5 A( N, I: ~OceanBase支持的所有SQL语句。因此,bigquery和sqltest两个工具也是配合使用,各
3 B3 Q; E/ {& W8 R9 l" ]* y有优势。) ]5 i4 T3 j( n; ^6 O( b8 U
OceanBase早期测试资源严重不足,因此,要求开发在提测前必须运行一遍压力$ t# k- ]% z; S! w
测试。然而,这些压力测试工具的维护非常耗时。2013年开始,RD压力测试工具逐
. V* T. @; X+ _& S8 @# e: u步废弃,其中的测试用例逐步融合到QA压力测试工具中。
& ^' i# ]; T( Y2 }[1]C语言中的宏定义,如果传入条件不成立,程序直接core dump退出。
" W! W! j+ Q5 A( W11.1.2 QA测试* \7 S$ j- O+ a
RD提测新版本后,进入QA测试阶段。QA首先快速执行一次快速测试,如果快5 @8 G. J3 J7 P8 M! z
速测试失败,则通知RD修复问题后重新提测。否则,进入后续的接口、功能、容! K) L8 }0 Y4 p% z% a2 S% U
灾、压力测试。如果系统设计变化较大,还需要执行专门的兼容性测试。需要注意+ h5 X0 V. s, t% V
的是,OceanBase开发模式逐步走向敏捷化,QA往往在正式提测前就已经完成了一+ \% F7 b6 y4 Q& W" ~
部分测试用例的执行。! z! y; |& |7 x
1.接口、功能、容灾测试7 q0 }5 l- Z* |7 n! e
(1)接口测试7 l# i0 Q9 E+ l; R1 ~# \- s
使用者通过JDBC/MySQL C客户端库访问OceanBase。由于OceanBase访问协议兼3 ]9 p3 V3 a5 G* [% X: S$ e5 [) M
容MySQL协议,因此,直接将MySQL数据库的官方测试工具和部分官方测试用例移
+ g: R; H% Q$ }; D- u; F% M植过来测试OceanBase。
1 k# }0 \# w9 r(2)功能、容灾测试
2 p# D# I) ^4 N2 vOceanBase包含很多功能,例如每日合并、负载均衡、新机器上线、主备同步、2 V, K/ {' {1 C
主UpdateServer选举等。功能测试会构造场景触发这些功能,并引入各种异常,如阻
3 D; ^' Q: q9 O$ e5 Y l塞网络、杀死服务器进程、模拟磁盘故障等来验证系统的容灾能力。. n a r' \9 ~" s; w5 G
OceanBase的接口、功能、容灾用例都实现了自动化和文本化。自动化的好处在8 t, B7 f1 W# [. v9 F
于无须人工介入,文本化的好处在于方便添加和维护测试用例,从而适应系统快速
/ D/ k0 M- G. L开发的需要。下面是UpdateServer其中一个主备切换测试用例:( e& K: G$ \$ v+ C
#部署一个OceanBase集群' }8 E {- K: o2 @0 T; O! }
deploy ob1=OBI(cluster=1211);5 x, r2 u6 k2 K+ |1 s$ P
deploy ob1.reboot;
# ]- T% d7 p( d6 d+ x( asleep 10;: {# q/ M; b6 ]- T4 ?" y; ? @2 W
#连接到其中一台MergeServer(ms0)
5 \* ~( i. T$ d8 |' Edeploy ob1.connect conn1 ms0 admin admin test;
/ R: e5 ]& j0 J6 R4 Uconnection conn1;
0 f; Y& G! X5 P# q#执行DDL(建表)以及DML语句(insert/update/delete)5 ~* Z# O+ O/ J
create table t1(pk int primary key,c1 varchar);* d5 B* B# t2 ^; L2 y; }
insert into t1 values(2,'2_abc'),(3,'3_abc'),(4,'4_abc'),(5,'5_abc');
, ]) Y$ ]* V6 v- kupdate t1 set c1='5_UPDATE'where pk=5;5 Q' L5 m/ g: G5 b" U( ~+ a' E4 Z
delete from t1 where pk=2;% A- {" @8 F7 R" L0 v$ ?. o, v
#读取表格内容
! u# a$ d+ g4 V2 U) |3 O6 Z0 z6 @select*from t1;
* p9 w) p u3 q3 v! y- X ]#获取原有的主UpdateServer的地址并记录为$a
+ ^2 D ~9 h s6 Y Xlet$a=deploy_get_value(ob1.get_master_ups);2 |( S! k' U) }8 { v
#关闭主UpdateServer并等待30秒& P. x9 z( x: P8 C
deploy ob1.stop_master_ups;6 E1 r" r% {: }3 T2 G: Z' P
sleep 30;
2 U' q9 U8 P% a8 z F* L#获取新的主UpdateServer的地址记录为$b. ]: ^ z. D1 C/ d
let$b=deploy_get_value(ob1.get_master_ups);/ `( t, p# }, i7 p+ G
#读取表格内容
' h/ Q! L! f4 E* l# O: l" O8 {select*from t1;4 `, ]- J9 c9 C: X5 T( C" ^
#比较$a和$b,看二者是否不同7 K; u- A, D9 u* Z* N7 @$ k& e
if($a!=$b)
0 b8 p+ [% N4 ?# _ c5 q{8 a$ q9 X, ?' D. X$ e+ H
--echo success# j$ _+ ~2 t+ n: s/ r$ q0 C
}
" T; F; L* T( L) U3 ]9 [deploy ob1.stop;4 p6 Q# {0 `) A$ w b3 C0 P
执行步骤如下:9 M7 U$ U! ?1 r' T+ X* Q% w7 Q, `
1)部署一个OceanBase集群,集群名称为ob1。
+ X; l& x9 w3 Z! W6 ]1 Z! H! i2)连接到其中一台MergeServer(ms0)。
+ f$ p2 ]9 g2 a a# \: J4 M3)执行DDL(建表)以及DML语句(insert/update/delete)。create_table语句创
) s" C; ^/ p( y9 O1 l建了一个包含两列的表格t1,其中,pk列为主键。DML语句对表格t1执行增、删、改
- P$ u; u) Z) P操作。& ^; G) `5 j' c
4)读取表格t1中的内容;获取原有的主UpdateServer的地址并记录为$a。( q- `% F0 i4 M: Q; C' P. [
5)关闭主UpdateServer并等待30秒。正常情况下,OceanBase将自动发生主备切
1 d9 g' \$ n) J8 [5 i) @换,主UpdateServer的地址会发生变化,且仍然能够正常读取表格t1中的内容。5 @* v. R& c+ j% O/ o0 Y1 ~, Z* A
6)再次读取表格t1中的内容;获取新的主UpdateServer的地址并记录为$b。
: Q! J; ]5 Q1 K8 i9 u R7)比较主备切换前后的主UpdateServer地址,看二者是否不同。! u P5 _0 G# D5 F D; `
每个测试用例对应一个预期结果文件,OceanBase的测试框架将执行该测试用例
6 ?& {% |% U9 y* G" g并生成一个运行结果文件。如果运行结果文件和预期结果文件完全相同,则测试用! I% @( ~0 O/ G! K5 ^, z: ^9 \8 C# ~
例通过;否则,测试用例不通过,测试框架将输出预期结果文件和运行结果文件的8 r+ g3 ?! B$ P9 G
差异。# S6 B$ D9 _) U' }; a9 k% V
2.压力测试3 S6 \8 c/ f) A1 ] h7 N
分布式存储系统中很多问题只有在高并发或者大数据量的情况下才会出现。2 P ~( Z' }# {7 m( C
OceanBase压力测试的原理是持续不断地写入数据,并在这个过程使用大量客户端读
, S3 G& g) `" ]+ a3 u; P/ l9 B0 s取并验证数据。假设线上的数据量为2TB,查询次数为每秒10000次,那么,只要测
* o0 c6 ]( ?' R4 O3 n试环境的数据量为4~10TB(线上数据量的2~5倍),测试环境的读压力为每秒0 p+ k9 ?( w4 I& `
20000~50000次(线上读压力的2~5倍),那么,基本可以认为系统是稳定的。
. p7 Y: T; V# C* c lQA压力测试工具融合了11.1.1节中提到的RD压力测试工具的测试用例,且支持
2 e: U5 m* v! P5 B+ R/ D自动持续回归和测试用例文本化,从而降低维护成本。另外,QA压力测试工具还支
* j$ }# x% l/ n* J. T持容灾操作,例如杀死某个服务器进程,发起主备切换,等等。3 h" b, D% V' Y4 q5 h; q" `, j
3.Benchmark测试6 J8 K$ t" s' d9 Z2 t8 s
Benchmark测试是具有代表性的SQL语句,例如读写一行数据,读写一批数据但1 y( f; V N% R
不排序,读写一批数据且排序,计算count/sum/distinct,等值连接,等等。测试团队/ `2 F4 D) Y& z
定期发布Benchmark测试报告,如果发现系统性能相比前一次有明显提升或者下降,6 o( `0 ^- n9 D( Z! u* \/ r- a
需要开发团队说明其中的原因。另外,每个版本正式发布时需要提供一份Benchmark, U+ F. x/ @2 i% u9 s; d, R
测试报告。
% X( y- f' C' N( y4.兼容性测试
8 @* I& P7 x4 N6 d' HOceanBase开发过程中保证兼容应用以前使用的接口,如果系统做了较大的设计- ~* m0 R/ p$ ^5 K; m
重构,需要执行兼容性测试确保使用过的接口不会出现问题。
3 Y- r* \: P6 u4 H' J9 |另外,OceanBase支持主备两个集群,系统升级时往往先升级备集群,如果没有
% ~* L8 I* u2 x% x+ o1 m F发现问题,才会升级主集群。升级过程中两个集群会部署不同版本的程序,兼容性: a" R/ K0 M; `, v/ \
测试需要确保这种部署方式能够正常工作,且新版本出现问题时,需要能够回滚到, b) [: _- D. j1 \
老版本。2 B& Z* H2 i+ |1 V4 L% ^! b
11.1.3 试运行
0 v' q$ K) O; m( K+ N互联网产品开发的理念是“小步快跑,快速试错”,QA测试阶段不可能发现所有" j# L$ [1 }: C7 R3 h# g
的Bug,很多问题需要等到系统上线试运行阶段才能发现。试运行部分有如下几步。
0 M& @5 v/ ]- n1.业务压力测试1 u, {0 c6 X" |$ w: u! S
业务第一次上线时,无法执行线上流量回放测试,此时,应用方往往会和) d c0 F& D' ?: X
OceanBase团队一起对业务进行一次压力测试。OceanBase测试人员首先将应用初始+ L$ [( Q/ m, e- y H `- q
数据导入到一个模拟环境,应用方会选取几个经常使用的业务场景,对OceanBase系7 }/ K% X/ s; V/ d1 T f. j
统进行压力测试。
1 @; V' b1 I$ K- |2.线上流量回放
& I. T) s5 ^; S3 e0 P* ?系统试运行之前,往往需要构造环境模拟线上请求。OceanBase测试人员会将线. _6 H7 P( f: _2 A3 G
上环境的数据导入到一个模拟环境,并在模拟环境回放线上的读写请求。线上流量, Q" _& f; m+ a3 M- t
回放工具支持回放任意倍数的线上请求,从而发现各种问题,包括接口使用、性: P3 t& x3 S6 Z2 ?' Q/ G7 c
能、负载均衡等方面的问题。线上流量回放是OceanBase上线试运行的最后一道防6 f9 S {" H3 d! u5 R! n" d! p i9 O5 ^
线。, D/ B' m8 i9 ]" g3 q3 `. c
3.灰度上线( I2 L& `: a i0 Y
系统通过了所有的测试环节便可以上线试运行了,这个过程又称为灰度上线。
. o1 [' i1 x) X3 l如果应用从别的数据库迁移到OceanBase,那么,灰度上线阶段会同时写两份数
3 x' O D" e( ~据,一份写到之前的系统,一份写到OceanBase,这个阶段应用方还会对两个系统的
7 `5 N5 a% z- N数据进行数据比对。如果没有问题,则将读流量逐步切入到OceanBase。( D" k4 W2 k$ A1 p' ]) v& T
如果应用从OceanBase老版本升级到新版本,那么,灰度上线阶段会首先升级备4 U( I( G& `3 X& p$ {, P7 T
集群到新版本,并将读流量逐步切入。如果没有发现问题,则将备集群切换为主集
0 u( F% X. G) T1 x* e群,由新版本提供读写服务,最后再升级原先的主集群到新版本。备集群切换为主
1 u) c4 N0 J O, Z+ b, Y. g9 c集群的风险较高,如果发现问题,需要立即切换回老版本。整个升级过程需要通过
- e$ x/ @. V. w8 }之前提到的兼容性测试模拟
* z' Q/ _9 T+ _/ O! x# [( ?8 h) C4 `4 Y. b9 C8 H' [) D6 K
; G/ u, @: g- X |
|