Flink 快速入门之 Flink DataStream Batch 模式

简介: 本文深度解析Flink 2.x中被移除DataSet API后,DataStream的BATCH执行模式:它不是“慢速流”,而是在调度、数据交换、状态管理三方面彻底重构的批处理范式;详解模式切换带来的行为差异、失效特性(如checkpoint依赖功能)及避坑要点,助你真正用好流批一体。

导读:DataSet API 在 2.x 里被移除之后,「批」只剩一条路——DataStream API 的 BATCH 执行模式。但它不是「跑得慢一点的 STREAMING」:调度、数据交换、状态管理三处机制全被换掉,还带来一批行为差异和使用限制。这篇把 BATCH 模式讲透:怎么开、换掉了什么、哪些代码会悄悄变行为、哪些特性直接失效。

一、为什么是「执行模式」而不是「另一套 API」

老版本 Flink 处理批数据要走 DataSet API,和 DataStream API 是两套平行的世界。2.x 里的答案是:批是一种执行模式,不是另一种 API。RuntimeExecutionMode 给出三个取值:

模式 语义 适用作业
STREAMING 经典流执行,低延迟 无界作业(唯一选择),有界作业也可用
BATCH 分阶段批执行,更高效 只能用于有界作业
AUTOMATIC 系统按 source 有界性自动选择 有界走 BATCH,任一 source 无界则退回 STREAMING

三种配置方式,官方明确推荐第一种——把模式留给部署时决定,代码保持配置无关:

# 推荐:提交时指定,同一份 jar 可以流批两跑
bin/flink run -Dexecution.runtime-mode=BATCH ./order-stat.jar
// 也可以写在代码里,但会失去上面这种灵活性
StreamExecutionEnvironment env =
        StreamExecutionEnvironment.getExecutionEnvironment();
env.setRuntimeMode(RuntimeExecutionMode.BATCH);

「有界」是 source 的属性:一个作业当且仅当所有 source 都有界时才是有界作业。Kafka 源通过 setBounded 声明,文件源默认有界:

KafkaSource<String> boundedKafka = KafkaSource.<String>builder()
        .setBootstrapServers("broker:9092")
        .setTopics("orders")
        .setGroupId("batch-job")
        .setStartingOffsets(OffsetsInitializer.earliest())
        .setBounded(OffsetsInitializer.latest())   // 读完最新位点即结束
        .setValueOnlyDeserializer(new SimpleStringSchema())
        .build();

在这里插入图片描述

二、BATCH 模式换掉了什么:三处机制级差异

同一个 DataStream 程序,切到 BATCH 模式后,底层换了三套机制。理解它们,才能理解后面的行为差异。

① 调度:从「全员常驻」到「分 stage 依次执行」。 STREAMING 要求所有 task 同时在线,资源必须装得下整个作业。BATCH 把作业按 shuffle 边界切成多个 stage,一个接一个执行——上游跑完、下线,下游再读中间结果,所以更少的 slot 就能跑更大的作业。

② 数据交换:从 pipelined 到 blocking。 流模式记录产生即发送;批模式必须把中间结果物化到非易失存储,代价是延迟,收益是故障时可回溯到仍有结果的 stage。

③ 状态:state backend 被直接忽略。 这是大多数人没预料到的一条。BATCH 模式下 keyed 操作的输入会按 key 排序,然后逐个 key 处理完所有记录再丢弃其状态——同一时刻内存里只有一个 key 的状态。TTL、RocksDB 调优这些在批模式下都无关紧要。

在这里插入图片描述

三、批模式下的时间:perfect watermark

流模式的 watermark 是一种悲观启发式——系统不知道「乱序到哪算完」,只能用水位线做估计,容忍 30 秒乱序就要多等 30 秒。批模式没有这个问题:输入提前已知,元素可以按时间戳排序处理,相当于拿到了 perfect watermark。

具体行为有三条,每条都可能改变你的程序语义:

在这里插入图片描述

  1. 自定义 WatermarkGenerator 被完全忽略。forBoundedOutOfOrderness 里的乱序边界在批模式下不起任何作用。
  2. 只在每个 key 关联输入的末尾(非 keyed 流则在全局末尾)注入一次 MAX_WATERMARK,所有窗口在输入末尾统一关闭。
  3. 所有 timer 都在 end of time 触发——先按 key 顺序、再按时间戳顺序。事件时间和处理时间的 timer 一视同仁。

但 WatermarkStrategy 仍然要写:它的 TimestampAssigner 负责给记录打事件时间戳,漏了它,事件时间字段就是空的。

// 批模式下 strategy 里的乱序边界被忽略,但 timestamp assigner 必须有
WatermarkStrategy<Order> strategy = WatermarkStrategy
        .<Order>forBoundedOutOfOrderness(Duration.ofSeconds(5))
        .withTimestampAssigner((order, ts) -> order.getEventTime());

