阿里妈妈基于 Flink+Paimon 的 Lakehouse 应用实践

摘要:本文整理自阿里妈妈的数据技术专家陈亮老师在 Flink Forward Asia 2024 流式湖仓(三)专场中的分享。分享的内容将分为三个部分:首先,介绍阿里妈妈广告业务的背景;其次,探讨阿里妈妈广告实时系统和数据湖架构的设计;最后,阐述我们在技术和业务层面从该架构中获得的收益。
一、业务背景
二、架构设计
三、整体收益
四、问答
一、业务背景
1.1 阿里妈妈广告业务介绍

简单介绍一下广告生态是如何运作的。广告首先需要广告主,因为他们是出资方。广告团队会在 DSP 等平台上创建和设置广告计划,投放计划包括目标人群、地域、时段以及预算等。广告主会选择合适的素材和创意,以吸引用户点击广告,实现广告投放目标。当所有信息在 DSP 平台上设置完成后,这些信息会同步到广告投放引擎中。
投放引擎的核心功能在于用户流量处理,流量源涵盖阿里系应用(淘宝、天猫、高德等)及外部媒体生态(字节、快手、知乎等)。引擎会根据用户在淘内的兴趣等属性实现精准广告分发。典型场景包括淘宝搜索广告推荐及信息流广告展示。
用户的搜索或浏览行为,都会产生广告曝光数据。当用户点击广告时,会产生点击数据。在电商场景中,点击广告并非最终目的。我们还需要引导用户进行收藏、加购、下单等操作。用户点击广告后,会进入广告主的商详页或店铺页进行相应转化操作。我们会收集到的转化信息,如收藏、加购、成交等,在此基础上进行进一步做转化归因分析。业界常见的归因模型包括线性、末次触点、首次触点、U 型、MTA 等模型,用于评估广告效果。所有数据评估完成后,需要将结果反馈给相关方。
在广告生态系统中,通常广告的计费依赖曝光/点击行为,曝光和点击的追踪过程可能会受到黑产攻击,导致平台或广告主的财产损失。为了保护平台和客户等,需要搭建广告反作弊体系,其中包含实时和离线的反作弊数据链路建设。同时,广告主设置的预算限制也不容忽视,我们不能让广告支出超出预算,否则广告主将不予认可。例如,如果广告主只愿意支付 100 元,我们却花费了 1 万元,那么超出的部分是无法得到支付的。因此,我们必须控制广告投放量,避免超投。整个广告生态系统相当复杂,涉及的链路很长,但数据必须准确且实时地反映给广告主,以便他们根据这些数据制定投放策略并调整预算。
1.2 阿里妈妈数据业务场景与诉求

结合上面的业务背景,这里引出妈妈 SDS 的业务场景和业务诉求。
(1)业务场景
对外的实时报表:广告主需要查看各种维度的实时数据,例如曝光量、点击率 CTR、转化率 ROI 等,以便实时了解广告的效果、预算是否需要增加或停投。
对内实时分析需求:内部运营人员等需要对广告投放进行评估,对特定的人群、商品、场景等进行各种分析,查看广告投放后的人群效果、地域投放情况以及是否存在其他问题。因此,内部也需要实时和离线的分析。
业务盯盘:对于一些关键的大促销活动节点,例如 618、双十一、双十二大促活动时段,我们需要密切关注业务变化。包括流量是否达标、预算是否充足以及效果是否理想等,并依据实时数据灵活调整运营和投放策略。
(2)业务诉求
灵活多变:阿里妈妈 SDS 对接的下游业务众多,每个出口都有其特定需求,变化迅速且迭代频繁。
稳定可靠:整个系统需要实时数据供多人查看,不能出现任何中断或数据更新延迟。延迟后广告主会立即发现并提出投诉或停投,这可能导致严重问题,比如 15 分钟内就登上热搜。
数据一致性:对于广告主而言,他们可以在多个系统上查看数据,因此数据的一致性至关重要,否则他们可能会质疑数据的准确性。
1.3 阿里妈妈数仓建设技术目标

