乐趣区

关于数据库:滴滴-x-StarRocks极速多维分析创造更大的业务价值

滴滴团体作为生存服务畛域的头部企业,正在全面测试和上线 StarRocks。其中橙心优选通过一年多的数据体系建设,咱们逐步将一部分须要实时交互查问、即席查问的多维数据分析需要由 ClickHouse 迁徙到了 StarRocks 中,StarRocks 在稳定性、实时性方面也给了咱们良好的体验,接下来以 StarRocks 实现的漏斗剖析为例介绍 StarRocks 在橙心优选经营数据分析利用中的实际。

“作者:王鹏,
滴滴橙心优选数据架构部资深数据架构开发工程师,负责橙心优选大数据根底服务和数据利用的开发与建设”

需要介绍

以后咱们数据门户上的漏斗剖析看板扩散,每个看板通常只能反对一个场景的漏斗剖析,不利于用户对立看数或横向比照等,看板无奈反对自选漏斗步骤、下钻拆解等灵便剖析的性能。因而,咱们须要一款能笼罩更全的流量数据,反对灵便筛选维度、灵便抉择漏斗,提供多种剖析视角的漏斗剖析工具,并定位散失人群、转化人群,从而放大问题范畴,精准找到经营策略、产品设计优化点,实现精细化经营。

技术选型

电商场景的流量日志、行为日志个别会比传统场景下的数据量大很多,因而在这样的背景下做漏斗剖析给咱们带来了两大技术挑战:

  • 日增数据量大:日增千万级数据,反对灵便抉择维度,如何疾速地对亿级数据量进行多维分析
  • 对数据分析时效性要求高:如何疾速地基于亿级数据量准确去重,获取符合条件的用户数量

StarRocks 与 ClickHouse 在橙心外部都有宽泛的利用,咱们也积攒了丰盛的教训,但 StarRocks 在易用性和可维护性上都比 ClickHouse 更胜一筹,上面这张表格是咱们在应用过程中对两者性能的一个简略比照:

通过一直地比照和压测,咱们最终决定应用 StarRocks 来存储须要进行漏斗剖析的数据,因为 StarRocks 在 SQL 监控、运维方面相比 ClickHouse 的劣势显著,而且咱们能够为了满足不同的查问场景,基于漏斗剖析明细表创立各种各样的物化视图,进步多维数据分析的速度。

零碎架构

零碎各层职责阐明如下:

1、数据源:次要是 web 端、客户端的埋点日志,这些埋点日志源源不断地上传给咱们的数据接入层

2、数据接入层:

(1) 数据接入总线 :提供多种数据源的接入接口,接管并校验数据,对应用层屏蔽简单的数据格式,对埋点日志进行校验和简略地荡涤、转换后,将日志数据推送到 Kafka 集群

(2)Kafka 集群 :数据接入总线与数据计算集群的中间层。数据接入总线的对应接口将数据接管并校验实现后,将数据对立推送给 Kafka 集群。Kafka 集群解耦了数据接入总线和数据计算集群,利用 Kafka 本身的能力,实现流量管制,开释顶峰时日志数据量过大对上游计算集群、存储系统造成的压力

3、 数据计算与存储层

(1) 数据计算集群 :数据存入 Kafka 集群后,依据不同的业务需要,应用 Flink 或者 Spark 对数据进行实时和离线 ETL,并批量保留到 StarRocks 数据仓库

(2)StarRocks 数据仓库 :Spark+Flink 通过流式数据处理形式将数据存入 StarRocks,咱们能够依据不同的业务场景在 StarRocks 里创立明细表、聚合表和更新表以及物化视图,满足业务方多样的数据应用要求

4、 数据服务层 :外部对立指标定义模型、指标计算逻辑,为各个利用方提供对立的离线查问接口和实时查问接口

5、 漏斗剖析零碎 :反对灵便创立和编辑漏斗,反对漏斗数据查看,漏斗明细数据导出

6、 数据中台 :围绕大数据数据生产与应用场景,提供元数据管理、数据地图、作业调度等通用根底服务,晋升数据生产与应用效率

具体设计

