分享人|货拉拉大数据引擎负责人 杨秋吉,张斌
业务背景
货拉拉成立于 2013 年,成长于粤港澳大湾区,是一家从事同城、跨城货运、企业版物流服务、搬家、汽车销售及车后市场服务的互联网物流公司。截至 2022 年 4 月,货拉拉的业务范围已经覆盖了国内 352 座城市,月活司机达到 58 万,月活用户达到 760 万,包含 8 条以上的业务线。
货拉拉大数据体系为支撑公司业务,现在已经成立三个 IDC 集群、拥有上千台规模的机器数量,存储量达到了 20PB、日均任务数达到了 20k 以上,并且还处在快速增长的过程中。
大数据体系
货拉拉大数据体系从下往上分为 5 层,最下面的是基础层和接入层,这两层主要会提供基础数据的存储、计算以及集群的管理功能。在基础层和接入层之上是平台层和数仓。在平台层之中包含了数据研发平台和数据治理平台,基于平台层的能力和数据仓库的数据体系,在这之上面包含了含有业务属性的服务层和应用层。整个体系自下而上相互支持,实现支持业务和赋能业务的能力。
图1.1 货拉拉大数据体系>>>数据处理流货拉拉典型的数据处理流,可以分成数据集成、采集、数据的存储计算、数据服务四部分,同时也包含了实时、离线以及在线三大业务场景。
图1.2 货拉拉大数据数据流在数据采集阶段会存在实时采集和离线采集两条路线。
中间是数据的存储和计算阶段。在离线场景中会通过对数据 ETL 之后转换为构造数仓的分层体系。实时比较典型的场景为数据在经过 Flink 的处理后会直接落在线存储系统,类似于 HBase 和 OLAP 等等,为后续的业务系统提供数据服务。
OLAP 演进概览
货拉拉从 2021 年开始进行 OLAP 的技术研究,截至目前已经经历 3 个阶段:
图2.1 货拉拉OLAP体系演进过程
OLAP1.0 孕育期
>>>业务需求分析先看下没有引入 OLAP 之前的业务数据流:
图3.1 OLAP1.0业务场景
根据该图可以看到业务的数据通过实时和离线处理之后会落在 MySQL,MySQL 之中储存了维度聚合之后的结果数据,这也意味着会在 Flink 之中做大量的聚合分析,根据业务需要的相应维度所做的一系列组合都是在Flink之中做实时聚合,最后将结果储存到 MySQL。
存在的问题:
对于存在的这些问题,我们经过分析之后,总结出了 3 个背后存在的需求点:
>>> 解决方案
根据业务需求,并通过调研,我们决定使用 OLAP 引擎来支持业务需求。那我们如何选择一款 OLAP 引擎,并把它稳定的应用到生产之中呢?我们总结了如下的 4 个步骤作为解决思路:
图3.2 OLAP 1.0 解决思路
技术调研
技术调研阶段,我们对比了 Durid、ClickHouse、Kylin、Presto 和 Doris 等等引擎。结合我们上述的 3 个业务需求,最终我们选择了 Druid 引擎。
原因是 Druid 除了能够满足我们的业务需求之外,还有一个比较重要的影响因素是 Druid 引擎是纯 Java 开发,与我们的技术栈比较吻合,可控性更高。
图3.3 OLAP1.0技术调研
POC 阶段
POC 过程中,从以下 3 个步骤着手:
图3.4 OLAP1.0 POC 验证
稳定性保障
当 POC 验证完成之后,接下来我们会进行稳定性的保障。我们将稳定性保障分为事前、事中、事后 3 个阶段:
图3.5 OLAP1.0 稳定性保障
上线阶段
当稳定性保障建立完成之后就会进入到上线阶段。上线过程我们同样分成了 3 个阶段:
图3.6 OLAP1.0 上生产
>>> 问题总结
下面总结了 1.0 阶段时遇到的问题:
图3.7 OLAP1.0 问题总结
OLAP2.0 完善期
>>> 业务需求分析
在 OLAP2.0 阶段主要有以下 4 个业务需求:
图4.1 OLAP2.0 业务需求分析下图是简单的业务工具的截图,从图中可以看到,OLAP2.0 需要能够支持汇总与明细,同时基于这些能力能够做一个快速的问题定位。
图4.2 OLAP2.0 业务需求分析骤去实现。
>>> 解决方案
图4.3 OLAP2.0 技术调研OLAP2.0 我们引入了 CliclkHouse。ClickHouse 能够比较好地支持复杂的数据类型,同时因为业务侧是埋点数据,所以对于实时导入语义要求并没有那么高。没有采用 Druid 主要是有 2 个原因:
剩下的部分就是 POC 、上生产的步骤,这两个步骤和 OLAP1.0 阶段比较类似,所以在这里就不过多展开介绍。
OLAP3.0 成熟期
>>>业务需求分析2022 年随着公司业务的发展,更多的产品线对于多数据源关联场景下的在线分析需求也会变得越来越迫切。比如说 AB 实验场景与实时数仓场景,这两个场景对于多表关联需求,尤其是大表的多表关联需求也变得越来越迫切。
图5.1 OLAP3.0 需求分析
举一个 AB 实验的例子。从下图可以看到,例子中是需要把 AB 实验的一个数据和后面相应的司机与用户的埋点数据关联到一起并做分析。在这种情况下,我们就会发现之前的两种工具都会存在一系列的弊端。
图5.2 OLAP3.0 需求分析
>>> 解决方案
技术调研
在技术调研阶段我们观察了 Druid 和 ClickHouse。Druid 引擎可以支持一些维表的简单 Join,ClickHouse 则能够支持 Broadcast 这种基于内存的 Join,但是对于大数据量千万级甚至亿级的一些表的 Join 而言,ClickHouse 的性能表现不是很好。
图5.3 OLAP3.0 技术调研
接下来我们对 Doris 进行了调研,我们发现 Doris 是能够支持小表的 Join,对大表的话也同样能够支持基于 Shuffle 的 Join,对于复杂数据类型(Array、JSon)的支持,经过跟 Apache Doris 社区沟通,预计将在 2022 年 7 月份的新版本中发布。通过在多个维度和需求满足度上进行对比,我们最终选择了 Apache Doris,也是因为 Apache Doris 的 SQL 支持度非常的完善。
图5.4 OLAP3.0 技术调研
POC 阶段
我们除了引用业务真实的数据和场景做验证以外,还引入了 TPC-DS 的数据集做了验证。在多表关联的场景下对单天数据进行查询,对 5 亿左右的数据量进行 Join,TP75 大概是 9 秒左右。在数据质量阶段我们也是把 TPC- DS 的数据集以及业务真实数据集,分别在 Hive 和 Doris 里面做了双跑验证,发现两者都是能够完全对得上的。
图5.5 OLAP3.0 POC
稳定性保障
与之前一样依然是从事前的容量评估和压测、事中的监控和定位来进行。
图5.6 OLAP3.0 稳定性测试
下面是我们的监控图,主要是关于 Compaction 相关的一些监控,感兴趣的同学可以看看。(文末 QA 环节有部分讲解)
图5.7 OLAP3.0 稳定性监控
>>> 问题总结
第一个问题是查询性能的优化。业务侧的需求为 7 天的查询 RT 需要在 5 秒内完成,在优化前,我们发现 7 天的查询 RT 是在 30 秒左右。对于这个问题,我们的主要优化策略是把小表 Join 大表改成了大表 Join 小表,主要原理是因为 Doris 默认会使用右表的数据去构建一个 Hashtable。还有类似下图中的情况:union all 是在子查询中,然后再和外层的另外一张大表做 Join 的查询方式。这种查询方式没有用到 Runtime Filter 的特性,因此我们将 union all 提到子查询外,这样就能够用到 Runtime Filter,这应该是由于这里的条件下没有推下去所导致的。同时运行时采用的 Bloom Filter 是可以将 HashKey 条件下推到大表 Scan 阶段做过滤。在经过对这两者优化之后便能够满足我们的查询性能需求了。
图5.8 OLAP3.0 问题1第二个问题是 UnhealthyTablet 不下降,并且在查询阶段会出现 -230 的报错。这个问题的场景是我们在没有停 FIink 写任务的时候,对 BE 机器交替重启,重启完会出现很多 UnhealthyTablet。经过我们后续的分析发现,其中一个原因主要是在 Coordinator BE 在做二阶段提交的时候比较巧合,Coordinator BE 的二阶段提交 Commit 后,也就是大部分的副本是已经 Commit 后且在 Publish 前,在这短短的时间范围内 BE 机器被重启,这也导致会出现 Tablet 状态不一致的情况。同时由于我们当时把参数调整的过大,导致了 Compaction 压力过大。最后的解决办法:与 Aapache Doris 社区的同学经过互助排查,引入了社区 1.1.0的 Patch,同时对相应的数据做了恢复。
图5.9 OLAP3.0 问题2
>>> 参数优化
图5.10 OLAP3.0 参数优化>>>数据流下图是使用 Doris 之后的数据流图:
图5.11 OLAP3.0 数据流
数据流中,我们在 Flink 中做的事情已经很少了,经过数据简单的 ETL 后就可以把数据直接灌入到 Doris。经过 Doris 一系列的聚合计算、union 计算以及多表关联计算之后,业务侧就可以直接查询 Doris 来获取相关数据。
总结与思考
总结:我们 OLAP 的引进主要还是从业务需求的角度出发来匹配合适的引擎,为业务精细化运维提供技术支持。在这之后,我们也思考了一套较为完善的上线流程及稳定性保证方案,为业务的平稳运行提供能力保障。
思考:我们认为很难有单个引擎能够富含各种场景。因此在技术选型时,需要针对于需求特点和引擎特点进行合理选择。
后续规划
我们希望可以向 OLAP 平台化发展,通过实现自助化建模的同时在这方面做一些多引擎的路由,使其能够支持各类聚合、明细以及关联等场景。
图6.1 后续规划 OLAP 平台化除 OLAP 平台化之外,后续我们的引擎演进计划从高效、稳定和内核演进三部分来进行。
图6.2 后续规划 引擎演进稳定性方面:对 Doris 还要继续深入内核理解,提供一定的二次开发。另外 Doris 社区的相关原理以及代码级别的教程数量十分丰富,这也间接性降低了我们深入 Doris 原理的难度。
内核演进方面:我们发现 Doris 基本能够覆盖 Druid 所有场景,因此后续计划以 Doris 引擎为主,Clickhous 引擎为辅,逐渐将 Druid 的相关业务向 Doris 迁移。
Q&A 环节
Q:刚才讲到了后续要从 Druid 引擎迁移到 Doris,要实现迁移的成本有多大呢?
A:迁移成本方面和我们之前的成本是一样的。我们上线的时候也会采用以下方式:先把业务的数据同时往 Druid 和 Doris 之中写,写完之后的业务迁移会涉及一些 SQL 改造。因为 Doris 更加接近MySQL的协议,比起 Druid SQL 会更加便捷,所以这部分的迁移成本不是很大。
Q:刚才介绍的第二个场景之中的监控图都看了哪些指标呢?
A:关于监控图,我们会比较关注 Doris 的数据导入。而在数据导入部分,我们最关注的就是 Compaction 的效率,是否有 Compaction 的堆积。我们现在还是采用的默认参数,也就是 Compaction 的分数就代表它的版本号,所以我们监控的更多的是它的版本。对于这方面的监控,社区也已经有了比较完善的相应技术方案,我们也是参考了社区的技术方案来进行了监控的指标搭建。
Q:从指标上看,Doris 的实时服务在线查询性能怎么样?在数据导入情况下性能损耗可以从这些指标上看出来吗?
A:实时导入方面主要是从 Compaction 的效率来看。结合到我们这边的业务场景,最多的一张表,单表一天也有 6 亿到 10 亿的数据量的导入,也是一张埋点。另外关于峰值,它的 QPS 也是能达到千到万的,所以导入这一块压力不是很大。
Q:SQL 缓存和分区缓存实际效果怎么样?
A:SQL 缓存方面效果还好,对于很多离线场景,尤其是首页这种查询的数据量而言。比如以昨天或者是过去一个小时之前的这种情况来说,SQL 缓存命中率会非常高。分区级缓存方面,我们分区的时间还是设的是小时级,这意味着如果这个查询里面涉及到的一些分区在一个小时内没有数据更新的话,那么就会走 SQL 缓存;如果有更新的话就会走分区级缓存。总体来看效果还好,但是我们这边命中比较多的还是 SQL 级的缓存。
Q:Doris 的查询导入合并和缓存的 BE 节点的内存一般怎么分配?
A:缓存方面我们分配的不大,还是采用的偏默认的 1G 以内。导入方面我们设计的是 parallel_fragment_exec_instance_num 这个参数,大概在 8G 左右。
Q:可以解释一下 OLAP3.0 的解决思路吗?
A:对于 OLAP3.0 方面来说,业务的主要诉求就是大表Join。除此之外,还有一些类似于导入的进度一致等等。在大表Join方面,我们也对比了很多的引擎。Druid 这方面就是偏维表;Clickhouse这方面还是偏基于内存方面的 Broadcast。正因如此,主要是基于大表Join的出发点,我们选择引入了在Join这方面能力更强的 Doris。
Q:Druid、ClickHouse 和 Doris 应该都是近实时的,就是 Near Real-time,他们的写入不是立刻可见的,是这样吗?
A:是这样的。像 Doris 和 ClickHouse 之前的写入都是 Flink 直接去写,我们也没有完全做到来一条数据就写一条,都是一个微批次。一个批次最大可以达到 150 兆的数据堆积,写入一次的时间间隔也是到 10 秒左右,没有做到完全的实时写入。
Q:方便透露一下货拉拉目前 Doris 的集群的使用情况,比如机器的数量和数据量吗?
A:我们的集群数量还不算很多,10 多台。
Q:对于 Doris 的运维方面,它的便捷性和 Druid、ClickHouse、Kylin、Presto 这些相比,有很好的扩展性吗?
A:我们觉得是有的。第一个是在我们 Druid 方面碰到了一个比较大的痛点,就是它的角色特别多,有 6 种角色,所以需要部署的机器会非常多。另外一点是 Druid 的外部依赖也非常多,Druid 依赖于 HDFS、离线导入还需要有 Hadoop 集群。第二个是 ClickhHouse 方面,我们当时使用的版本对于 Zookeeper 也是有比较大的依赖。另外,ClickHouse 也是偏伪分布式的,有点类似于数据库的一种分表。Doris 自身就只有 FE、BE,外部依赖会非常少,所以我们从部署的角度同时考虑到 Doris 的横向扩展方面,Doris 的扩缩容也能够做到自平衡,所以相比而言 Doris 会更好一些。
Q:在实时特征场景下,分钟级的数据更新对服务性能要求比较高,可以用 Doris 吗?能达到 TP99 200 毫秒以下吗?
A:TP99 能够否达到200毫秒以下主要和你查询 SQL 相关。
例如我们这边的很多涉及到大表 Join 的查询,涉及的分区数据量大概在 10 亿量别,业务侧对于查询性能要求是 5 秒以内,通过 Doris 是可以满足我们需求的。如果是实时特征这种业务,是否能达到 200 毫秒可能需要经过一轮实际测试才能得到结果。