数据时效性:从技术角度讲,广告主希望数据尽可能实时,理想情况下是及时无延迟,目前我们提供的保障是分钟级别的数据更新。
系统吞吐量:阿里妈妈这边处理的流量非常庞大,日均规模达到千亿级别,TPS 高达千万级,读写具备很大挑战。我们期望系统在特定场景下,如新业务上线后,能够迅速回放数据,将数据快速刷新至系统中,因此快速回放是一个基本要求。
稳定可靠:系统可用性≥99.9%。故障快速恢复“止血”。支持灰度发布,故障或问题往往发生在发布或变更时,因此灰度发布能力至关重要,灰度发布过程出现问题,系统能够及时回滚,避免故障影响持续和扩大。
成本效益:正如那句老话所说,“既要马儿跑又要马儿不吃草”,我们希望用尽可能少的资源支持更多的业务。同时,我们也希望减轻开发和运维的负担,让自己能够从繁重的工作中解放出来,专注于更有意义的业务。
二、架构设计
在介绍业务之后,现在让我们来分享一下我们的架构及其演进过程。首先,让我们看一下简化后的系统链路图。
2.1 为什么需要实时数仓?

从图中可以看出,简化后的链路实际上非常复杂。在最初构建实时系统时,我们的目标是速度,要求系统能够迅速覆盖业务需求。如何实现快速呢?我们使用 Flink 进行数据消费,实时数据通过类似于 Kafka 的系统写入业务系统,使业务能够迅速启动。这是一种常见的手段和方法。通过这张图,我们可以清晰地看到同一份数据如何在不同的业务系列中被展示。每一条链路代表一个业务逻辑,虽然它们共享一套代码和一系列作业,但解析和消费的数据却是相同的。
这虽然带来了一些明显的好处,但重点是我们需要关注存在以下问题:
需求灵活多变:首先,在业务层面,随着业务种类的增加,每个环节都需要维护和开发,这在灵活性和效率上构成了重大挑战。
开发成本:其次,这种开发模式类似于烟囱式,缺乏复用性,导致了重复劳动。
资源浪费:第三,所有数据都需要解析和消费,这实际上造成了资源的浪费,因为有些数据可能根本用不上,但仍然需要被解析和处理。
数据口径:第四,数据口径问题,如果在某个业务系统中忘记或未能及时更新数据口径,那么输出的数据就会出现问题。
运维成本:最后,运维方面,所有任务都需要我们自己完成,包括压力测试、性能调优和问题排查等,这些都需要投入大量时间和成本。
针对上诉存在的问题,我们提出了两个解决方案。
2.2 阿里妈妈实时数仓方案演进
(1)基于 TT 的实时数仓方案