目前,基于 StarRocks 的 bitmap 类型只能承受整型值作为输出,因为咱们原始表的 user_id 存在字母数字混合的状况,无奈间接转换成整型,因而为了反对 bitmap 计算,须要将以后的 user_id 转换成全局惟一的数字 ID。咱们基于 Spark+Hive 的形式构建了原始用户 ID 与编码后的整型用户 ID 一一映射的全局字典,全局字典自身是一张 Hive 表,Hive 表有两个列,一个是原始值,一个是编码的 Int 值。以下是全局字典的构建流程:
1、将原始表的字典列去重生成长期表:

长期表定义:

create table 'temp_table'{'user_id' string COMMENT '原始表去重后的用户 ID'}

字典列去重生成长期表:


insert overwrite table temp_table select user_id from fact_log_user_hive_table group by user_id

2、长期表和全局字典进行 left join, 悬空的词典项为新 value,对新 value 进行编码并插入全局字典:

全局字典表定义:

create table 'global_dict_by_userid_hive_table'{
   'user_id' string COMMENT '原始用户 ID',
   'new_user_id' int COMMENT '对原始用户 ID 编码后的整型用户 ID'
}

将长期表和全局字典表进行关联,未匹配中的即为新增用户,须要调配新的全局 ID,并追加到全局字典表中。全局 ID 的生成形式,是用历史表中以后的最大的用户 ID 加上新增用户的行号:

--4 更新 Hive 字典表
insert overwrite global_dict_by_userid_hive_table 
select user_id, new_user_id from global_dict_by_userid_hive_table
--3 与历史的字段数据求并集
union all select t1.user_id,
--2 生成全局 ID:用全局字典表中以后的最大用户 ID 加上新增用户的行号
(row_number() over(order by t1.user_id) + t2.max_id) as new_user_id
--1 取得新增的去重值汇合
from 
 (
   select user_id from temp_table
   where user_id is not null
 ) t1 
left join 
 (select user_id, new_user_id, (max(new_user_id) over()) as max_id from 
       global_dict_by_userid_hive_table 
 ) t2
on 
 t1.user_id = t2.user_id
 where t2.newuser_id is null

3、原始表和更新后的全局字典表进行 left join , 将新增用户的 ID 和编码后的整型用户 ID 插入到原始表中:


insert overwrite fact_log_user_hive_table
select
 a.user_id,
 b.new_user_id
from
 fact_log_user_hive_table a left join global_dict_by_userid_hive_table b
on a.user_id=b.user_id

4、创立 Spark 离线同步工作实现 Hive 原始表到 StarRocks 明细表的数据同步:StarRocks 表 fact_log_user_doris_table 定义(Hive 表 fact_log_user_hive_table 与该表的构造统一):


CREATE TABLE `fact_log_user_doris_table` (`new_user_id` bigint(20) NULL COMMENT "整型用户 id",
 `user_id` varchar(65533) NULL COMMENT "用户 id",
 `event_source` varchar(65533) NULL COMMENT "端(1:商城小程序 2:团长小程序 3:独立 APP 4:主端)",
 `is_new` varchar(65533) NULL COMMENT "是否新用户",
 `identity` varchar(65533) NULL COMMENT "用户身份 (团长或者普通用户)",
 `biz_channel_name` varchar(65533) NULL COMMENT "当天首次落地页渠道名称",
 `pro_id` varchar(65533) NULL COMMENT "省 ID",
 `pro_name` varchar(65533) NULL COMMENT "省名称",
 `city_id` varchar(65533) NULL COMMENT "城市 ID",
 `city_name` varchar(65533) NULL COMMENT "城市名称", 
 `dt` date NULL COMMENT "分区",
 `period_type` varchar(65533) NULL DEFAULT "daily" COMMENT ""
) ENGINE=OLAP
DUPLICATE KEY(`index_id`, `user_id`, `biz_channel_name`, `pro_id`, `city_id`)
PARTITION BY RANGE(`dt`)(PARTITION p20210731 VALUES [('2021-07-31'), ('2021-08-01')),
 PARTITION p20210801 VALUES [('2021-08-01'), ('2021-08-02')),
 PARTITION p20210802 VALUES [('2021-08-02'), ('2021-08-03')),
 PARTITION p20210803 VALUES [('2021-08-03'), ('2021-08-04')),
 PARTITION p20210804 VALUES [('2021-08-04'), ('2021-08-05')),
 PARTITION p20210805 VALUES [('2021-08-05'), ('2021-08-06')),
 PARTITION p20210806 VALUES [('2021-08-06'), ('2021-08-07')),
 PARTITION p20210807 VALUES [('2021-08-07'), ('2021-08-08')),
 PARTITION p20210808 VALUES [('2021-08-08'), ('2021-08-09')))
 DISTRIBUTED BY HASH(`index_id`, `user_id`) BUCKETS 10
