重塑数仓开发模式:物化视图与逻辑数据集的应用

大数据
文章详细介绍了逻辑数据集和物化视图的配置、运维、查询改写以及ETL任务生成与调度等关键技术手段。

小红书在大数据处理领域引入了逻辑数据集和物化视图技术,解决了传统架构中 APP 表复用度低、单表BI数据集可扩展性不足、宽表数据集看板查询性能差等问题。这些技术通过优化数据处理流程,平衡了数据通用性和查询性能,有效提升了数据处理效率和查询响应速度。文章详细介绍了逻辑数据集和物化视图的配置、运维、查询改写以及ETL任务生成与调度等关键技术手段。

通过这些创新实践,小红书在数据集收敛程度、看板查询性能方面取得了显著提升,为未来数仓智能化建设奠定了坚实基础。

01背景

2004年谷歌发表了一篇《Mapreduce》的文章,从此开启了大数据处理的时代。随后的二十年,中国移动互联网逐步发展壮大,数据的分析和处理在互联网公司中的地位越来越重要。移动互联网产生了海量的埋点日志,大数据技术在这样的数据体量下得到了快速的迭代与发展。在这个过程中,各大公司逐步形成了一套标准的数据处理架构。从逻辑层面,数据处理流程可以分为数据收集、数据处理和数据展示3个过程。数据处理流程分为5层ODS、DWD、DWS、DM、APP。从引擎角度,数据处理基本都是在spark 批处理中完成,而对外的数据应用基本依赖的是 OLAP 引擎。产品层面,数据处理一般由离线调度平台来负责,数据应用会包含公司内部的数据产品和BI分析工具。

图片

小红书数仓在此基础上,向产品运营分析师推广了自助数据集的使用。核心目的就是收拢数据的出口方式,规范化指标定义,提升数仓数据集的权威性和覆盖度。这个过程中我们遇到两个问题:

  1. 单表BI数据集可扩展性不足。比如相同业务下不同方向的分析师、产品和运营往往需要从不同的角度做数据分析。不同的角度也就对应了不同的实体维度,如果将所有维表字段都放到宽表当中,会造成宽表字段信息过分冗余,难以维护和检索,此外每次新增分析场景或者修改维度定义,也势必需要数仓工程师对表进行修改。随着一个数据集的使用场景越来越多,数仓工程师的压力也会增大。
  2. 基于宽表数据集的看板查询性能较差。大量查询迁移到核心数据集之后,越来越多的业务会基于核心数据集直接搭建看板,由于核心数据集本身的数据量较大,并且看板指标通常会查询较长周期的数据,因此相比于APP表,直接通过宽表数据集搭建看板的这种方式查询性能更差。

1.1 问题分析

受限于当前的标准处理模型,数仓很难保证同时满足数据通用性和查询性能的要求。随着小红书业务的快速发展,数仓对外出口的数据集越来越多,为了收敛指标定义、降低数仓的运维成本。我们开始考虑如何在不降低查询性能的前提下,提高数据集的通用性。

当前的 RedBI 平台,两种主要的数据集,一种是单表数据集,另一种是 SQL 数据集。SQL数据集类似于一种逻辑视图,用户在 RedBI 查询 SQL 数据集的时候会将这段 SQL 当作一张表进行查询,因此 SQL 数据集的查询比较复杂,查询性能相对于单表会差一些。

SQL 数据集一般是一个主表关联多张维表,其性能下降多数是来自于关联操作。虽然 StarRocks 相对于 Clickhouse 来说Join性能会好很多,但是随着 Join 的维表的数量增加,其性能依然会下降很明显。尤其是当用户的查询如果只涉及到主表字段的时候,SQL 数据集没办法做到查询裁切,会比单表查询更慢。

图片

如上图所示,SQL1 里只包含Table1 的字段,那么就只应该查询 Table1。SQL2 只包含 Table1 和 Table2 的字段,就应该查询 Table1 和 Table2 的关联结果。对于 SQL3,因为涉及到 Table2 和 Table3 的维度字段,所以应该查询 Table1,Table2 和 Table3 的关联结果。因此如果我们可以对查询做到裁切,就可以有效减少无意义的计算,提高查询效率。

