介绍
本文主要分为四个章节,背景、技术细节、测试以及总结。第一章背景,讲述为什么需要选择新的数据库。第二章AnalyticDB剖析,讲述选型的数据库以及相关的技术细节。第三章测试,讲述所选择对应数据库的测试结果,第四章节对前面的技术细节、测试及成本进行总结。
第一章 背景
对于一个广告投放平台,所涉及的数据库读写场景。复杂分析的查询所占比例比较大。某广告平台现有的数据报表包含帐号、广告、计划、平台和代理商等维度。当新商户的入住,会带来50+左右的帐号,每个帐号会涉及到至少一个代理商户甚至更多。平均每天活跃帐号60+,每天需要新上广告平均20+条广告。数据目前统计的时间为小时维度,每天大约新增广告数据28800多条记录。此外,为了更少的修改业务代码,节省开发上的时间。在选择上也偏向选择兼容MySQL协议的数据库。
在2013年,Google广告部门发表一篇关于F1的论文。F1是一款OLTP和OLAP混合数据库,它的诞生是为了解决大规模广告数据查询问题。基于以上背景,分析型数据库比较适合此类场景。在选择上阿里云的AnalyticDB比较贴合我们的需要。接下来根据阿里云公开发表的论文AnalyticDB: Real-time OLAP Database System at Alibaba Cloud 剖析一些技术细节。
第二章 AnalyticDB剖析
AnalyticDB (简称ADB)诞生于2012年,2016年开始商业化发布2.0版本,并对外提供服务。2018年发布3.0版本(也是目前的主版本)。它支持100PB级数据量、实时读写查询、读写数据一致性、数据库自身包含高可用、兼容SQL2003。在定位上,它是一款OLAP数据库。
传统的数据分析数据库都无法同时满足离线计算和实时计算。面对实时计算的场景所需要的成本并不低。下图是传统的大数据计算模型。数据经过提取、转换、加载至指定的特征数据库。假设这一套服务需要引入至少两套新的基础设施以及数据清洗服务。
图1,ETL处理模式
“架构简单”——使用现有的产品以及少量的配置就能达到我们期望的效果是最好的。
AnalyticDB采用计算和存储分离的架构,同时为了兼并读写性能。对计算层内部采用读写分离架构。如图2:
图2,架构图
整个系统在架构中分为协调者、读节点、写节点、底层文件储存系统四个角色。读写请求首先会到达协调者Coordinator。协调者区分当前请求是读还是写,然后发送到对应的处理节点。读写节点会通过RPC的方式进行增量的数据同步,以应对实时查询。盘古和伏羲是阿里云底层的文件存储管理系统和计算资源(CPU和内存)管理系统。因为是多租户的系统,读写节点的调度和高可用管理是由Gallardo组件管理。
目前的数据库系统架构要想提高SQL的查询效率,改进的方式是优化数据查找的方式、在优化器层面能选择有效的索引,在执行器层能把条件拆为速度快的查询树,尽量少的从磁盘获取数据。如果全部能够从内存中获取是最好不过,ADB的优化方向也是如此。
读写分离的架构可以当读或者写的压力增加时,通过加节点就能缓解查询压力,让整个集群的性能提高以降低压力。广告数据的查询大部分场景都是几个列的数据,涉及多个数据表。传统的数据库存储方式都是按行存储数据,行的存储方式非常有利于数据更新,而相比较数据查询就比较弱。在查询时需要把整行的数据从磁盘上读取出来再在内存中提取需要的字段。这部分对于分析查询的场景是一种资源浪费。列式存储的方式可以在查询上只筛选对应的列字段。ADB是行列混合存储的方式,为了实现这种方式。在数据存储上引入了索引文件来存储行列之间的关系。如图3
图3,数据结构
在底层数据存储是按列存储,然后通过索引文件把相关的列串成行。不过这部分会导致存储上的增加,但现在的硬盘价格越来越低,内存价格也在下降。通过空间换计算的方式也是一种可以使用的手段。从上图中可以看到元信息文件中包含了常见的统计值:最大值、最小值、去重复数等。这些信息的收集是为了做相对应的计算时可以直接在元信息中读取,以减少从磁盘查找数据的时间。
ADB对于复杂的数据类型使用“打平”的处理方式,例如a.b.c
来表示KEY。目的也是为了更好的利用已优化的方法来处理。行列混合存储的方式才用数据结构的方式处理外,在数据维护上也是一个话题。如何让数据的写入快?就是不管存放数据位置,顺序的写入数据到磁盘,俗称“顺序写”。ADB写入一条数据需要经过以下步骤:
-
从SQL中解析多列数据
-
追加数据到增量数据日志并且返回行ID
-
在删除bit中标记删除值为0(1为删除态)
-
创建删除位快照
-
把删除快照和版本放入映射map(索引)中
如果是删除数据,只需要根据索引查找对应记录的行ID,然后修改bit位上的值为1。重新创建快照返回新的行ID即可。这种方式对于频繁更新的场景会容易导致写放大问题,不过这部分可以把GC在高峰期调整的快点。
数据组织方式是优化方式之一。对于数据查询来说,索引的重要性不言而喻。在以往的数据库中,新索引维护需要人工介入,判断是否需要创建索引。在现实的环境中也遇到因为索引问题而导致系统的CPU超过系统阈值。ADB的处理方式是为所有列自动加上索引,其中为了解决索引构建引发写入性能低的问题,采用异步构建索引的方式。系统内部会把整个创建索引的任务演变为MapReduce的模式。
数据查询的执行计划要选择正确的索引,需要统计信息越准越好。在传统的MySQL数据库中,它的统计信息(innodb_table_stats
)是定时和定量统计,当遇到更新和写入比较频繁的场景时。统计信息的更新往往不是特别及时。ADB 为了解决这个问题,采用基数采样和先前采样数据结合的方式。基数采样的意思是在查询优化阶段,发送一个采样请求到存储层来生成新的统计信息。
读写分离会涉及到一个读写数据一致性的问题。假设,写节点收到一个写入请求后,立即来了一条读请求。ADB使用增量数据加基线数据的方式。当用户写入数据到写节点,先写日志然后返回成功。此时客户端立即发送一条数据查询的语句查询被分派到读节点。读节点会从写节点拉取增量数据(增量数据也是存在索引的,是排序索引)和盘古系统拉取基线数据,在比对数据版本后合并数据并返回。如图4和图5
图4,实时读工作流
图5,增量数据和基线数据合并过程
通过增量数据和基线数据来保证实时读取。整体来看ADB的性能是通过在查询的各个阶段进行优化,利用原有的存储系统API的优势和资源调度,利用空间换取时间来提高查询性能。
为了解决数据的存储问题,ADB会自动进行分区。用户在创建表时指定分区的字段即可。在数据库内部按照三副本方式存放,多副本的方式也是为了容错。如图6
图6,数据分区
第三章 测试
测试主要分为两部分:第一,选择慢查询进行比较查询差异,第二,通过运行业务代码的方式测试兼容性。
数据同步采用全量+增量的数据导入方式,通过DTS服务导入到ADB中。在导入的过程中把一些基础表设置为维度表(维度表会在每个读节点存储)架构如图7
图7,数据同步架构
把MySQL5.6中的慢查询SQL放入ADB查询,查询时间可以保证在1s内返回查询结果。
SQL兼容性测试方案:
- Fork API代码,保持与上游仓库的代码同步
- 前端代码共享
- 数据库连接指向ADB地址。
- 因为拥有Kubernetes环境,所以整个测试项目只需要新创建API SVC,Page SVC
对数据报表进行常规操作,各个维度、指标、时刻进行筛选排序以测试兼容性。结果100%兼容。
查询压测
1000次查询,压测时长100秒,5个pod . 查询样本库10条复杂报表SQL,覆盖全维度、全指标。测试结果如图
通过上面的图标可以看到,当查询量比较大时,查询的响应时间会随之受到影响,响应时间还是在可接受的范围内。随着时间的推移,相同的查询在短时间内的查询响应时间会降低,这是因为ADB对查询结果有缓存,相同的查询不再重新计算。
在测试过程中发现一些问题,例如DTS无法同步DDL语句(目前这个问题已经修复)、存储放大(大部分是日志,官方给出的解答是以后不会计算到用户存储空间。可通过工单可以调整日志存储时间)、监控图表的指标衡量是取平均值。
对于存储放大主要是影响存储的估算问题:
实际存储=数据+索引(数据x0.66)。
注:ADB会压缩数据,所以实际要少很多。目前MySQL5.6 中6GB的数据到ADB中还是6GB左右。
监控指标取平均值问题,阿里云会在后续提供单个节点的监控。目前会影响到判断扩容和监控告警的配置。不过通过降低监控告警的阈值也算可用。
部署上线方案
数据通过DTS同步到ADB,API代码中新建一个ADB配置,报表所有读查询使用ADB进行查询。数据写入和更新还是写入MySQL,再通过DTS同步到ADB。
第四章 总结
AnalyticDB3.0 for MySQL最近的一次更新是在2019年12月份,本次调研的时间为11月份。中间相差有一个月可能存在一定的差异,另外还有对应的for PostgreSQL版本。相比较而言PostgreSQL的功能特性要多,支持Oracle部分语法等。当业务使用的阿里云产品时,随着数据量的增加,并且不想做太大的业务改动。ADB也是一个可以调研的方向
参考文献