章节摘要:本章跟着同一个业务需求走一条线——"统计每个商户最近一分钟的成交",先用 DataStream 写一遍,再用 SQL 写一遍,最后发现需求升级成"识别十分钟内连续三次失败支付"时各用什么武器。三个站点对比三种表达层的表达力、成本与适用边界,终点是你拿到需求就能选对武器。
主线是一个再普通不过的需求:"统计每个商户最近一分钟的成交额。"产品同学提它只花了十秒,但工程上你要先做一个决定:用哪一层 API 来写? 同样的逻辑,DataStream API 给你完全的控制权(连状态用哪种容器都由你定),Table SQL 给你两行声明式代码(引擎替你规划状态与序列化),CEP 则在你需要模式识别时闪亮登场。三种写法没有高下,只有合身与否——本章的主线就是把这个"合身"讲成可操作的判断。
这条主线的深层价值在于:API 的选择不是审美问题,而是状态与运行时成本的传导链。第 4 章刚讲完状态的重量,本章马上展示同一逻辑在不同表达层下状态形态的差异——SQL 聚合的状态布局引擎说了算,DataStream 的状态结构你亲手设计。选错表达层,第 8 章的调优会处处别扭;选对了,很多"调优问题"根本不会发生。
5.1 DataStream API——发动机舱。数据流的根本抽象(无界数据集上的转换算子)、进程函数(KeyedProcessFunction 这类"带状态钩子"的万能工具)、以及它对时间与状态的完全控制力。你会看到 3、4 两章的概念如何在一个函数里合体,也会看到它代价:样板代码多、优化靠人。
5.2 Table API 与 SQL——驾驶舱。声明式的世界里,你描述"要什么",引擎决定"怎么算"。SQL 的窗口、join、topN 的状态成本各有门道,执行计划怎么看、为什么同一条 SQL 换个写法状态规模差十倍。这是今天实时数仓开发的主战场,本章着墨最多的一站。
5.3 复杂事件处理 CEP——模式识别武器库。当需求从"聚合"升级成"识别事件序列的模式"(连续三次失败、先浏览后下单、一个小时内的异常轨迹),普通聚合立刻笨拙。CEP 的模式语言(顺序、循环、条件、时间约束)与它的状态代价(每条中间序列都是状态)值得认真一笔。
顺带交代一句删繁就简的决定:旧版教程里的 Stateful Functions 一节并入了本章与 5.2 的讨论——那套"把有状态函数当微服务编排"的定位过于小众,其核心思想(状态与计算同址、以消息驱动函数)在 DataStream 的进程函数与 SQL 的流式 join 里都能找到更主流的对应物,不值得单开一站。
本章的认知拐点在 5.2 的中段:很多人把 SQL 当"简化的 DataStream",写起来快就一定优化得慢。理解执行计划后你会发现——SQL 不是简化,是另一种分工:它把"如何组织状态与序列化"交给引擎的优化器,多数场景下引擎做得比手写更好;只有优化器够不着的角落(超复杂状态机、特殊序列化、精细 TTL 控制)才需要回退到 DataStream。把 SQL 当默认、把 DataStream 当回退,是当下实时数仓的主流打法。
最终落点是一张武器选择卡:聚合报表类需求,SQL 起手;涉及精细状态控制(自定义 TTL、复杂清理逻辑、外部服务调用),DataStream 的进程函数;事件序列模式识别,CEP 或者 SQL 的 MATCH_RECOGNIZE。三张卡在第 8 章大屏复盘里都会被实际打出。
代码写完了,作业要落到集群上长期生存——部署模式、高可用、监控体系在等着。第 6 章我们从开发视角切换到运维视角,把"能跑"变成"敢睡"。
金句:API 选型的功夫不在写得多快,而在让状态长得不费劲。