「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!」
1:项目背景
bi系统往往决定一家公司的日常决策,所以必须要够灵活、底层数据通用、指标体系归一、能快速接入相关指标体系至关重要。过程中不断的与产品、业务不断的沟通升级。从渠道分析、会员、核心数据、埋点体系验证、人群画像、自定义报表、漏斗、全平台数据打通、推荐系统ab/test,打磨出一套BI雏形。
2:数仓系统的衍变
我们的数仓系统经过了4次大版本衍变,详细如下:
数仓版本 | 相关的技术方案 |
---|---|
1.0 | azkaban定制执行离线脚本(hive -f 执行脚本),ads层建立es外表。bi系统仅支持离线数据。 |
2.0 | 迁移离线脚本到db,建立ods,dwd,dim,mid,dws ads层,通过spark sql 执行job。ads层的数据同步到es。 |
3.0 | 建立主题、指标,dws层的数据接入kylin 。通过指标完成底层的数据指标复用,降低指标入口来源维护,实时数据分析引入clickhouse。 |
4.0 | 维护所有的主题,字典,指标,组件,可视化(多组件整合),cube 自动化构建。所有离线、实时任务都迁移到dolphinscheduler 。 |
看到上面的每一步,我很庆幸自己和团队的每一个人成员都敢于去挑战自己。当然我们在做的过程中也看过业内商业化产品(神策、友盟、字节),毕竟在跟着业内主流走,大方面不会偏。
3:数仓的治理
bi系统是负责展示大数据的门户,背后的底层逻辑搭建、模型的抽离至关重要。我重点说下每一个版本,我们做了一些什么样的治理。首先大致了解一下数据中台的系统架构,详细如下:
1.石器时代(es 外表)
刚开始搭建bi体系的时候,我们的各种体系都比较欠缺。当初为了快速响应业务,所有的报表都通过外表处理。(快速的创建报表体系,让相关人员看到初步的成果)详细如下:
##hive对应的 es 外表
CREATE EXTERNAL TABLE `app.channel_hour_analyse_report`(
`id` string COMMENT 'doc_id',
`channel_number` string COMMENT '渠道号',
`install_device_count` bigint COMMENT '安装量',
`staticdate` string COMMENT '时间',
`hour` bigint COMMENT '小时')
ROW FORMAT SERDE
'org.elasticsearch.hadoop.hive.EsSerDe'
STORED BY
'org.elasticsearch.hadoop.hive.EsStorageHandler'
WITH SERDEPROPERTIES (
'serialization.format'='1')
LOCATION
'hdfs://nameservice1/user/hive/warehouse/app.db/channel_hour_analyse_report'
TBLPROPERTIES (
'es.mapping.id'='id',
'es.nodes'='prod-es1:9200,prod-es2:9200,prod-es3:9200',
'es.resource'='d_custom_channel_operation_day_hour_table/_doc',
'es.write.operation'='upsert',
'last_modified_by'='test',
'last_modified_time'='1603697145',
'transient_lastDdlTime'='1603697145')
##hive 对应的hbase 外表
create EXTERNAL table `dwd.dw_public_userid_deviceid_relation`(
`rowkey` string COMMENT 'rowkey',
`userid` string COMMENT 'userid',
`deviceid` string COMMENT 'deviceid' ,
`last_login_time` string COMMENT 'last_login_time',
`use_count` INT COMMENT 'use_count',
`reserve1` string COMMENT '预留字段1',
`reserve2` string COMMENT '预留字段2'
) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH
SERDEPROPERTIES ("hbase.columns.mapping"=
":key,
cf:userid,
cf:deviceid,
cf:last_login_time,
cf:use_count,
cf:reserve1,
cf:reserve2") TBLPROPERTIES ("hbase.table.name" = "userid_deviceid_relation");
复制代码
2.青铜时代(脚本迁移到spark sql)
所有的脚本迁移到db,建议分为ods、dwd、dim、dws、ads 层,同一层的数据设置优先级,因为同一层的数据可能存在相互依赖的情况。一定要把数据来源, sink 目标表,ddl,exec_sqls(建议 JsonArray存储),app项目,分区,exec_level(建议越小约优先执行),状态,创建人,时间,修改人,时间(方便以后问题追踪),还可以扩展到kylin,clickhouse 等olap场景是否使用。 所有的数据取消外表,通过spark job 写入es 。
val frame: DataFrame = spark.sql(read).filter(_.getString(0) != null).coalesce(10)
frame.show()
EsSparkSQL.saveToEs(frame, index, esConfig)
复制代码
3.铁器时代(引入kylin)
通过spark sql 执行整体的执行时间降低40%。但是业务需要添加纬度过滤,我们对应的sql 就需要成倍的增加。对于后期的脚本维护成本是比较大的,所以引入kylin。建立纬度、度量,迁移历史spark 脚本。注意 kylin 提交spark 任务,刚开始通过hive on spark 执行任务。后续优化通过livy 提交任务到spark ,整合的性能有较大的提升。在本次项目中引入字典库、模型为工业时代打下基础。
4.工业时代(数仓建模)
引入kylin以后所有的数据层还是通过dws load hive 数据到kylin ,但是底层的hive元数据管理,主题、指标管理、复合指标管理、组件管理、可视化管理都是人工维护。为了打通河西走廊,我们把底层所有的同一行为的数据收缩统一、所有的度量、纬度通过系统动态构建cube。并且适配其他的olap 组件接入。
private RestClient getOrCreateRestClient(KylinRestClientType clientType) {
RestClient restClient = restClientHashMap.get(clientType);
if (restClient == null) {
switch (clientType) {
case CUBE:
restClient = new CubeClient();
break;
case MODEL:
restClient = new ModelClient();
break;
case METADATA:
restClient = new MetadataClient();
break;
default:
LOG.error("Can't match Client:{}", clientType);
}
LOG.info("create Kylin restClient type:{}", clientType);
restClientHashMap.put(clientType, restClient);
}
return restClient;
}
复制代码
4:总结
每一次的新尝试,都会有一定的突破。过程中有一些地方不够完美或不是足够的合理,但思维的碰撞促使我们不断的进步。业界有很多开源的数据展示组件像superset,metabase等,但是这些都离不开底层的指标与建模。欢迎大家一起讨论数据建模管理,以上是个人的一些思考。个别出处有问题,欢迎大家指正。