Apache Doris扩容性能测试

1,705 阅读10分钟

1、背景

最近在对一些MPP数据库进行调研,经过一些对比,最后选择Apache Doris作为最终的选择,在对Doris进行性能测试的过程中也踩了一些坑,将其记录下来,也希望能够对大家之后进行数据库性能测试有一点帮助。

2、目标

  • 分布式服务很重要的一个特征就是能够横向扩展,本次性能测试也希望能够对Doris横向扩展能力有一个量化的认识
  • 在之前性能测试的测试数据集只有15GB,本次预期在一个资源比较充足的服务器集群中对大数据集情况下Doris的表现做一个综合的评估。

3、前提

  • 本次测试的所有表、SQL均未进行任何提前聚合、优化等等操作。
  • 在集群扩容之后,必须等待集群整体均衡之后再执行SQL,否则将影响统计结果。

4、环境、数据集

4.1、硬件环境

  • 服务器数量:6
  • CPU:96 Core, Intel(R) Xeon(R) Gold 6271C CPU @ 2.60GHz
  • 内存:376GB
  • 硬盘:1块机械硬盘
  • 网卡:万兆网卡

4.2、数据集

基准测试规范数据量SQL总数表数量
TPC_DS512GB99个SQL25张表

4.3、部分表数据量

表名称数据总量(单副本)单表行数
store_sales193G14.7亿(1474534559)
catalog_sales147G7.3亿(737297458)
web_sales73G3.6亿(368652885)
store_returns17G1.4亿(147453239)
web_returns5.0G3600万(36863085)

4.4、最终形成统计的SQL数量

多表关联SQL数量单表SQL数量
62个7个

4.5、Apache Doris集群

Apache Doris环境(一)

软件名称版本服务器总数FE节点数BE节点数
Apache Doris(百度Polo预编译版本)0.14.12.46Leader-1,Observer-1(均混布)3 ~ 6

5、测试完整流程

5.1、下载TPC-DS源码

访问 TPC Download Current Specs/Source

点击下边红色的内容

填写下边的内容之后,它会将下载链接发送到邮箱中。

然后将其下载到本地并上传到服务器中,进入tools目录编译,执行命令:

$ make

但是在使用官方提供的包编译生成的工具生成sql的时候会出现错误

ERROR: Substitution'_END' is used before being initialized at line 63 in ../query_templates/query1.tpl

所以我们采用下边的方式来实现

5.2、使用第三方库来生成数据和sql

下载源码:

$ git clone https://github.com/gregrahn/tpcds-kit.git

注:若是服务器中无法访问外网需要先下载到本地之后再上传到服务器中。

5.2.2、编译

$ cd ./tpcds-kit/tools
$ make -f Makefile.suite 

5.2.3、生成sql

for id in `seq 1 99`; do ./dsqgen -DIRECTORY ../query_templates -TEMPLATE "query$id.tpl" -DIALECT sqlserver -FILTER Y >> /home/disk1/mpp/tpc-data/tpc.sql; done
  • -DIALECT sqlserver :指定生成SQL的方言 上边的指令将1 ~ 99的模板全部生成sql,最后将sql重定向到指定目录中的tpc.sql。

5.2.4、生成数据

$ nohup ./dsdgen -dir /home/disk2/mpp/tpc-data -scale 512 &
  • -dir :生成数据的目录
  • -scale: 生成数据的大小

上边的指令,可以生成总共大小为512GB的测试数据,生成的过程会比较长,大概需要几个小时,所以采用后台执行的方式。

5.2.5、初始化表结构

在tools目录中的tpcds.sql文件保存了我们测试需要用到的25张表,但是这些表并不能直接在Doris中创建,需要进行改造。因为这些表都有主键约束,所以我们采用Doris的Uniq模型作为建表模型(Doris的几种模型区别可以参考:数据模型)。

5.3、表结构调整

我们以web_returns表作为整个流程的代表:

5.3.1、原始SQL