SQL 数据集的性能差的另一个原因是数据集太大。如果要保证达到和 APP 层表一样的性能,那么就需要生成类似实体表的加速数据--物化视图。虽然物化视图和App表都是为了查询性能创建的数据集,但是物化视图和 APP 表相比,其优势主要体现在,物化视图不会增加模型的数量,只是查询到原始数据集的查询会路由到物化视图,而App表会增加模型,用户在查询的时候必须得指定 APP 表。所以物化视图可以在保证模型通用性的前提下提高数据集的查询性能。

由于业务的查询大部分遵循某种规律,搭建必要的缓存,也可以大幅度降低查询的时间。

02 数仓开发新范式

2.1 总体方案

经过上述的分析,数据集变为宽表+维表的模式。宽表定义了一个数据集可以查询的粒度和指标,维表定义了可以拆解的维度。这样一来,每一个业务都会只会产出有限的数据集,数据集个数得到极大收拢,指标的定义也会更加清晰。

图片

这种宽表+维表的数据集,我们称之为逻辑数据集。逻辑数据集相对于 SQL 数据集来说加入了查询裁切的功能,一般情况下不同目的的查询都只会使用到宽表+部分维表,一个数据集适用的分析场景由维表数量决定,但是查询性能只和当前的分析需要有关。在保证使用范围的情况下,保证了最小的查询范围,无额外性能损耗。

但是随着数据集的通用性提升,越来越多的数据集开始应用于看板制作,相对于自助查询,看板查询的性能要求会更高,并且并发也会更大。自助查询用户会的查询比较灵活,所以对查询的耗时容忍度也更高,一般可以接受20s以内的查询性能。但是对于看板来说,一个看板中可能涉及到几十个图表,每个图表又会涉及到多个查询,相当于同时有上百个查询打到 OLAP 引擎,如果一个查询的耗时还是20s,那整个看板展现出来的时间必然很漫长。此外很多看板查询的显示周期很久,可能达到1年以上,直接查询底表大概率会导致查询失败。

因此,我们需要针对数据集建立对应的物化视图,物化视图基本可以覆盖看板中的绝大多数查询,由于物化视图的数据量较少,所以可以将单个查询的执行时间压缩到4s以内,并且可以将之前查询失败的报表查询出来。

下图是我们的实际技术架构。

图片

DWS 层的数据是进入BI工具的最后一层,这一层我们使用Iceberg存储。Iceberg 作为一种数据湖存储格式,可以使用Spark进行读写,并且也可以使用StarRocks读。实验已经证明,相同资源情况下,StarRocks on Iceberg 的查询性能在绝大场景下和 Clickhouse 相当甚至更优,并且Iceberg 不和 OLAP 引擎深度耦合,其扩展性能也更好,完全可以做到存算分离,解决存储焦虑。

在这层之上就是 RedBI(小红书内部的BI平台)中的逻辑数据集,逻辑数据集是数仓对外的“产品”。

在逻辑数据集之上就是查询加速层,查询加速层中的第一层是物化视图,一个逻辑数据集可以建立多个物化视图,需要保证覆盖大多数的看板查询。相对于传统CUBE类型的APP表,物化视图的优势主要体现在两个方面:

  1. 计算复杂度低。CUBE计算本质上需要将数据复制n份(依据CUBE个数),然后进行聚合操作,如果CUBE众多,那么中间的数据膨胀会相当严重,甚至会引发执行超时和报错。而物化视图本质上是对宽表的聚合,所以不存在中间数据膨胀,执行性能会更好。
  2. 通用性高。CUBE表一般属于APP表,和BI宽表数据集本身没有绑定关系,那么这个CUBE表很可能只能服务于特定的看板,当有另外的看板在用到类似的维度分析时,如果没有数仓工程师凭借丰富经验做推荐,大概率不会复用该APP表。而物化视图本身是绑定到数据集的,所以只要可以命中物化视图的查询格式,那么不论查询来自哪里,都可以进行复用。

查询加速层的第二层是缓存,尤其是在固定查询的场景下,缓存可以极大缓解对集群的查询压力。

下面着重介绍逻辑数据集和物化视图两大内容。

2.2 逻辑数据集

2.2.1 执行流程

图片

逻辑数据集核心包含两部分:数据集配置和查询裁切。

