ClickHouse在京东小程序自定义数据分析中的应用与实践

一、 业务背景

随着移动互联网的快速发展,小程序作为当下零售环境下的崭新载体,它凭借着入口丰富、场景多元、传播能力强、触手可及以及用完即走的特点,得到了广泛的认可和传播。而在小程序的日常运营与发展中,存在着多样的数据信息,面对如此丰富的数据生产资料,如何高效灵活地对这些原始数据进行分析与挖掘,迅速掌握小程序数据的波动,洞察小程序用户行为变化,是目前国内各个小程序平台不断追求突破的问题。因为只有不断提高数据的分析效率,才能更好地沉淀数据分析的能力,进而借助于数据的深层潜在价值为小程序的业务发展而赋能。
京东小程序数据中心已涵盖用户行为分析、留存分析、用户画像及来源分析等四大基础数据分析模块,涉及的数据指标多达60+。
早期的数据主要由京东小程序客户端引擎SDK进行采集,通过子午线原生渠道进行统一上报,再由服务端统一清洗处理;这种模式虽然可以覆盖大部分基础数据分析的场景,但是仍然存在如下痛点问题:
1、数据类型不完整:基础数据指标仅为小程序框架可以获取的数据,而小程序内开发者自有代码的页面曝光、点击等业务数据,小程序框架无法自动获取,导致小程序数据平台提供数据的完整性无法得到保证。例如,针对ISV商家开发的某营销类小程序,我们无法采集并分析到该小程序在进行营销活动时,某一个领券按钮的用户点击数据;
2、行业数据无法沉淀:小程序涵盖的业务场景丰富多样,且复杂程度不一,早期的数据中心,仅提供后置的数据分析展示,因为业务数据缺失,无法提供基于行业的预测分析模型,很难为商家提供更为有效的经营指导策略支持。
3、无法满足多变的数据统计需要:目前已有的数据分析是固化的、预置的且不可变的,自定义数据分析能真正支持数据的灵活统计需要,满足多变的业务数据分析场景。
以上问题的关键,在于如何解决未来海量业务数据的存储、灵活处理及深度分析,基于此,我们调研了行业内多家成熟数据解决方案,重点考虑京东业务特点,最终构造了一套完整的京东小程序自定义数据分析服务。
接下来,本文将详细介绍京东小程序自定义数据分析服务的整体技术方案和关键流程,重点涵盖动态规则配置解析、数据存储设计以及实时数据查询分析等功能的设计和实现。

二、 技术选型

京东小程序的自定义数据分析需要一种支持海量数据存储、查询高效且运维成本较低的数据存储方式,经过调研对比发现,ClickHouse以下的三点特征可以很好地满足我们的技术选型诉求。
1、支持列式存储和数据压缩
京东小程序自定义数据分析需要满足用户在系统查询分析时的查询执行效率,我们期望在百亿数据集中,秒级返回执行的自定义数据分析的聚合结果,对比发现,ClickHouse按列存储的特性便可以极大提升数据查询的效率,因为按列存储与按行存储相比,前者可以有效减少查询时所需扫描的数据量,如果数据按行存储,数据库首先会逐行扫描,并获取每行数据的所有字段,再从每一行数据中返回查询所需要的字段,导致会扫描所有的字段。如果数据按列组织,数据库可以直接获取想查询的列的数据,从而避免了多余的数据行扫描。
针对分析类查询,通常只需要读取表的一小部分列。在列式数据库中你可以只读取你需要的数据。例如,如果只需要读取100列中的5列,这将帮助你最少减少20倍的I/O消耗。
ClickHouse采用的压缩算法可以将列的数据进行压缩处理,数据中的重复项越多,则压缩率越高;压缩率越高,则数据体量越小;而数据体量越小,则数据在网络中的传输越快,对网络带宽和磁盘I/O的压力也就会进一步地变小。
2、MPP架构,支持分布式水平拓展
京东小程序自定义数据分析服务需要支持水平的拓展。因为随时业务的发展,小程序的数据量势必会日益庞大,调研发现,ClickHouse天然具备分布式存储的特点,它本身是一款MPP(Massively Parallel Processing)架构的列式存储数据库,支持大规模并行处理,以多主对等的扁平架构,保证了海量数据在各个节点的分布式存储。
这样对于我们后期的业务数据的拓展存储提供了必要的保障,只需简单增加节点,即可实现水平扩容,极大地降低了运维的成本。
在ClickHouse中,数据可以保存在不同的shard上,每一个shard都由一组用于容错的replica组成,查询可以并行地在所有shard上进行处理,如下图Node1和Node2均为主shard,互为replicate,然而这些对用户来说完全是透明的。