create table web_returns
(
    wr_returned_date_sk       integer                       ,
    wr_returned_time_sk       integer                       ,
    wr_item_sk                integer               not null,
    wr_refunded_customer_sk   integer                       ,
    wr_refunded_cdemo_sk      integer                       ,
    wr_refunded_hdemo_sk      integer                       ,
    wr_refunded_addr_sk       integer                       ,
    wr_returning_customer_sk  integer                       ,
    wr_returning_cdemo_sk     integer                       ,
    wr_returning_hdemo_sk     integer                       ,
    wr_returning_addr_sk      integer                       ,
    wr_web_page_sk            integer                       ,
    wr_reason_sk              integer                       ,
    wr_order_number           integer               not null,
    wr_return_quantity        integer                       ,
    wr_return_amt             decimal(7,2)                  ,
    wr_return_tax             decimal(7,2)                  ,
    wr_return_amt_inc_tax     decimal(7,2)                  ,
    wr_fee                    decimal(7,2)                  ,
    wr_return_ship_cost       decimal(7,2)                  ,
    wr_refunded_cash          decimal(7,2)                  ,
    wr_reversed_charge        decimal(7,2)                  ,
    wr_account_credit         decimal(7,2)                  ,
    wr_net_loss               decimal(7,2)                  ,
    primary key (wr_item_sk, wr_order_number)
);

5.3.2、调整后的SQL

create table web_returns
(   
    wr_item_sk                int               not null,
    wr_order_number           int               not null,
    wr_returned_date_sk       int                       ,
    wr_returned_time_sk       int                       ,
    wr_refunded_customer_sk   int                       ,
    wr_refunded_cdemo_sk      int                       ,
    wr_refunded_hdemo_sk      int                       ,
    wr_refunded_addr_sk       int                       ,
    wr_returning_customer_sk  int                       ,
    wr_returning_cdemo_sk     int                       ,
    wr_returning_hdemo_sk     int                       ,
    wr_returning_addr_sk      int                       ,
    wr_web_page_sk            int                       ,
    wr_reason_sk              int                       ,
    wr_return_quantity        int                       ,
    wr_return_amt             decimal(7,2)                  ,
    wr_return_tax             decimal(7,2)                  ,
    wr_return_amt_inc_tax     decimal(7,2)                  ,
    wr_fee                    decimal(7,2)                  ,
    wr_return_ship_cost       decimal(7,2)                  ,
    wr_refunded_cash          decimal(7,2)                  ,
    wr_reversed_charge        decimal(7,2)                  ,
    wr_account_credit         decimal(7,2)                  ,
    wr_net_loss               decimal(7,2)                  
)
ENGINE=olap 
UNIQUE KEY(`wr_item_sk`, `wr_order_number`)
DISTRIBUTED BY HASH(`wr_item_sk`, `wr_order_number`) BUCKETS 3
PROPERTIES("replication_num" = "3");

调整后的SQL主要是指定了表的引擎、Uniq模型,以及唯一约束的字段,还有分桶的字段、分桶数,副本数量等等。

注意

在Doris中表中的字段区分为Key、Value两种类型。Key类型的字段必须在Value类型的字段之前,而在Uniq模型的除了唯一约束是Key,其他的字段均为Value,所以我们需要将原始表结构中的wr_item_sk、wr_order_number移动到前边

这也就决定了我们在导入数据之前还需要根据表结构顺序的变换,将原始数据顺序调整为跟表结构一致。

5.4、调整数据

5.4.1、去掉最后一个竖线

TPC-DS生成的数据默认是采用“竖线-|”来间隔的,但是它的每行数据最后一行却多了一个竖线|。导致解析出来的结果多了一行,所以我们需要将其最后一个竖线删除,有很多种方法来解决这个问题,例如:

  • 用python、shell脚本处理
  • 使用sed将文件最后一个竖线删除,然后重新写入到一个新文件中的。

使用sed删除最后一个竖线:

$ sed  s'/.$//' web_returns.dat >> doris/web_returns.dat

5.4.2、调整列顺序

awk -v FS="|" -v OFS="|" '{print $3, $14, $1, $2, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24}' web_returns.dat >> ./doris/web_returns.dat

上边的采用web_returns表的数据进行展示,将第3、14行数据顶到前边两行数据,后边的数据依次顶上。值得注意的有下边几个地方:

  • -v FS="|" :这里是指定awk解析的字段分隔符,因为awk默认是空格作为分隔符,若不是空格,则需要单独指定。
  • -v OFS="|" :这个参数时指定输出数据的分隔符,同样awk是默认采用空格作为输出分割符。

在生成的所有25张表数据,全部都需要采用这种方式来进行调整才能够才能够在下一步进行导入。

5.5、导入数据

在Doris中为我们提供了6种不同的导入方式,因为当前的数据就在当前的服务器中,所以我们使用Stream load的方式进行导入即可。