我们使用图形化界面对数据集进行配置,界面中的节点是一个数据集或者是一个 SQL,节点与节点中间按照关联键进行连接。配置可以告诉系统只能沿着关联键进行裁切,而不可以对节点内部进行裁切。

开启查询裁剪需要同时满足以下两个条件:

  1. 节点与节点之间是 LEFT-JOIN 连接
  2. 右表关联键不存在重复值

其中,右表连接键唯一性的判断,会在数据预览步骤中进行,和预览结果一起返回。调用数据预览接口时处理如下:

图片

2.2.2 查询裁切步骤

1. 从数据集元信息中,获取可以进行裁剪的节点列表。

2. 根据 DSL 中的维度、指标、筛选等字段,把本次查询用到的所有字段展平,把字段对应的节点 id 排除,从而得到本次查询可裁剪的节点列表。

3. 所有的节点列表去掉可裁剪的节点,得到优化后的节点列表。

4. 然后根据连接条件把相关的表 Join 起来,作为一个整体数据集执行BI查询。

图片

2.3 物化视图的技术手段

2.3.1 工具选择

StarRocks 和其他 OLAP 引擎一样,也具备物化视图的功能。StarRocks 的物化视图分为同步物化视图和异步物化视图。同步物化视图可以保证数据集的一致性,异步物化视图需要设置刷新周期。但是在应用到生产环境的时候,就会发现物化视图的调度对集群会造成很大的压力,并且也无法满足很多业务诉求。

  1. 同步物化视图的开销较大,数据只要发生变化就会进行刷新,这样在数据集每条导入的过程中就会涉及大量的新增操作,导致大量物化更新,进一步会对集群造成巨大的压力,甚至导致集群崩溃。
  2. 而异步物化视图必须设置刷新周期,对于BI数据集来说,数据基本是天级就绪,而且每天数据的就绪时间并不固定,异步物化视图要么需要设置较短的刷新周期,要么天级刷新,但是刷新时间较晚,这样无法满足业务查询性能的诉求。
  3. 此外 StarRocks 是一个 OLAP 引擎,和 Spark 不一样的是,不存在类似于 Yarn 的作业调度管理。那么当大量的物化视图开始调度的时候,很难去合理安排物化视图的调度顺序,也无法根据当前的资源情况给不同的物化作业分配不同的资源,因此在先前的 StarRocks ETL 处理中,我们会遇到因为资源抢占导致的作业失败现象。随着物化视图越来越多,物化视图的调度成功率必然也会劣化。
  4. 对于 UV 类的计算来说,需要物化成 BITMAP 类型,这就需要对消重字段进行编码,StarRocks 中没有很紧凑的编码方式,官方也建议用户自己映射编码,一方面 StarRocks 中的物化视图无法对 UV 进行物化,另一方面无法得知用户的编码表。

因此我们在 RedBI 中完成了物化视图的功能,相比于原生的物化视图:

  1. RedBI 的物化视图可以充分利用数据平台已有的作业调度能力。
  2. 此外,看板也是在RedBI上搭建的,RedBI 本身可以获取到查询的所有信息。
  3. RedBI 可以使用数仓的编码表生成对应的 BITMAP,进而完成对uv类指标的物化。

2.3.2 实现方案

图片

当前业界在设计物化视图功能的时候,都聚焦在了查询的改写能力方面,尽可能保证物化视图可以适应越来越多的查询场景。但是实际在生产环境中我们发现物化视图的配置和运维流程会更加重要。和物化视图相关的整套产品功能包括以下几类:物化视图配置、物化 ETL 任务生成与调度、物化查询改写、物化治理。

  • 视图配置:通过RedBI中的物化配置 UI 界面完成视图配置。
  • 物化运维: 监控物化视图当前的新鲜度,保证物化视图的定义依然可以被大部分查询命中。
  • 查询改写: 对查询参数进行校验,将符合物化规则的查询请求路由到合适的物化视图表并完成查询改写。
  • ETL 任务生成与调度:生成物加速 ETL 任务,实现数据预计算并存储,将数据固化为更小的物化视图表。

视图配置