3、多样化的表存储引擎
京东小程序自定义数据分析的场景较多,涉及点击、浏览、曝光和订单等四大类分析场景,每种场景都有独特且常见的统计需要,比如常见的计算去重用户数、求和金额、求金额平均值或最大值等,而在ClickHouse中可以针对表设置对应的表引擎,表引擎决定了表存储在哪里、以何种方式进行存储以及支持的查询方式。同时,表引擎可以结合ClickHouse的物化视图使用,能够达到非常好的查询效果。
ClickHouse共拥有合并树、内存、文件、接口和其他6大类20多种表引擎。其中每一种表引擎都有着各自的特点和适用的场景,对于简单的场景,可直接使用简单的引擎降低运维成本,而复杂的场景也有合适的选择。

比如,MergeTree家族的ReplacingMergeTree引擎,它会删除排序键值相同的重复项。数据的去重只会在数据合并期间进行,合并会在后台一个不确定的时间进行,因此你无法预先作出计划。因此,ReplacingMergeTree 适用于在后台清除重复的数据以节省空间,但是它不保证没有重复的数据出现。
SummingMergeTree会把行主键相同的行合并为一行,计算求和值,该行包含了被合并的行中具有数值数据类型的列的汇总值。
AggregatingMergeTree在合并分区的时候按照定义的条件聚合数据,将需要聚合的数据预先计算出来,在聚合查询时直接使用结果数据。

三、 京东小程序自定义数据分析的整体架构

了解了ClickHouse相关特性后,接下来介绍完整的京东小程序自定义数据分析的技术方案。

整体的自定义数据分析功能主要包含自定义数据上报、数据加工计算以及数据存储三大层次结构。其中最核心的问题是上报的数据如何基于自定义的配置规则进行匹配关联查询。而解决办法是在上报的数据记录中可以采用一个event_id(事件id)来标识某次上报请求数据,然后将业务字段放在map结构中,如下数据结构所示,这样可以实现业务数据字段的横向拓展,又能轻松定位到上报的数据记录。

上报数据的通道主要包括网关http实时数据通道以及子午线客户端埋点通道,将这些数据统一下发至实时数仓或者HDFS离线数仓。
通过中间层的数据流转,执行Flink实时计算或者MapReduce的离线计算,从而对原始的上报数据进行过滤、加工计算,最终批量写入至ClickHouse来实现数据的最终持久化存储。
至此,可以基于前端界面上配置的自定义事件和查询指标、过滤条件、分组条件等自定义查询规则,实现数据的在线查询分析。效果展示如下图所示。

四、 京东小程序自定义数据分析的流程设计

那么,规则引擎服务如何基于自定义规则动态解析处用户上报的数据的呢?规则引擎的执行流程主要包含两部分,包含自定义数据上报属性的配置写入以及自定义数据分析两个核心流程。
首先,需要将上报的属性配置保存至数据库进行持久化存储,当进行实时数据查询时,会先获取以上的事件规则和指标,之后,规则引擎会构建查询sql脚本推送至执行引擎,执行引擎下发sql脚本至ClickHouse集群去执行数据的查询并返回结果至前端,最后,异步将执行结果写入缓存,并设置数据有效期,便于提升下次查询效率。整体的解析执行流程如下图所示。

五、 京东小程序自定义数据分析的表设计