a. 数仓分层
基于 TT(类似于 Kafka 一样的消息队列)的实时数仓方案,实时数仓包含 ODS、DWD 和在线维表。
ODS 层:业务所需日志,包括用户行为日志、广告日志,以及业务数据库中的转化消息、收藏、下单和成交等消息,都通过日志采集/DRC 系统,将数据采集到 TT 中,作为实时系统 ODS 层数据。
DWD 层:在实时链路中,系统利用 Flink 来消费 TT 数据并加工出 DWD 层数据。
在线维表:ODS 层可能会缺少一些常用的维度字段,这些字段的更新频率可能并不高,通常是按天更新。为此,我们设计了维表系统(iGraph)用以补充这些维度字段。同时,我们也会使用配置系统(diamond)补充部分信息,这些信息相当于维表信息,用于补充到 DWD 层。
b. 方案弊端
数据重复:在下游消费 DWD 层数据时,大家可能会注意到 ODS、DWD 的作业,因为业务迭代或作业 Failover 会导致数据重复。在 DWD 层,是否需要去重取决于业务需求,但大多数情况下,去重是必要的,因为不去重会导致数据重复出现,比如广告主会立即注意到数据同比突然增长,从而引发投诉。
DWS 层缺失:另一个问题是,从 DWD 层到应用层之间,可以增加一个 DWS 层,因为下层的聚合逻辑往往是相同的。但在 TT 中,由于不具备 upsert 能力,因此无法将 DWS 层的最新聚合结果覆盖更早的聚合结果。举个例子,假设时间窗口为 5 分钟,10:05 聚合一条数据写入 TT,10:10 时第二次聚合数据需要覆盖上一次聚合结果,但在 TT 中会存在两条记录。下游接入 TT 后,需要自行执行一次数据去重,这代价极高。经过测试,资源消耗至少增加一倍,且数据量大导致作业不稳定。不设计 DWS 层,则直接将聚合结果写入下游的在线存储系统,包括 OceanBase、Hologres 和 ClickHouse 三种。实时链路旨在解决时效性问题,即使有实时反作弊机制,其精准度仍不足。此外,业务上还需处理去重逻辑。
No Schema:实际上在 DWD 和 ODS 的实时链路中,我们面临的是一个未结构化的数据问题。这些数据在解析后并没有一个固定的 Schema,导致下游如算法和 BI 分析在使用这些数据时,不得不自行进行解析和计算,这无疑增加了成本并浪费了资源。
资源与效率:对于广告主而言,他们自然希望数据既快速又准确。因此,我们还部署了一条离线链路,这也是一个典型的 lambda 架构。将 ODS 层的数据同步到 MaxCompute 中并通过 ETL 加工产出 DWD 层,聚合 DWD 为 ADS 层最终同步到在线存储系统。由于需要维护离线和实时两套代码,这无疑使得开发和运维资源都翻倍。
(2)基于 Paimon 的湖仓方案

我们如何解决基于 TT 实时数仓面临的问题呢?幸运的是,从 2023 年开始,我们关注到 Paimon 技术栈,2023 年 6 月开始调研 Paimon 技术并逐步在业务中推广应用。
方案优势
主键表:本方案中 ODS 层同前一个方案一致,也是基于 TT 存储且入湖过程完全相同。但 DWD 层将原有的存储替换成了 Paimon,同时新增 DWS 层设计。Paimon 具备 upsert 操作,支持 DWD 和 DWS 层 upsert 写入实现去重,下游消费 changelog 即可。
Schema:此外,它还带来了另一个好处,即之前提到的算法、BI 以及各种运营需求的数据,现在可以直接在 DWD 和 DWS 层进行查询。过去,这需要我们提供支持,而现在,数据表已经解析完毕,数据也已就绪,可以直接使用实时和离线查询。
开发效率:实时离线统一 schema,无需再次解析开发和计算开销,实时离线代码可复用。
关于离线链路,我们之前提到需要将数据同步至 ODS 这一步骤的原因何在呢?实际上,由于反作弊机制是基于离线处理的,它必须处理一批数据,这一步骤是不可或缺的。此外,这一流程还有另一个好处,即作为备份(Backup)链路。在 ODS 层完成数据解析后,我们可以将数据反向写入到 Paimon 中。这样对于下游查询而言,它们能够查询到经过修正后的数据。如果存在修正结果,则查询修正后的数据;如果没有修正结果,则直接查询实时数据。整个流程完成后数据再同步到 ClickHouse 中,用于支持下游的高频查询。
2.3 阿里妈妈广告湖仓架构

目前我们妈妈这边的广告湖仓架构如图所示。系统架构包含四个层次和一个运维平台。
数据层:数据的最初来源目前仍然在 TT 中,整个系统依赖于 TT,所以这一部分保持不变。TT 中包含了各种行为数据、广告数据以及成交转化等数据。业务数据库中的维表数据会增量同步到 TT 中。解析完这些增量同步的数据后,会将其写入 iGraph 中。TT 数据则通过 Flink 进行 ETL 处理导入到我们的数据湖中,即 Paimon 表,包括 DWD 和 DWS 层。在这里有主备两套存储系统,双系统设计既用于异地灾备,也提供可用性和灰度发布能力。数据实时提供给消费者使用,而离线链路则有离线修正数据,这实际上是依赖于离线的另一条链路。这两套数据最终会合并在一起。
计算层:所有的 ETL 过程,包括最终的数据写入存储,我们使用了 Flink 和 MaxCompute 计算引擎。
存储层:配置主备两套系统,主备链路分别配置同步任务,确保主备同步的可靠性和独立性。
应用层:妈妈报表、BI、算法、达摩盘等应用。
运维平台/工具:系统监控、系统运维、自动压测。
这种设计实际上构成了一个三链路架构,包括两个实时链路和一个离线链路,实时链路能够支持日常的灵活切换。至于离线链路,它为整个系统提供了备份,以防 Flink 出现问题时,我们至少还有离线数据作为保障。尽管我们不希望出现问题,但我们的架构设计要求我们必须做好准备。此外,它还作为大促活动的备份方案。对于高频大规模查询,我们现在使用 ClickHouse 来处理,能够应对万级 TPS 的应用场景。对于小流量场景或更灵活的查询,我们支持使用 MaxCompute。需要注意的是,这可能会对时效性产生一定影响,可能是小时级别的。我们还在探索使用 StarRocks 和 Hologres 进行灵活的点查和分析。上游应用主要包括报表、BI 监控、算法以及实时和批量的数据洞察。这些构成了四个层次。最右侧,我们拥有自己的运维工具和平台,这是因为我们的作业规模较大,需要进行各种监控,例如组间延迟和问题检测。例如,若存在写入问题、消费问题、中间过程状态问题,或特定节点问题,这些都需要监控,因为这是一个全局监控过程。我们设计了这样的系统以应对可能出现的多种问题。我们拥有自己的实时作业运维平台和压力测试平台,因为对于大数据场景而言,压力测试是不可或缺的。由于每年流量和业务的变化较大,不进行压力测试可能会导致各种问题的出现。
2.4 Paimon 常见优化手段

前面我介绍了我们整个湖仓架构的演进过程,以及我们对下一个架构的展望。在这里,我想分享一下我们在构建湖仓时采用的一些常见优化策略。
性能优化:
强烈建议根据使用情况启用异步 Compact 功能,这能显著提升系统的吞吐量,包括单表写入的吞吐量和稳定性。
其次是调整 Checkpoint interval time,这需要根据流量情况进行调整。例如,对于流量在十万级别的系统,可能不需要调整,但对于百万甚至千万级别的系统,必须增大 Checkpoint interval time,以避免频繁 checkpoint 导致的堆积和各种反压问题。
对 Writer 节点资源的调整,这同样需要根据流量情况进行预估,比如参照 bucket 数调整并行度,在数据追溯和回刷时,这些调整尤为重要。Writer 节点的内存配置也需根据场景进行调整,因为我们的场景通常流量较大,所以需要进行调整。
最后,根据业务特点,分区的选择和设置,以及 bucket 数设置。一旦我们建立了一个 Paimon 表,之后再去调整其分区或切换到 bucket 数,都需要经历一个 Rescale 的过程。这可能需要停止系统,代价相对较大。因此,在考虑峰值情况下,我们需要评估性能是否能够满足需求。
存储优化:
文件生命周期管理:在执行 Checkpoint 时会产生许多小文件。如果生命周期表设置得过长,小文件的数量自然会增加。尽管有合并操作,但在高流量场景下,生命周期管理的问题不容忽视。这包括分区、生命周期、快照以及变更日志的生命周期管理。
小文件合并:文件合并可以开启独立 compact 作业完成。小文件合并是当前阶段需要关注的问题,社区可能会提出新的解决方案,大家可以继续关注。
清理废弃文件:在初期使用时,我们可能会遇到性能优化不佳或稳定性差异的问题,导致作业频繁失败,产生一些孤立文件。这些文件需要手动清理。社区提供了一些通用命令,我们可以用这些命令来编写自己的清理脚本,并进行定时调度以解决问题。实际上,存储优化主要解决的是文件数量问题,而不是文件大小问题。
稳定性优化:稳定性问题在流量大时尤为突出,可能会触发故障。例如,内存设置不合理或对流量峰值预估不足,都可能导致系统无法恢复。尽管我们设置了生命周期和快照文件的过期时间,但一旦它们过期,作业可能就无法恢复。
开启 Comsumer:为此,我们提供了 Consumer 的能力,可以将 Consumer ID 标记出来,使其在一定时间内或永远不过期,从而在作业失败后仍能恢复。但需要注意的是,启用 Consumer 后,文件数量会增加,因为过期时间变长了。在追溯时,系统会逐个扫描 Snapshot 文件,最终追溯的数据量会增加,速度会变慢。
调整 TM 资源:TM cpu/mem 资源的调整应根据具体情况进行。Paimon 团队提供一些经验公式,可以根据实际情况进行调整,例如根据一张表的更新频率、一条记录的大小以及 Bucket 的数量等,从而估算出内存需求。根据经验进行配置,特别要注意的是,使用过 Paimon 的用户应该熟悉它最后的 Commit 节点。这个节点确保了数据最终一致性,因此在配置到这个节点资源时,如果分区数量众多,就需要适当增加 CPU 和内存资源,以保证系统运行更加流畅。
下面是一个优化例子,我们曾经完成了一个作业,一个小时写入了 700+GB 数据。根据这个作业,我们设置每个分区的 bucket num 为 512,每小时一个分区。生命周期设置了 7 天,支持实时数据流读写。在这样的设置下,TPS(每秒事务数)可以达到五六百万。在开启异步处理之前,节点切换的平均耗时超过 50 秒,而开启后则缩短至 20 秒。