大多数的 OLAP 引擎的物化视图功能都假设用户已经对物化视图的结构有了清晰的设想。那这样的物化视图从根本上来说依然是数仓在建设APP表的思路,即先有模型设计,然后才会产生物理模型。但是这样的物化视图本质上并没有减轻数仓的工作量,也没有改变数仓的工作方式。如果要最大可能消灭APP层,物化视图的模型设计就不能强依赖数仓的模型设计能力。因此我们的物化视图主要是通过数据集的看板和自助分析模版来生成。

理想的状态下,物化视图可以按照数据集的看板和模版自动生成。但是完成自动化生产物化视图的过程中,我们首先要解决用户手动创建的难点。用户手动创建物化视图依赖的核心功能包括

1. 需要物化的内容。在我们的场景下,就是看板和自主分析模版。看板和自主分析模版的查询热度作为辅助指标可以使用户知晓哪些看板的物化更有价值。

2. 调试过程。用户不大可能一次性就可以创建出没有任何问题的物化视图,物化视图要想发挥价值,必然需要保证性能和命中率两个方面。

  • 物化视图的命中率是我们依赖历史查询进行的分析生成的。如果物化视图的命中率太低,那么对于查询性能的改变就微乎其微。此外,通过看板和自主分析模版生产的物化视图结构可能因为功能不支持或者物化周期的原因命中率低,需要用户进行手动调整。
  • 物化视图的数据量要有限制。如果用户将所有看板和自主分析模版都加入物化,必然可以保证很高的命中率,但是这样的物化视图也接近于明细了,那物化视图的查询就会变慢,物化视图查询加速的能力也就丧失了。因此调试过程中需要显示物化视图的数据量,以保证物化视图的性能。

提需过程

我们需要在什么时候决定要对什么内容创建物化视图进行加速呢?仅仅依赖数仓的经验肯定是不靠谱的,因为数据集的使用方可能是分析师、产品和运营。这些使用方往往会根据自己的需求去搭建看板,数仓是完全不清楚业务具体是怎么使用的。

数仓建设APP表的流程如下图所示。业务方(一般是分析师或产品)首先提出数据需求,然后需要和数仓进行需求对齐,使数仓可以理解业务的诉求,数仓确认需求之后就会涉及对应的 APP 模型。建设好 APP 表之后还需要和业务方进行调试,保证指标符合预期,这个过程如果不符合预期,得多次和业务方进行沟通对齐。

图片

如果物化视图依然沿用这一思路,对于数仓和业务方来说,物化视图和 APP 表就没有任何差别,因为根本上没有降低其中的沟通成本。

业务方对于看板的样式以及指标是最清楚的,一旦涉及到沟通,必然存在信息损耗。因此我们将提需流程改为了如下方式。可以看出新的提需流程是先由业务创建出看板,然后将需要物化的内容提需给数仓,数仓完成对应的物化需求。这个过程中,需求文档不再是一个充满文字和表格的文档,也不需要人工讲解,而是一个真实的看板图表。配合物化视图的配置功能,可以轻松完成物化视图的搭建。

图片

物化运维

物化视图并不是一成不变的,物化视图的变动一般来自于三个方面:

  1. 数据集中的表发生了变更,进行了数据回刷。这种情况下,物化视图本身不需要进行更改,只需要回刷即可。当上游数据集完成回刷的时候,我们会自动调度起下游的物化视图任务,回刷对应日期的实例。
  2. 看板和模版发生修改,可能会导创建的物化视图失效。这种情况下平台一方面会提醒修改人图表是否无法命中物化,另一方面会通知到数仓发生变更的看板和模版,数仓需要重新测试物化视图对这些看板模版的命中率,并且更新物化视图结构,以保证物化视图命中率。
  3. 数据集字段定义发生变更。RedBI 数据集中除了表的原始字段外,还有很多依赖原始字段生成的计算字段,这些计算字段如果发生变更,那么按照之前字段定义创建的物化视图也可能失效。因此当数据集的字段定义发生变更的时候,平台会提示数据负责人失效的物化视图和影响的看板图表,另一方面也会通知数仓更新物化视图。

查询改写

改写流程:

图片

改写采用了基于 SPJG(SELECT-PROJECT-JOIN-GROUP-BY)模式的结构信息来进行透明改写的算法,即将原表的sql查询替换成物化视图的查询。物化视图的改写基于 LodQuery,改写时基于物化配置中存储的字段表达式列表进行匹配和替换。下面是改写步骤:

  • 用户发起查询时,BI 界面的查询配置会转化为 QueryDSL,QueryDSL 经过解析 Lod 表达式、字段拆解等,然后转化为 LodQuery 对象。