ClickHouse的表分为本地表和分布式表,分布式表是一个逻辑上的表, 可以理解为数据库中的视图, 一般查询都查询分布式表。分布式表引擎会将我们的查询请求路由本地表进行查询, 然后进行汇总最终返回给用户。本地表是实际存储数据的表,本地表和分布式表的关系如下图所示,在写入和读取数据时通过nginx实现请求的负载均衡,防止出现写入和读取不均衡的情况。

以京东小程序自定义点击事件的数据统计场景为例,我们创建对应的本地表vapp_analysis_local和分布式表vapp_analysis_dist如下图所示。
本地表:

分布式表:

举例说明,根据京东小程序点击事件的数据存储特点,我们做了如下的表设计:
设置主节点数和副本数。shard属性设置节点的主数据节点数,replica设置节点的副本数,从而保证数据存储的多副本高可用。
选择分区字段。ClickHouse支持分区,分区字段是每张表整个数据目录最外层结构,可以很大程度加快查询速度。具体的DDL操作关键词是 PARTITION BY,指的是一个表按照某一列数据(比如日期)进行分区,对应到最终的结果就是不同分区的数据会写入不同的文件中,在我们的业务场景中是按照数据的上报时间取年、月、日按照天来进行分区的,toYYYYMMDD(report_time)。
设置排序规则。设置合理的数据排序规则可以提升数据的查询效率,数据会按照设置的排序字段先后顺序来进行存储,在进行聚合计算时也会按照聚合条件对相邻数据进行计算。在我们的业务场景中采用的是小程序的AppID来作为排序的规则,小程序AppID是每个小程序的唯一标识,在查询数据时绝大部分场景会以AppID的维度进行数据的查询。所以,采用AppID作为排序字段可以很大程度上提升我们的数据聚合运算效率。
设置表引擎。在点击事件的场景中,我们设置的支持多副本的ReplicatedMergeTree引擎,可以支持数据的多副本存储,保证数据的高可用。
在以上的表设计中,content字段非常关键。我们将上报的自定义数据存储到表中的content字段中,并以json结构进行存储,这样即可支持上报字段的水平拓展。当规则引擎将动态生成的sql脚本下发至Clickhouse执行查询时,利用Clickhouse的json解析函数JSONExtractString进行取值转换,这样就可以非常容易得到我们想要分析的指定的业务字段。
举例说明,当我们想从京东小程序点击事件表中获取事件编码为applets_buy的金额字段amount时,基于规则解析引擎构建并下发至ClickHouse的动态脚本即为如下形式,这样便可实现上报字段的动态提取。

六、 京东小程序自定义数据分析的监控

在整个自定义数据分析的链路中,涉及的环节较多,需要有良好的监控机制,来保证系统功能的稳定运行。
针对MQ消息队列、Flink实时计算任务、ClickHouse存储等中间件的监控,我们采取的是Grafana提供的可视化监控能力。如下图所示,这样可以直观地看到诸如CPU、内存、磁盘的I/O、磁盘使用率等情况。

同时,针对京东小程序运行时的监控,我们提供了一套完整的监控告警机制,支持配置自定义告警规则,来帮助我们及时发现京东小程序自身异常页面数据、性能数据以及网络请求数据等异常数据信息,目前已可以监控到线上所有小程序的异常数据和性能运行情况,以单个小程序为例,监控的情况如下图所示。

基于以上两种监控手段,可以帮忙我们时刻掌握京东小程序在整个链路中的性能数据的波动、及时发现性能瓶颈、迅速定位运行中出现的各种问题,从而为整个京东小程序的业务发展保驾护航。

七、 总结展望

京东小程序自定义数据分析服务所提供的高效灵活的处理能力,不仅极大地提高了京东小程序数据平台的完整性,也为持续沉淀行业业务数据提供了完善的保障,预计首批落地支持50+核心小程序的业务自定义数据上报、分析及可视化,完整串联用户在小程序内外的行为路径,支持商家精细化运营的需要。
京东小程序数据能力已经完成了从0到1的突破,未来将会致力于打造京东小程序智能数据分析模型,从而实现从1到N的飞跃。最终帮助更多京东小程序商家不断优化运营策略,降低数据分析成本,提升业务产能及效率!