技术编程|基于Apache Doris的小米增长分析平台实践( 五 )


技术编程|基于Apache Doris的小米增长分析平台实践
文章图片

文章图片

从上图结果可以看出 , doris_exchange_instances对于聚合和join类型的小查询改进明显 。当然 , 这个测试是在很多次测试之后找到的最优doris_exchange_instances值 , 在实际业务中每次都能找到最优值可行性较低 , 一般对于中小业务根据查询计划中需要扫描的buckets数目结合集群规模适当降低 , 用较小的代价获得一定性能提升即可 。后来我们将这个改进贡献到社区 , 该参数名被修改为parallel_exchange_instance_num 。
为了扩展SQL的查询能力 , Doris也提供了和SparkSQL , Hive类似的UDF(User-Defined Functions)框架支持 。当Doris内置函数无法满足用户需求时 , 用户可以根据Doris的UDF框架来实现自定义函数进行查询 。Doris支持的UDF分成两类(目前不支持UDTF , User-Defined Table-Generating Functions , 一行数据输入对应多行数据输出) , 一类是普通UDF , 根据单个数据行的输入 , 产生一个数据行的输出 。另一类是UDAF(User-Defined Aggregate Functions) , 该类函数属于聚合函数 , 接收多个数据行的输入并产生一个数据行的输出 。UDAF的执行流程如下图所示:
技术编程|基于Apache Doris的小米增长分析平台实践
文章图片

文章图片

UDAF一般需要定义4个函数 , 分别为Init、Update、Merge、Finalize函数 , 若为中间输出的数据类型为复杂数据类型时 , 则还需要实现Serialize函数 , 在Shuffle过程中对中间类型进行序列化 , 并在Merge函数中对该类型进行反序列化 。在增长分析场景中 , 留存分析、漏斗分析等都使用到了UDAF 。以留存分析为例 , 它是一种用来分析用户参与情况/活跃程度的分析模型 , 考查进行初始行为后的用户中有多少人会进行后续行为 。针对以上需求 , 我们首先定义了函数retention_info , 输入是每个用户的行为信息 , 然后以每个用户的id为key进行分组 , 生成每个用户在指定时间内的每个时间单元(如天 , 周 , 月等)的留存信息 , 然后定义函数retention_count , 输入是retention_info函数生成的每个用户的留存信息 , 然后我们以留存的时间单位(这里通常是天)为key进行分组 , 就可以算出每个单位时间内留存的用户数 。这样在UDAF的帮助下 , 我们就可以顺利完成留存分析的计算 。
4.4 Doris表的管理
在我们的增长分析场景中 , 从是否分区的角度上看 , Doris的olap表主要分成两种类型 , 一种是非分区表 , 如人群包和业务画像表 , 人群包表的特征是数据量较小 , 但是表的数量多;业务画像表数据量较少 , 数据量中等 , 但有更新需求 。另一种是分区表 , 如事件表 , 这类表一般单表数据规模都比较大 , 在设计上 , 我们以时间字段为分区键 , 需要每天增加为表添加新的分区 , 使得实时的数据能够成功地导入当天的分区 , 并且需要及时地删掉过期的分区 。显然 , 让每个业务自己去管理表的分区 , 不仅繁琐 , 而且可能出错 。在我们原先的GA架构中 , 就有动态分区管理服务 , 使用Doris系统后 , 我们将动态分区管理服务集成到了Doris系统中 , 支持用户按天、周、月来设置需要保留的分区个数以及需要提前创建的分区数量 。
另一个表管理的典型场景是修改表的schema , 主要操作为增加表的字段 。Doris现阶段只支持一些基本数据类型 , 在大数据场景下业务打点上报的日志的数据类型多为嵌套类型(list , map) , 所以接入Doris时需要展开或者转换 , 导致Doris表字段数目较为庞大 , 部分类型字段展开困难不得不用varchar存储导致使用起来非常不方便 , 查询性能也相对低下 。由于Doris不支持嵌套数据类型 , 当嵌套类型新增元素时 , 则Doris表需要增加字段 , 从提交增加字段请求到添加字段成功等待的时间较长 , 当集群管理的tablet数目庞大并且表的数据量和tablet数目都比较多的情况下可能会出现添加列失败的问题 。针对以上问题 , 目前我们主要做了以下两点改进:


推荐阅读