批处理与流处理是什么
批处理一次读取一段有界数据(分区、文件、日切片),跑完作业即退出;流处理面对的是无界事件流,作业常驻内存,数据到达即处理。二者不是新旧替换关系,而是对「数据是否会有终点」给出的两种答案。
微批与真流
Spark Structured Streaming 走微批:按很小的时间间隔把流切成一批批小作业,延迟通常在秒级;Flink 走事件驱动,算子间以流水线方式传递记录,延迟可以压到毫秒级。延迟要求不高时,微批的工程成熟度与批流同代码的优势更明显。
基本信息
| 批处理 | 读取有界数据集,作业结束即释放资源 |
|---|---|
| 流处理 | 常驻处理无界数据流,靠 checkpoint 保证恢复 |
| 微批 | 流数据按小间隔切批执行,延迟秒级 |
| 容错方式 | 批靠失败重跑;流靠 checkpoint 快照恢复 |
| 典型引擎 | 批:Spark、Hive、MapReduce;流:Flink、Kafka Streams |
对比项
| 对比项 | 批处理 | 流处理 |
|---|---|---|
| 数据范围 | 有界(文件/分区) | 无界(持续事件流) |
| 延迟量级 | 分钟到小时 | 毫秒到秒(取决于链路) |
| 吞吐与成本 | 高吞吐、按需启停 | 常驻资源,空闲也占位 |
| 补数与重跑 | 改分区重跑即可 | 需要重置位点或从快照重放 |
| 结果确定性 | 同一批输入结果稳定可复现 | 取决于时间语义,处理时间不可复现 |
| 运维重点 | 调度依赖与窗口时长 | 状态大小、反压与位点提交 |
典型使用场景
- 日终财务报表、对账与结算:跑批最合适,可反复重跑核对
- 实时大屏与风控告警:需要秒级输出,用流作业
- 历史数据回灌与口径修正:走批任务补数,不要塞进流作业
- 同一指标既要实时值又要收盘值:实时链路出近似值,批链路出对外口径
- 日志明细入湖后按小时分区聚合:微批即可满足,无需常驻流作业
Structured Streaming 最小示例
Structured Streaming 最小示例
# 读 Kafka 流并写出到目录,微批模式,进程常驻不退出
# checkpointLocation 保存位点与状态,必须落在共享存储,否则故障后无法恢复
spark.readStream.format('kafka') \
.option('kafka.bootstrap.servers', 'kafka1:9092,kafka2:9092') \
.option('subscribe', 'orders') \
.load() \
.writeStream.format('parquet') \
.option('checkpointLocation', '/ck/orders') \
.outputMode('append') \
.start('/warehouse/orders_stream')
# 同一个目录换成批读就是一次性作业,可以挂调度、能跑完、结果可复现
# spark.read.parquet('/warehouse/orders_stream')同一段 SQL 的两种执行
同一段 SQL 的两种执行
-- 批:读有界历史表,跑完即出全量结果
SELECT region, SUM(amount) AS amt FROM orders_file GROUP BY region;
-- 流:读事件流,必须按窗口持续产出,不能等“数据到齐”
SELECT TUMBLE_START(ts, INTERVAL '1' MINUTE) AS w, region, SUM(amount) AS amt
FROM orders_kafka
GROUP BY TUMBLE(ts, INTERVAL '1' MINUTE), region;批流统一 SQL 已是主流:Flink SQL 与 Spark SQL 都能跑批也能跑流,把加工逻辑收敛成一份 SQL,可显著降低两条链路口径不一致的风险。
为什么大多数团队批流并存
对外口径指标通常要求可复现、可解释、能重算,这天然属于批;实时性指标要求分钟级甚至秒级可见,只能靠流。让流链路只负责「看得快」、批链路负责「算得准」,两条链路共用同一份指标定义,是常见且稳妥的分工,也解释了为什么批引擎与流引擎长期共存而没有被彼此取代。
资源规划思路不同:批作业按分区分批买算力、可以错峰运行;流作业要按全天常驻预留,成本随并行度线性增长。所以能用批解决的定时需求,不要顺手写成流作业。
流作业长期运行要盯状态大小与 checkpoint 耗时:状态随 key 基数持续膨胀时,重启恢复时间会一轮比一轮长,最终无法在允许窗口内恢复。