三、湖仓收益

接下来,我想分享一下我们通过这些优化带来的业务和技术收益。
业务收益
由于采用了分层设计和弧形设计,下游的许多迭代工作变得简单,只需编写一段代码,进行 Group By 或 Join 操作即可,大大缩短了交付周期。整体统计下来,交互周期缩短了约 30+%。
实时的 DWD 和 DWS 层的数据可以用于洞察场景,无需通过离线处理,通常在 15 分钟内就能产出一批数据。整体观察下来,时效能减少约两个半小时,平均节约两个小时。
实时数据监控也大大改善了业务运营的效率。以前,业务运营人员在数据更新超过两小时后会感到焦虑,不确定是否需要增加预算或停止投放。现在,由于数据是分钟级产出,运营人员能够准确判断整体投放进展和预算是否达到预期。
技术收益
主要减轻了我们的计算资源负担。通过去除重复消费的链路,整体资源开销降低了 40%以上。
分层设计提高了业务效率,减少 50%开发工作量。
架构中提到的主备双链路设计,满足了三个 9 的高可用性要求,即 99.9%的运行时间。一年 365 天计算下来,停服时间应该不到 9 小时。实际上,我们全年几乎没有长时间停服,如果出现这种情况,你们肯定能在热搜上看到我们遇到了问题。
最后是这个冗余作业的这个订阅之间,因为是这样的,就是我们去订阅这个 TT,其实它是要付费的,就是你重复消费一遍,它个钱就是重复给你算一遍,这个都是钱。就是所以以及我们的 Flink 作业这个资源就是开销也很大,这个东西就是都是钱,所以整体算下来都是成本,另外就是你把些作业干掉了之后,我也不用天天盯着些作业,运维成本同步下降。
更多内容

活动推荐
阿里云基于 Apache Flink 构建的企业级产品-实时计算 Flink 版现开启活动:新用户复制点击下方链接或者扫描二维码即可 0 元免费试用 Flink + Paimon实时计算 Flink 版(3000CU*小时,3 个月内)了解活动详情:https://free.aliyun.com/?utm_content=g_1000395379&productCode=sc

版权声明: 本文为 InfoQ 作者【Apache Flink】的原创文章。
原文链接:【http://xie.infoq.cn/article/9001b08310534a00c913fc036】。文章转载请联系作者。
评论