另一条高频踩坑:reduce、sum 这类「滚动」操作在流模式下逐条发出增量更新,在 BATCH 模式下只在最后发出一个最终结果。如果你的下游逻辑依赖「每来一条更一次」,切到批模式行为就变了。

四、批模式下失效的特性:一切依赖 checkpoint 的东西

BATCH 模式的容错不靠 checkpoint,靠回溯中间结果:故障时只重启失败任务及其前驱,而不是从快照拉起全部任务。代价是一批依赖 checkpoint 的特性直接失效:

// 这些在 BATCH 模式下都不能用:
// 1. CheckpointListener 回调
// 2. KafkaSink 的 EXACTLY_ONCE 模式(依赖 checkpoint 完成提交事务)
// 3. FileSink 的 OnCheckpointRollingPolicy

需要事务性 sink 时,必须使用 Unified Sink API(FLIP-143,即 sinkTo + Sink V2 接口),它的提交不依赖 checkpoint 机制。实践中更常见的做法是:批模式输出走幂等写(主键去重)或直接落文件,不做事务。

自定义算子还有一条隐藏规则:算子永远不绑定 key,而批模式逐 key 处理时,水位线会在 key 之间从 MAX_VALUE 直接切回 MIN_VALUE——任何「缓存上一个水位线」的假设在批模式下都是错的。

五、一个完整可跑的批作业

把上面的约束拼起来,一个 BATCH 模式作业的骨架长这样——和流作业唯一的区别是 source 有界 + 模式声明:

StreamExecutionEnvironment env =
        StreamExecutionEnvironment.getExecutionEnvironment();
env.setRuntimeMode(RuntimeExecutionMode.BATCH);

FileSource<String> source = FileSource
        .forRecordFileFormat(new CsvReaderFormat<Order>() {
   }, new Path("./orders/"))
        .build();

env.fromSource(source, WatermarkStrategy
                .<Order>forMonotonousTimestamps()
                .withTimestampAssigner((o, ts) -> o.getEventTime()), "orders")
   .keyBy(Order::getUserId)
   .window(TumblingEventTimeWindows.of(Time.days(1)))
   .aggregate(new OrderAgg())
   .sinkTo(FileSink
           .forRowFormat(new Path("./out/"), new SimpleStringEncoder<Stat>())
           .withRollingPolicy(DefaultRollingPolicy.builder().build())
           .build())
   .uid("sink-daily-stat");

env.execute("daily-stat-batch");

两点提醒:批模式下不需要配置 checkpoint 与状态后端(配了也被忽略);uid 仍然要写——虽然批作业没有 savepoint 恢复的强需求,但保持习惯统一,跨模式复用代码时少一个隐患。

六、什么时候不该用 BATCH 模式

BATCH 模式也不是万能的,两类场景要坚持 STREAMING:

  1. 要增量结果。大屏每秒刷新、指标逐条更新,这些语义依赖流模式的持续输出,批模式只有「一个最终结果」。
  2. 依赖事务性 sink。如果下游必须 exactly-once 且走 Kafka 事务,BATCH 模式下此路不通。

还有两个边界情况值得知道:为无界作业做状态引导(先用有界数据跑出初始状态取 savepoint),以及为最终跑无界的代码写测试,这两种情况即便输入有界也应保持 STREAMING 模式。

七、上线前检查清单

在这里插入图片描述

左两栏决定能不能用:所有 source 有界、资源允许分阶段执行。右两栏决定用了之后会不会踩雷:同一段代码的语义差异,以及所有依赖 checkpoint 的失效特性。变更评审时按这十六项过一遍,绝大多数批模式事故都能提前拦截。

结语

DataStream BATCH 模式是 Flink「流批一体」承诺的兑现处:同一套 API、同一份代码,模式只是部署时的一个开关。但兑现的前提是你理解引擎在开关两侧换掉的东西——调度从常驻变成分阶段,交换从 pipelined 变成 blocking,状态从驻留变成排序后逐个处理,时间从启发式变成 perfect watermark。