PROPERTIES (
 "replication_num" = "3",
 "dynamic_partition.enable" = "true",
 "dynamic_partition.time_unit" = "DAY",
 "dynamic_partition.time_zone" = "Asia/Shanghai",
 "dynamic_partition.start" = "-2147483648",
 "dynamic_partition.end" = "1",
 "dynamic_partition.prefix" = "p",
 "dynamic_partition.replication_num" = "-1",
 "dynamic_partition.buckets" = "3",
 "in_memory" = "false",
 "storage_format" = "DEFAULT"
);

在这里咱们应用了 StarRocks 的明细模型来建表,满足用户查问漏斗明细数据的应用场景,在明细表上依据不同的多维漏斗剖析查问需要创立相应的物化视图,来满足用户抉择不同维度查看漏斗模型每一步骤用户准确去重数量的应用场景。

5、创立 bitmap_union 物化视图晋升查问速度,实现 count(distinct) 准确去重:

因为用户想要在漏斗模型上查看一些城市用户转化状况。

查问个别为:

select city_id, count(distinct new_user_id) as countDistinctByID from fact_log_user_doris_table where `dt` >= '2021-08-01' AND `dt` <= '2021-08-07' AND `city_id` in (11, 12, 13) group by city_id

针对这种依据城市求准确用户数量的场景,咱们能够在明细表 fact_log_user_doris_table 上创立一个带 bitmap_union 的物化视图从而达到一个事后准确去重的成果,查问时 StarRocks 会主动将原始查问路由到物化视图表上,晋升查问性能。针对这个 case 创立的依据城市分组,对 user_id 进行准确去重的物化视图如下:

create materialized view city_user_count as select city_id, bitmap_union(to_bitmap(new_user_id)) from fact_log_user_doris_table group by city_id;

在 StarRocks 中,count(distinct) 聚合的后果和 bitmap_union_count 聚合的后果是完全一致的。而 bitmap_union_count 等于 bitmap_union 的后果求 count,所以如果查问中波及到 count(distinct) 则通过创立带 bitmap_union 聚合的物化视图方可放慢查问。因为 new_user_id 自身是一个 INT 类型,所以在 StarRocks 中须要先将字段通过函数 to_bitmap 转换为 bitmap 类型而后才能够进行 bitmap_union 聚合。

采纳这种构建全局字典的形式,咱们通过每日凌晨跑 Spark 离线同步工作实现全局字典的更新,以及对原始表中 Value 列的替换,同时对 Spark 工作配置基线和数据品质报警,保障工作的失常运行和数据的准确性,确保次日经营和市场同学能看到之前的经营流动对用户转化率产生的影响,以便他们及时调整经营策略,保障日常经营流动成果。

最终成果及收益

通过产品和研发同学的共同努力,咱们从须要查问的城市数量、时间跨度、数据量三个维度对准确去重性能进行优化,亿级数据量下 150 个城市 ID 准确去重查问整体耗时 3 秒以内,以下是漏斗剖析的最终成果:

将来布局

1、欠缺 StarRocks 外部工具链的开发,同滴滴大数据调度平台和数据开发平台整合,实现 MySQL、ES、Hive 等数据表一键接入 StarRocks。
2、StarRocks 流批一体建设,因为 StarRocks 提供了丰盛的数据模型,咱们能够基于更新模型和明细模型以及物化视图构建流批一体的数据计算与存储模型,目前正在计划落地阶段,欠缺后会推广到橙心各个方向的数据产品上。
3、基于 StarRocks On ElasticSearch 的能力,实现异构数据源的对立 OLAP 查问,赋能不同场景的业务需要,减速数据价值产出。

后续咱们也会继续关注 StarRocks,在外部一直的降级迭代。期待 StarRocks 能提供更丰盛的性能,和更凋谢的生态。StarRocks 后续也会作为 OLAP 平台的重要组件,实现 OLAP 层的对立存储,对立剖析,对立治理。

退出移动版