合作机构:阿里云 / 腾讯云 / 亚马逊云 / DreamHost / NameSilo / INWX / GODADDY / 百度统计
首先介绍下小米销售数仓,包括发展历程、销售数仓定义、数据获取使用、销售数仓的内容和规模。
在 2019 年前,小米的中国区、国际部等业务数据团队在进行独立的数仓建设,这个时期是烟囱式的开发。随着业务飞速发展,在集团技术委 ABC(AI、Big data、Cloud)策略的指导下,开始建设统一的销售数仓。在 2020 年,完成了离线销售数仓的建设,同时在筹备实时数仓的建设。2021 年,实时数仓建设完毕,随着后续的业务和技术升级,进入了迭代优化和数据应用阶段。
小米的销售数仓整体上就是存放整个公司销售数据的仓库,包括了订单数据、物流数据、门店数据、用户行为数据及商品数据,并按照维度建模和规范进行建设的高效数据集合。
上图是销售数仓的场景图,数据主要来自于两个部分,一是在线业务数据,主要是订单系统、商品中心(小米的所有商品进行管理的地方)、门店系统(线下门店进行管理的地方)、售后系统和进销存系统。同时也有一些日志采集数据,经过销售数仓的处理,划分为不同的主题进行建设。销售数仓整体会进行元数据管理,目标是做到全域的元数据管理。最上层是数据应用层,包括集团数据看板、三区运营的看板、实时大屏、大促战报和数据挖掘。
销售数仓数据的获取主要通过以下三种方式:
数仓的使用形式有多种,包括传统的离线 Hive、数据湖 Iceberg、实时消息队列 Talos、OLAP 引擎、即时查询等。
销售数仓的目标是为公司提供准确好用的销售数据。在区域方面,包含全球的业务;在品类方面,包含手机、笔记本、大家电、生态链等;在渠道方面,包含小米网、商城、米家、三方平台等。我们的日单量在千万级别,每天会处理上亿条日志数据。
在进行数仓建设时,首先是梳理业务,找到核心业务逻辑,对业务过程进行认识和理解,并在数据库中找到相关的数据表。在此基础上,站在更高维度对业务流和数据流进行汇总和分类,划分好主题域,便于后续的管理。然后进行事实表和维表的梳理,借助数据百科进行指标梳理,以具体的业务为核心,指标与维度同等重要。接下来对数仓进行建模,按照维度建模方式组织数据,在这个过程中需要注意分层和规范。最后就是物理实现,这个环节重点关注的是开发规范、交付物、质量等
接下来介绍数仓分层方式。数仓分层最底层是 ODS 层,它是贴源数据,与业务数据保持一致。在 ODS 之上是 DW 层,DW 层可以细分为两层。一层是 DWD 基础数据,主要做清洗和规范化,不对数仓团队外部开放使用。另一层是 DWM 层通用数据。基于 DWD 的数据做关联和聚合,会将核心的逻辑实现放在这一层,用于提升公共数据的复用性,可以开放给外部团队使用。数仓中还有 DIM 层(维度层),DM 层(宽表层),ADS 层(应用数据层),以及 TMP 层(存放临时表)
在数仓建模过程中,需要遵循以下一些基本的建模原则:高内聚低耦合,公共逻辑下层,成本与性能平衡、一致性、数据可回滚。
将业务相近的数据设计为一个逻辑模型或者物理模型。例如订单有很多来源,包括小米商城、小米网、有品商城以及三方数据等。在 DW 层会整合为同一个订单表,同时会对一些缺失字段进行默认处理,保证所有来源的数据最终在 DW 层是统一的,从而实现高内聚。订单和物流被划定为不同的主题,以减少其耦合度。
前面介绍数仓分层时,指出公共逻辑要尽量放在 DWM 层处理,对下游使用方尽量屏蔽复杂的业务逻辑,从而做到口径统一。例如在订单处理过程中,会有很多无效的订单,识别无效订单的核心逻辑在 DWM 层,这样下游业务方就可以直接使用。
一定的数据冗余,虽然可能带来成本增加,但查询性能可以得到提高。例如在区域维表设计中,针对国家、省份、城市、区县,通过一个区域层级字段将其分类,虽然数据是冗余的,但用户使用起来会比较方便,并且查询更快速。
在数仓建模过程中,要保证字段含义和命名规范是统一的,这样可以降低理解和使用的成本。
要保证数据可回滚,在不同时间去执行数仓的调度,针对历史数据计算出的结果是一致的。
那我们是如何进行指标管理呢?在小米内部会通过 OSM 模型,根据公司的目标和策略,通过数仓中的度量值进行考核。
例如 2023 年的目标是手机出货量要达到 X 万台,相关策略是要设计好产品,提高用户购买;同时严控质量,减少质量问题带来的影响。基于目标和策略,在销售数仓中通过两个度量值来衡量,一是手机妥投数量,这个数值要尽可能高;二是手机售后退货数量,反馈质量情况。
指标生产是基于 Hive 离线数据、MySQL 在线数据、分析数据进行建模,建立语义模型,再进行审核认证,发布到集团指标库,与数据百科进行联动。在指标消费侧,用户可以通过数据百科进行查询指标口径详情、上游血缘、维度等,数据百科与公司的 OA 工具进行联通,提高指标易用性和使用效率。
小米的销售数仓采用的是 Lambda 架构。销售数据是集团数仓中的核心之一,内部关注度高。如果是流处理,部分情况下无法达到百分之百的准确性,因此需要通过批处理,去保证 T+1 数据的准确性。在批处理层使用 Spark 加 Hive 去处理离线数据。在流式处理层,使用 Flink 加消息队列 Talos。在 DW 和 DM 层,会通过 Hologres 进行维表的加速查询。最终再把这两部分数据进行联合,提供给下游业务方使用。
我们在处理销售实时数据中,会遇到各样的问题,这里介绍下实时数据流状态过期问题的解决方法。在实时数据中,销售订单主要分两部分。第一部分是订单事实表,第二部分是订单明细事实表。订单中所有的状态变更都体现在订单事实表,而订单明细数据在第一次创建之后,就不会再发生变化。大家都知道,实时计算消息队列的保存时间是有限制的,通常会设置一个时间周期。Flink 也有计算状态的保存时间,在一定时间周期后计算状态会过期,需要注意的是,由于订单明细不再变化,如果一些订单主表的两次状态变化时间大于状态过期时间,这时候销售相关指标是失准的。
实践中是通过引入一个离线流,在订单和订单明细上各自去识别这部分过期数据,通过一个离线数据的消息队列,与原始的实时数据流进行合并,去重后下发到下游进行处理,大幅度提高同类场景下数据准确性。
但是这样会引发另外一个问题,即批处理思维方式带来的物流指标异常。
以物流场景为例,一些国际业务在商品出货后,由于距离较远或者报关审批等流程,会导致部分货物可能三个月后才发生一个状态变更。物流主表记录物流状态的变更,物流明细表以及离线的补充物流明细表会进行合并操作,之后对这两部分进行去重,去重后的结果再与物流主表进行关联,然后下发进行其他的处理逻辑。这是一个典型的离线处理思维。上述处理方法忽略了一个重要的环节,即 Flink 中算子 state 的保存机制。
在补离线流的时候,由于补充离线任务本身也需要调度时间,导致数据可能无法及时精准的补进去,为了准确的补充离线数据,会多补充一部分数据。在 RANK 算子下发时,多补的这一部分数据,会导致实时流中的明细数据不过期,即离线数据流跟实时数据流进行合并和排序操作会使实时数据中的原始流过期时间进一步延长,不会下发对应的明细数据到 join 算子。实际解决是通过利用 Flink 中的处理时间,按照物理明细表的业务联合主键下发最后一条数据,主要的解决思路就是深入理解实时计算过程,避免受离线开发思维影响。
接下来介绍一下基于 Iceberg 的存储批流一体方案。
主要是将离线处理中的 Hive 和实时处理中的 Talos 全部换成 Iceberg 去处理。选择 Iceberg 的原因是其对结构化和非结构化数据都有很好的支持。小米有一些非结构化的三方数据以及一些跟谷歌合作的 BQ 埋点日志,这些数据比较复杂,把这些数据存储在 Iceberg 中会比较方便。Iceberg 支持事务写,在其变更过程中,不影响下游业务读取数据,这方面 Hive 是做不到的。另外小米计算平台团队通过 merge into 语法,实现了对 Iceberg 数据的高效修正,使得离线和实时可以高效地相互融合。
但这个方案也存在不足之处,由于 Iceberg 的事务提交依赖 Commit,但是在实时写入中每次 Commit 的速度会依赖 Checkpoint 设置的时长,所以无法做到秒级别的实时。
下面介绍销售数仓能力层,即数仓经过一定的建设和升级,逐渐沉淀下来的一些公共能力。
首先是统一的数据架构。准实时数据需求是基于 Iceberg 的分钟级流批一体处理方案;在实时方面,是基于 Flink + Talos 的秒级处理方案及离线批处理方案。
数仓规范在数仓能力层中举足轻重。日常工作中非常重视具体的开发过程和规范,尤其是对一些新同学,规范是必要且实用的。通过数仓开发和质量规范,会统一表命名方式、字段命名方式、数仓分层等,配置 DQC 相关的完整性校验、一致性校验、空值率校验。
数据安全是数仓能力建设的一个重要方面。一是通过合规管控,所有的数据生产环节都严格遵守国家的法律法规。在公司内部有质量部、隐私委以及法务部会对所有环节进行监控。二是会进行安全分类,即按照数据的敏感度和重要性将数据进行分类。三是在权限控制方面,会严格规范数据流程,在每个部门都会有对应的安全负责人来负责最终的安全校验。在审批过程中,会遵循权限最小的原则。核心研发人员和使用人员,签署数据保密协议。四是集群隔离,小米是一个国际化公司。在国外会将机房部署在当地,并且机房之间的数据明细是不允许传输的。对一些汇总的指标,经过安全负责人的审批之后,可以传回国内进行分析。在欧洲的数据业务,会严格遵守欧盟的 GDPR 条例。针对海外数据,会成立国际数据运营中心,本地开发部署和运维。
数仓能力建设的一个重要环节就是指标应用。具体的指标应用是数据百科,如下图右侧所示,数据百科中包含全部数据口径的描述、基础信息、维度的拆解和相关指标。在指标口径上会严格指定权限审批的负责人,明确整个指标的详情。下游可以通过数据百科,快速了解相关指标。部分指标会和集团数据看板进行联动,提供给集团的管理者使用。
最后进行一下总结和展望。
经过几年的建设和应用,我们已经基本建成了离线销售数仓,公司的运营和管理层都在深度且广泛的使用销售数仓数据。团队内部沉淀了数据架构和数仓能力规范,会不断与业界进行交流学习,探索最佳实践案例。
销售数仓未来的两个趋势,一是数据的价值化,二是指标的实时化。由于目前公司处于快速发展的过程中,数据部门和业务需要更紧密地结合,充分挖掘数据的价值,真正将数据的价值体现出来,去赋能业务,为公司带来业绩的增长。目前实时化是一个大的趋势,数据以及业务的变化,都需要及时体现出来,做到高实时性。
A1:我们是通过离线的方式去对数据准确性进行修正。在离线里面会跑全量数据,即每次跑的时候是从 ODS 层采集到 DW 层的处理,以及 DM 层,每个分区里面都是全量数据。这一块计算会比较重,用来解决状态经常变化的问题。
A2:我们会有一个平台部门去负责整体的数据权限,我们在每一层,从ODS到DWD、DWM都会有权限管控。
A3:目前在部门内部 Kudu 是将要被替换的状态。因为 Kudu 是一个相对小众的产品,运维成本会比较高。我们正在用阿里的 Hologres 去替代 OLAP 引擎,包括Kudu 和 Doris。
目前在我们的离线和实时数据生产中,会使用Doris去加速结果表,我们会把一些中间结果或者最终的汇总数据存到 Doris 里面(主要是汇总数据),之后利用 Doris 的 OLAP 能力去对查询进行加速。
A4:我们将 DWD 和 DWM 统称为 DW,都是明细层。DWD 主要是进行规范化,把可能不同的异构数据统一到 DWD 来。在这个过程中除了 ETL、规划化、标准化之外,不会进行特别复杂的操作。在 DWM 层我们会加工一些公共的复杂的逻辑。DWM 层也是明细数据,是把多个 DWD 表做关联,生成的明细宽表。
A5:我们的 ODS、DWD 以及 TMP 层是不提供外部访问的,其它层基本都可以对外部提供读权限。DW 层例如 DWM 是可以提供给外部访问的。因为 DWM 已经进行了逻辑的封装,用户使用 DWM 通过简单的计算就能得到我们在 DM 中最终得出的指标。
A6:不是,我们是存在一块的。
TOP