LodQuery抽象

RedBI抽象的 LodQuery 大致包括以下部分:

• dimensions:查询维度,指定了需要查询的聚合粒度

• measures:查询度量,指定了在聚合粒度为 dimensions 时需要查询的度量字段

• from:查询表信息,指定了多张原始表、自定义SQL表、逻辑数据集对应的主表和多张维表的定义及关联方式,存在嵌套结构。

•dimensionFilters:维度筛选,指定了对明细数据的筛选方式,需要指定Pill和FilterPredicate

• measureFilters:度量筛选,指定了对聚合后数据的筛选方式,需要指定Pill和FilterPredicate

• orderBy:排序,指定了查询需要按哪些字段进行排序

• offset:查询偏移量,指定了结果需要偏移多少行数据

•limit:查询数据量,指定了结果集的数据量上限

  • 基于数据集物化配置获取对应物化视图列表,并根据优先级排序进行物化命中的校验。
  • 命中物化则将 LodQuery 改写为物化查询的 MaterializedQuery。
  • 对 MaterializedQuery 进一步优化,包括谓词下推、开窗函数处理,引擎特定函数处理等,转换为为 TableQuery(抽象语法树)。

选择基于 LodQuery 而非 TableQuery 进行物化改写的原因在于虽然 TableQuery 和 LodQuery 结构大体一致,但 LodQuery 作为 RedBI 的抽象,具有更丰富的元信息。例如LodQuery 将维度(dimensions)和度量(measures)明确分离,而TableQuery则不区分 dimensions 和 measures。此外,在 LodQuery 转换为 TableQuery 之前,尚未进行各项查询优化,例如谓词下推、窗口函数处理、引擎特定函数处理等,数据结构更加精简,这为物化改写提供了更大的灵活性和可操作空间。

  • 基于 TableQuery 生成SQL, 发送到 StarRocks 进行数据查询,并返回数据。

物化ETL任务生成与调度

物化配置信息确定之后,通过 LodQuery 可以直接确定需要聚合的维度和指标,针对 SUM、COUNT、MAX、MIN 类型的指标可以直接计算,针对比值类型的指标需要分为分子分母分别进行计算,针对UV类型的指标需要将UV类的指标转化为BITMAP。

UV 计算问题:

看板中会涉及到不少UV的计算,物化视图中要实现精确的 UV 计算,就需要建立对应的 BITMAP。为了保证 BITMAP 存储大小和查询性能,消重字段的对应的数字 id 不能太零散。紧凑的编码可以提升 BITMAP 的压缩率和查询效率。

Bitmap 背后的实现基于 Roaring Bitmap,这是一种用于保存聚合后明细数据的数据结构。它通过两级索引来保存明细数据,简而言之,通过两级索引定位到具体的 container,container 中存放着聚合后的明细数据的低16位,它有三种类型:纯数组类型的 Array container、位图类型的 Bitset container 和 RunLen 编码的位图 RunLen container。

size 小于 4096用Array container, 当 size 大于 4096 的时候,显然使用 Bitset Container 更省空间。所以当整个 size 大于 4096 的时候,Container 会从 Array Container 转成 Bitset Container,再通过 Runlen 编码后能否减少空间决定是否要转为最终存储格式 RunLen Container。

消重字段我们一般分为两类:

  1. 业务实体 id:比如用户 id、商家 id、商品 id等。每个业务都有核心分析的业务实体,我们针对这类实体id建立了对应的编码表,编码表可以将字符串id映射为紧凑的数字id。大部分的 UV 指标可以通过这类字段进行计算。
  2. 自定义消重字段:这类字段通常是通过维度+实体 id 拼接而成,比如搜索 id+搜索词+用户,这类字段的基数很大,也很灵活,很难用固定的编码表进行映射。对于这种类型的字段,我们现在只能通过特定的sql改写来解决,本文不做详细讨论。

但是含有 BITMAP 的物化视图的性能并不总是比底表查询性能好,因为底表查询数据量虽然大,但是并发也高,倾斜的可能性较低。但是物化视图按照一些维度聚合之后,可能会造成部分 BITMAP 存储的id数量太多,太分散,从而导致 BITMAP 的 union 计算耗时增加。那针对这种情况,我们从两个方面进行优化:

  1. 增加物化视图的数据条数,从而增加查询并发。
  2. 降低BITMAP的倾斜程度。