curl --location-trusted -u user:password \
-H "label:web_returns_20220107" \
-H "column_separator:|" \
-T /home/disk1/mpp/tpc-data/doris/web_returns.dat \
http://10.68.41.86:8030/api/tpc_db/web_returns/_stream_load
  • user:password:当前Doris集群的账号密码
  • label:该任务的标签,为了避免数据被重复导入,建议添加标签
  • -T:指定导入数据的文件
  • http://10.68.41.86:8030/api/tpc_db/web_returns/_stream_load: 其中tpc_db是指定的库名称,web_returns是将要导入的表名称。

上边使用Curl触发导入任务,执行的过程如下: 这种类型的导入任务是同步执行的,执行完成之后会返回执行结果。

注意

在导入数据的时候,若是数据集比较大,比如超过10GB、导入的时间比较长,我们需要调整Doris的默认配置才能够执行,主要是修改下边两个配置。

  • 在fe.conf文件中设置:stream_load_default_timeout_second = 21600,这个配置单位为秒,上边的配置是指定超时时间为6小时。
  • 在be.conf文件中设置:streaming_load_max_mb = 204800,这个配置单位为MB,上边的配置是指定导入文件最大为200GB。

在集群中每个节点均修改完成之后,我们可以依次重启FE、BE节点(注:采用CURL参数传递的方式并不会生效),然后在执行导入。

6、测试报告

6.1、统计指标解释

  • 性能提升比例:这个指标是基于执行总时间,对比当前节点数减一统计的,例如4节点集群性能相对于3节点集群单表聚合总体性能能够提升16.5%。
  • 增加节点加速比:这个指标是当前节点数所执行全量SQL,对比当前节点数减一统计的,例如在4节点时,所执行的62个多表关联SQL速度有80.6%的比例比3节点更快。

6.2、单表聚合统计

注:上边的SQL均是对store_sales(14.7亿)单表表进行聚合查询。

6.3、多表Join统计

  • 在生成的99个多表关联的SQL中我们选择了其中62个作为测试的SQL,上边的图并不完整,空间有限,将中间的一部分去掉了。

7、统计结果分析

上边的图表数据值较多,不太方便我们对整体结果快速感知,所以根据结果统计了一些图来直观展示。

7.1、扩容性能提升折线图

  • 上边的折线图是根据第6部分的测试报告中的执行总时间统计出来的,将3节点作为一个“锚点”,当集群处于4、5、6个节点时,执行的SQL总时间与3节点时间反比得出递增的数值,然后再除以“锚点”(集群处于3节点时的执行总时长)得出的上述折线图。

  • 上边的图我们可以清晰的看到,当集群处于3个节点,在扩容到4节点时,性能提升最明显,然后继续加节点时,性能递增的趋势逐渐平缓。这个增长走势是符合正常分布式集群扩容的性能增长趋势的,我们每扩容一个节点,新增节点(算力)在集群中的占比就会降低一些,此时若是性能提升仍然没有达到我们的预期时,应该考虑优化SQL(Bitmap索引、物化视图、ROLLUP、分区分桶)等等手段来实现,而一味堆机器则边际效益递减

7.2、增加节点加速比

  • 解释一下,“节点加速比”的含义就是,每增加一个节点,所有SQL执行时间减少(加速)的比例

  • 因为我们是以3节点为基准,所以这张折线图中没有3节点的数据。其中在多表关联的类型中(62个SQL),增加到4节点时,加速比能达到80.6%,增加到5节点时,加速比为66.1%,但是在6节点时反而加速比能到70.96%;按照前边“边际效益递减”的结论,照理说到6节点时加速比应该更小。这里没有按照这个规律的主要原因是在62个SQL中有一部分执行时间非常短(毫秒级),在这种情况下,偶然性就不能忽略了,所以6个节点的加速比比5个节点的大也是存在这种可能性的。

8、总结

  • 1、从上边的单表聚合统计结果来看,在大数据集(193G)的情况下,单表的聚合若是没有提前聚合、物化视图、ROLLUP等等优化手段,查询的效率也是较低的,在这类需求下,需要我们根据业务的实际需求来分析,找到一个合适的优化方案,这一点也是区别于传统的Hive、Hadoop的解决方案,那就是Doris的优化手段较多,主要看使用者能否发挥它的最大“功力”。

  • 2、Doris在多表关联的性能上表现从上边的数据来看是比较优秀的,所以在使用的过程中我们没有太大必要将数据冗余成一张宽表,增加存储成本;采用直接关联查询的方式在大多数情况下也能够满足我们的查询延时要求。

  • 3、对于集群资源来说,在一定程度上,增加节点资源确实能够提高整体集群性能,但是随着我们节点资源的增加,性能的提升效果是边际递减的,所以我们在使用的时候首先应该立足于业务优化、SQL优化,其次才考虑集群升级

参考