相关实践学习
基于Hologres+Flink搭建GitHub实时数据大屏
通过使用Flink、Hologres构建实时数仓,并通过Hologres对接BI分析工具(以DataV为例),实现海量数据实时分析.
实时计算 Flink 实战课程
如何使用实时计算 Flink 搞定数据处理难题?实时计算 Flink 极客训练营产品、技术专家齐上阵,从开源 Flink功能介绍到实时计算 Flink 优势详解,现场实操,5天即可上手! 欢迎开通实时计算 Flink 版: https://cn.aliyun.com/product/bigdata/sc Flink Forward Asia 介绍: Flink Forward 是由 Apache 官方授权,Apache Flink Community China 支持的会议,通过参会不仅可以了解到 Flink 社区的最新动态和发展计划,还可以了解到国内外一线大厂围绕 Flink 生态的生产实践经验,是 Flink 开发者和使用者不可错过的盛会。 去年经过品牌升级后的 Flink Forward Asia 吸引了超过2000人线下参与,一举成为国内最大的 Apache 顶级项目会议。结合2020年的特殊情况,Flink Forward Asia 2020 将在12月26日以线上峰会的形式与大家见面。
目录
相关文章
|
8天前
|
人工智能 JSON 自然语言处理
LangChain 六大使用场景:哪些值得做,哪些不值得,一张决策图说清
本文系统梳理LangChain六大核心场景(RAG、Agent、对话系统、结构化提取、内容生成、多模态),逐项解析痛点、机制、落地要点与适用边界,并附“不该用”的反向清单。强调“模型+外部世界”协同才是框架价值所在,助力AI工程化理性选型。
282 0
|
5天前
|
人工智能 中间件 Java
LangChain 到底是什么:从链式连接到 Agent 运行时,讲透 v1.0 的核心概念
LangChain 是大模型应用开发框架,非单纯API封装。v1.0聚焦Agent工程化:以`create_agent`为核心,基于LangGraph实现可持久化、可中断、可观测的智能体循环;统一模型接口、强化工具描述、分层记忆管理,并通过中间件支持人工介入、摘要压缩与隐私脱敏,推动AI从“能跑”走向“可靠生产”。(239字)
170 1
|
8天前
|
SQL 存储 分布式计算
一篇文章搞懂 Hive:从数仓定位到架构、表设计与数据倾斜治理
Hive是基于Hadoop的SQL数据仓库工具,不存数据、不算数据,仅作“胶水层”:元数据存MySQL,数据落HDFS,计算交YARN。支持内外表、分区/分桶、ORC/Parquet列存及丰富优化策略,专为海量离线分析而生,是企业级数仓十五年事实标准。(239字)
483 1
|
2天前
|
分布式计算 分布式数据库 Spark
HDFS 写文件流程:复制管线与故障恢复机制
本文深度拆解HDFS写文件流程:`hdfs dfs -put`秒回背后,是客户端、NameNode与DataNode协同完成建文件、64KB packet切包、三节点串行管线复制、逐层ack及动态容错(如节点宕机自动剔除+异步补副本)的完整链路,揭示“写成功≠三副本齐”的设计本质。
44 1
|
2天前
|
存储 运维 调度
HDFS 三副本放置策略:机架感知的容错权衡
HDFS三副本放置策略是机架感知下的精妙权衡:第一副本本地写(提性能)、第二副本跨机架(保容错)、第三副本落于第二副本同机架(省骨干带宽)。本质是在单机架故障容忍与网络资源约束间的最优解。
32 0
|
2天前
|
存储 分布式计算 固态存储
HDFS Block 为什么默认 128M:寻址时间与传输速率的权衡
HDFS默认Block设为128MB,源于磁盘寻址时间(约10ms)与传输速率(约100MB/s)的工程权衡:为使寻址仅占传输时间1%,理想块大小≈100MB;再对齐二进制幂次,取最接近的128MB。它平衡了NameNode内存开销、寻址效率与计算并行度。
38 0
|
3天前
|
消息中间件 分布式计算 Kafka
Flink 的对手换了:三条分野,重排实时计算选型
本文深度剖析2026年Flink与Spark等流处理方案的本质差异,摒弃过时对比表,聚焦**执行模型、状态归属、交付形态**三大分野,直击选型核心:不是“谁更强”,而是“哪种复杂度你付得起”。
79 0
|
5天前
|
消息中间件 监控 Kafka
Structured Streaming 数据源落地案例:四种源、四段可直接抄的代码与踩坑实录
本文详解Structured Streaming四大生产级数据源实战:Kafka限流防积压、File源原子写入与maxFileAge误读避坑、Rate源渐进式背压验证、foreachBatch一托三幂等分发。每个案例均按“约束→写法→翻车→修复”闭环展开,直击参数设计本质与线上事故根因。(239字)
58 0
|
7天前
|
分布式计算 监控 数据安全/隐私保护
Structured Streaming 窗口操作及案例实践:三种窗口、一个 watermark、三种迟到处置
本文深入剖析流式聚合核心——窗口机制,厘清滚动、滑动、会话三类窗口的本质差异与状态代价;详解窗口与Watermark联动的四阶段生命周期;解析迟到数据的丢弃、update修正、多水印容忍三大策略;结合GMV统计、滑动告警、用户会话三大实战案例,并指出窗口不输出、状态膨胀、时间字段用错三大高频陷阱。(239字)
82 0
|
13天前
|
分布式计算 资源调度 Kubernetes
Spark 核心之 ClusterManager 原理剖析
本文深度解析 Spark 的 ClusterManager 抽象层:通过 ExternalClusterManager 接口与 ServiceLoader 机制,统一适配 Standalone/YARN/K8s 三大资源管理器。详解 Master URL 路由、源码实现对比及自定义扩展方法,揭示 Spark “调度不变、资源可插拔”的核心设计哲学。(239字)
61 0