我们为id编码增加分桶,比如1-100w分一个桶,100w-200w分一个桶,这样一方面增加数据条数,另一方面可以减轻数据的倾斜,并且可以有效提升BITMAP的压缩效率。

经过分桶之后的物化视图,查询性能平均可以提升5倍。

03 收益

逻辑数据集上线后,已经替代了大部分sql数据集。截止到发文,逻辑数据集部署100+个,查询占比达到30%,已经超过SQL数据集。

部署物化视图的数据集为40+个,涉及交易、直播、广告等多个业务,平均查询耗时降低80%,并且平均命中率为30%。

04 展望

当前逻辑数据集基本取代了 SQL 数据集,但是针对复杂的处理逻辑还无法覆盖,比如对于直播业务,用户通常会同时看主播的历史数据和当天分维度数据,从数仓底层来说一般是两种不同粒度的表,这种情况下分析师和产品期待的是可以使用一个数据集来完成分析,但是当前依赖 Join 的逻辑数据集显然无法满足这种查询场景。未来我们会探索将不同粒度的表结合为一个逻辑数据集的场景,以进一步减少核心数据集的个数,提高用户找数效率。

理想状态是数仓只需要加工到宽表这一层,应用层完全可以根据业务需求做自动组装,物化视图本质上就是要实现从宽表到看板或自助查询的自动化加速。不过物化视图当前还有多个方面可以进行提升。

首先,针对大基数消重指标的支持问题,未来的物化视图解决方案可能会引入更高效的数据处理算法和更强大的计算引擎。随着硬件性能的提升和分布式计算技术的成熟,物化视图或许能够以更低的资源消耗来处理大规模数据集中的复杂消重操作。

在回刷和数据修改同步方面,未来的物化视图功能可能会实现更智能、更高效的同步机制。一方面需要更智能实现物化依赖数据集的变化,有效识别出必须物化的场景,减少物化回刷频次。另一方面针对物化同步的调度能力进行优化,保证物化的执行效率和集群稳定性。

针对物化视图管理复杂性的问题,未来数仓系统可能会借助AI的能力集成更加自动化和智能化的管理工具。这些工具可以提供自动化的生命周期管理,帮助识别和清理过时或低效的物化视图,甚至合并必要的物化视图,减轻数据工程师的负担。

在展望未来时,我们希望数仓工程师会更聚焦于宽表模型设计,物化视图和逻辑数据集会将工程师从应用层建设中完全释放出来。随着技术的不断进步,不断去推进数仓智能化建设。

05 作者

黄猿(吴筱琦)

小红书数据仓库工程师,现负责渠道归因和数据任务性能优化。

儒毅(夏翔)

小红书分析平台研发工程师,现负责 RedBI 平台查询网关的开发。

雨时(张克冰)

小红书数据平台研发工程师,现负责 RedBI 平台的查询能力建设。

责任编辑:庞桂玉 来源: 小红书技术REDtech
相关推荐

2010-07-30 17:46:46

DB2物化视图

2010-08-13 10:29:35

DB2数据库

2024-04-17 07:21:52

物化视图查询加速器数据仓库

2010-08-20 13:33:50

DB2物化视图

2010-05-04 10:20:17

Oracle物化视图

2009-05-06 11:09:10

Oracle物化视图数据库

2022-07-26 15:38:58

数据仓数据治理数据团队

2009-11-17 15:59:25

Oracle物化视图

2010-07-27 14:26:08

DB2数据库物化视图

2010-08-02 13:25:23

DB2物化视图

2023-09-18 07:23:45

2009-11-17 16:47:09

Oracle物化视图日

2023-10-13 07:25:50

2025-01-09 08:22:05

2010-08-19 17:17:08

DB2数据库

2011-03-11 16:42:51

Oracle数据库视图

2021-10-13 07:23:03

数据同步仓库

2010-11-19 10:11:49

Oracle物化视图

2024-11-19 08:09:09

MySQL数据库数据

2014-12-15 09:09:30

Perforce
点赞
收藏

51CTO技术栈公众号