Pinterest 抄了流的作业
📋 总体概括
Pinterest 公开了一套基于事件时间的分区终结机制:用 Flink 追踪事件时间,把非回退水印发布进 Iceberg 元数据,让下游任务自行判断 PB 级 CDC 数据何时'足够完整'。本文拆解其技术路径、产业逻辑与对国内数据平台的启示。
📄 正文
深夜两点半,某家电商的数据团队被一条告警惊醒:昨天的分区又少了一批 CDC 数据,而下游报表已经发出去了。这不是某一家公司的痛,而是所有做持续摄入的数据平台共同的宿命式难题——数据,到底什么时候才算“到齐”?
最近,Pinterest 在其官方工程博客上公开了一套基于事件时间(event time)的分区终结机制:用 Apache Flink 追踪事件时间,把一个“非回退水印”发布进 Apache Iceberg 的元数据,让下游任务自己判断“这块数据够齐了,可以开工”。机制不算惊天动地,但判断很明确:数据完整性正在从‘经验题’变成‘元数据可计算题’,这是湖仓工程成熟度的又一级台阶。
🕳️ 分区永远差一点:持续摄入下的老难题
在流式摄入的世界里,“完成”是一件奢侈品。
先看场景。据 Pinterest 工程博客披露,其数据库摄入框架持续消费源库的 CDC 变更流,覆盖数千张业务源表、日均处理数十亿条变更记录,按事件时间把数据落到 Iceberg 的分区里——比如按天分区,整座数据湖的规模在 PB 级。下游要做聚合、要跑报表、要喂模型,所有这些动作都有一个隐含前提:这个分区的数据“差不多齐了”。
问题就卡在这个“差不多”上。CDC 数据天然乱序、天然迟到:用户凌晨一点的交易记录,可能因为网络抖动,下午三点才同步过来。传统做法就两种。
第一种,延迟等待。比如约定每天分区落定后额外等上三到四个小时再触发下游。Pinterest 的工程博客把这种困境概括得很直白:过早触发下游计算,风险是数据不完整、结果出错;而一味拉长等待,时效被白白吃掉,算力成本也在实打实地烧。 在 PB 级规模下,每多等一小时,背后都是数千核时级别的计算资源,而即便如此,固定延迟也只是在“缺数”和“迟到”之间赌一个概率。
第二种,外部编排触发。由调度系统人为判定某个条件满足后发出“分区完成”信号。看似可控,实则把完整性判断散落在各个调度脚本里,口径不一、无处审计,出问题时排障像考古。
从工程直觉出发,任何做过持续摄入的团队对这套机制的第一次共鸣,恐怕都不是惊叹,而是“我们也这么凑合过”。凑合,恰恰说明这个环节长期缺乏一个工程化的正解。
产业逻辑很直白:当数据规模到 PB 级,“差不多”的代价会被放大成真金白银的重跑成本和迟到报表。 分区终结这件事,值得被认真设计。
⚙️ 水印出流进表:一次关键的位置移动
水印不是新东西,把它写进表元数据才是。
水印(watermark)是流处理的核心概念。Apache Flink 很早就用它来刻画事件时间的进度:“事件时间已推进到 T,晚于 T 到达的数据大概率不会再有,或按迟到策略单独处理。”它解决的正是流处理里那个终极问题——窗口什么时候该关。
Pinterest 做的事情,本质上是在摄入层复用这套机制,然后把结果挪了个位置:
具体来说:Flink 作业在消费 CDC 流时持续维护事件时间水印,并把一个非回退(non-regressing)的水印发布到 Iceberg 元数据里。下游任务不再靠拍脑袋,而是直接读元数据——当某分区的事件时间边界已被水印越过(比如“今天”这个分区的水印已经推进到当天结束之后),该分区就被判定为“足够完整”,可以终结并触发后续处理。按其工程博客的表述,这让分区的终结时刻不再由固定延迟决定,而是由数据自身的事件时间进度决定,时效收益以小时计,且省去了大量为“保险起见”而空转的下游算力。
这里有两个关键设计点,值得单拎出来。
一是“非回退”。CDC 流里事件乱序是常态,水印如果跟着乱序事件来回波动,下游的判定就会反复横跳。非回退保证水印单调不减,给了下游一个稳定的决策依据。
二是“放进 Iceberg 元数据”。这一步的位置选择比技术本身更有分量。水印完全可以存在 Pinterest 自家的调度系统里,但他们没有——放在开放表格式里,意味着 Spark、Trino 等任何读这张表的引擎,看到的是同一份‘完成性事实’。 从工程角度冷静分析:难的从来不是算出水印——Flink 生态里这已经是成熟能力——而是让所有引擎认同一份水印,让它有一个所有引擎都能读到的中立存放位置。
🌊 完成性的三种答案:从拍脑袋到查元数据
数据到齐与否,在过去二十年里基本靠猜。
把这个问题放进时间线里看,脉络会很清晰:
- 2014-2015 年:Apache Flink 系统性地提出基于事件时间的窗口与水印机制,流计算第一次认真回答“数据到齐了吗”
- 2016 年:Kafka 0.10 引入消息级事件时间戳,事件时间有了更通用的载体
- 2018 年:Netflix 将 Iceberg 开源,开放表格式开始承载分区演进、统计信息等表级语义
- 2025 年:Pinterest 在其工程博客上公开基于事件时间的分区终结机制,水印正式写入 Iceberg 元数据,供下游多引擎消费
这个演进的方向只有一个:把“完成性”从引擎私有状态和运维经验里解放出来,变成平台级、可计算、可共享的元数据语义。
三种主流策略放到一张表里对比,差异一目了然:
| 策略 | 原理 | 优点 | 代价与风险 |
|---|---|---|---|
| 延迟等待 | 固定延迟后视为完成 | 实现最简单,无侵入 | 时效与完整性互相拖累,PB 级下浪费严重 |
| 外部编排触发 | 调度系统判定后发信号 | 集中可控,可叠加业务规则 | 判断逻辑散落各处,口径不一,难以审计 |
| 事件时间水印 | 元数据内可计算的完成信号 | 数据自证,单调可靠,多引擎可消费 | 需要流引擎与表格式深度配合 |
产业逻辑在于:水印从 Flink 算子内部的一个变量,变成开放表格式的一等公民元数据,意味着“完成性”被产品化了。对 PB 级平台来说,这不是炫技——一个分区早终结一小时,折算下来就是省下来的集群费用和提前一小时交付的报表;一次因不完整导致的下游重跑,可能就是一场通宵。可靠性和成本,在这里是同一枚硬币的两面。
🗺️ 竞争格局:Iceberg 门口的元数据之争
表格式卷的早已不只是存储格式,而是元数据能力。
(注:原文此处曾附一张缺乏公开信源支撑的生态竞争象限图,为避免误导读者,本文予以删除,改以文字说明产业判断。)
删去那张图,核心判断依然成立:Pinterest 选择把水印落在 Iceberg 而非私有系统,等于给开放表格式阵营又添了一票重仓。
湖仓竞争的焦点,正在从“存储格式谁压缩率更高”上移到“元数据能承载多少平台级语义”。Iceberg 这几年一路走来——schema 演进、分区演进、隐藏分区、快照与回滚——每一步都是在往表格式里塞原本属于数据库和调度系统的职责。这一次轮到了“完成性信号”。
推演下去,逻辑很清楚:谁家的表格式能承载更多平台级语义,谁就更接近数据平台“操作系统”的位置。 引擎可以换、云厂商可以换,但表和它的元数据是所有计算绕不开的公共界面。这也是为什么各大引擎和厂商都争先恐后地拥抱 Iceberg——不想在元数据层被边缘化。
反观自研闭源摄入方案:技术门槛不低、投入不小,但难复用、难招人、生态孤立,正被 Kafka + Flink + Iceberg 这类开源组合逐步挤出新的选型清单。Pinterest 作为重度自研起家的代表之一,都选择把关键语义落在开放格式上,这个信号本身比机制细节更值得琢磨。
💡 国内平台能抄的三件事
真正该抄的不是代码,是“判断权归谁”的思路。
把 Pinterest 这套机制背后的工程思想,拆成痛点与解法:
落到国内数据平台的语境,有三条判断值得说透。
第一,分区终结策略应该写进平台设计文档,而不是躺在工程师脑子里的“再等俩小时”。国内不少中台的通病,是完整性口径同时存在于调度系统、数据质量监控和各业务线约定三处,互相对不上。Pinterest 的做法本质是把口径收拢到元数据一层——元数据成了唯一权威。对国内团队而言,落地的第一步甚至不必是水印,而是先盘点清楚:你们家的“分区完成”,目前到底由谁说了算、写在几个地方。
第二,表格式选型时把元数据能力当第一考量。很多团队选 Iceberg 还是别的格式,比的是兼容性和压缩率,但真正拉开差距的是元数据层能承载什么语义——完成性信号只是最新的一例,后面还会有更多。选型时不妨多问一句:三年后这套平台要往表元数据里放什么,这套格式接得住吗。
第三,事件时间要从源头贯彻,这条值得展开说。CDC 场景里业务时间与处理时间的错位是迟到数据的根因:如果摄入时统一不打上可信的业务事件时间,源库里一次补数、一次历史回刷,就可能让下游水印被“未来”或“过去”的数据冲击,非回退机制只能兜住乱序,兜不住错误的时间戳本身。所以水印必须放在摄入框架里计算,而不是下游补救——摄入层见过源 schema、见过变更语义,是唯一有资格定义“这条记录的事件时间是什么”的位置。Pinterest 把水印生成放在摄入框架而非消费端,位置本身就说明了答案。国内团队做 CDC 链路时,应当把“事件时间的定义权和打标责任”明确收归摄入层,并配套监控事件时间与处理时间的偏移水位线——偏移突然拉大,往往就是上游补数或时钟异常的信号。
小结
Pinterest 这一步的信号价值大于机制本身:水印从流处理的算子内部走向 Iceberg 元数据,意味着“数据何时完整”这个困扰行业二十年的问题,第一次有了可计算、可共享、多引擎共识的标准答案。这是流批边界消融的又一注脚,也是开放表格式向数据平台“操作系统”迈进的又一步。接下来值得盯的是 Iceberg 生态能否把“完成性”标准化为通用接口——一旦更多引擎和云厂商跟进,“等俩小时”这类土办法,就该进博物馆了。
参考来源:Pinterest Engineering Blog 关于基于事件时间的 Iceberg 分区终结机制(event-time based partition finalization)的官方文章;Apache Flink 与 Apache Iceberg 官方文档。文中 Pinterest 摄入规模(数千张源表、日均数十亿条变更、PB 级数据湖)与延迟窗口等数据均引自该官方博客的公开披露。
本文由本站 AI 辅助聚合生成,原始来源如下: