一、批处理调度概述

1.1 什么是批处理

批处理,说白了就是「攒一批活儿,一次性干完」。

我刚开始接触分布式系统时,对批处理的理解很朴素——不就是写个脚本,半夜跑一跑嘛。后来真正上手才发现,事情远没那么简单。

批处理的核心特征,我总结为三点:

  • 数据有界——处理的数据集是确定的、有限的。你今天跑的是昨天的订单,数据量是已知的。
  • 非实时触发——不是用户点一下就要立刻响应,而是按时间窗口(比如每天凌晨2点)或数据量阈值触发。
  • 全量或增量扫描——要么把整个数据集过一遍,要么只处理上次运行以来新增的数据。

我个人的定义:批处理是一种「先收集、后处理」的计算模式。它不追求秒级响应,但追求吞吐量和数据完整性。

举个例子。你在电商平台下单后,订单状态立刻变成「已支付」,这是实时处理。但到了月底,财务系统要统计所有订单的毛利、成本、退款率——这就是批处理。它不会在你下单那一刻就算,而是等数据攒够了,统一算一笔账。

1.2 批处理与实时处理的区别

很多人问我:批处理和实时处理,到底怎么选?

我的回答是:看业务能不能等。

能等几秒甚至几分钟的,用批处理。一秒都不能等的,用实时处理。但现实往往更复杂——同一个系统里,两种模式经常混着用。

下面这张表,是我在项目中反复对比后整理的:

对比维度 批处理 实时处理
延迟要求 分钟级~天级 毫秒级~秒级
数据范围 有界数据集(全量或增量) 无界数据流(持续到达)
触发方式 定时调度 / 手动触发 事件驱动 / 持续消费
吞吐量 高(可批量处理百万级记录) 中低(每条记录独立处理)
容错策略 重试整个批次 / 断点续传 逐条重试 / 死信队列
典型场景 报表生成、数据仓库ETL、对账 风控拦截、实时推荐、监控告警
资源消耗 集中爆发(跑批时CPU/IO飙升) 平稳持续(资源占用较均匀)

一个小经验:我曾经接手过一个对账系统,原本用实时流处理,每条交易都去核对,结果数据库连接池被打爆了。后来改成批处理——每5分钟攒一批,批量核对,系统瞬间稳了。所以别迷信实时,批处理在特定场景下反而更可靠。

1.3 批处理调度的核心概念

做批处理调度,有几个概念你必须吃透。我按重要程度排个序:

1.3.1 作业(Job)与任务(Task)

作业是调度的最小单元。一个作业可以拆成多个任务,任务之间可能有依赖关系。

举个例子。我做一个「每日销售报表」的批处理作业:

  • 作业:每日销售报表生成
  • 任务1:从MySQL拉取订单数据
  • 任务2:从Redis拉取实时销量缓存
  • 任务3:合并数据并计算汇总
  • 任务4:写入报表数据库

任务1和任务2可以并行跑,但任务3必须等它们都完成才能开始。这就是依赖关系。

1.3.2 调度策略

调度策略决定了「什么时候跑、怎么跑」。常见的策略有:

  • 定时调度:每天凌晨2点、每周一早上8点……用Cron表达式控制。
  • 依赖触发:上游作业跑完了,下游自动启动。比如「数据清洗」跑完才触发「数据加载」。
  • 数据驱动:某个目录有新文件到达,或者数据库表行数超过阈值,就触发作业。
  • 手动触发:运维人员点一下按钮,或者调用API启动。

注意:我曾经踩过一个坑——把定时调度和依赖触发混用,结果同一个作业被同时触发了两次,导致数据重复写入。后来我强制规定:一个作业只能有一种触发方式,除非你做了幂等处理。

1.3.3 数据一致性保证

这是批处理调度里最头疼的问题。我简单说几个关键点:

  • 原子性:一批数据要么全部处理成功,要么全部回滚。不能出现「一半入库、一半失败」的情况。
  • 幂等性:同一个作业跑两次,结果应该一样。如果下游不支持幂等,你就得自己加去重逻辑。
  • 状态管理:作业跑到哪一步了?失败了从哪重试?这些状态必须持久化,不能只存在内存里。

1.3.4 容错与重试

批处理作业跑几个小时,中间网络闪断、数据库超时、磁盘满了……什么都有可能发生。

我个人的容错原则是:

  1. 能重试的,别直接失败。比如网络超时,重试3次再说。
  2. 重试要有退避策略。别一秒重试10次,把系统打垮了。用指数退避,第一次等1秒,第二次等2秒,第三次等4秒。
  3. 超过重试次数,进死信队列。人工介入处理,别让作业卡死在那里。

1.3.5 监控与告警

批处理作业半夜跑,你不能一直盯着屏幕。所以监控必须到位:

  • 作业状态:成功、失败、运行中、等待中……一目了然。
  • 执行耗时:昨天跑了30分钟,今天跑了2小时,肯定有问题。
  • 数据量校验:输入100万条,输出只有80万条?赶紧告警。

我的习惯:每个批处理作业的最后一步,都加一个「数据对账」任务。比如统计输入行数、输出行数、异常行数,写入监控表。这样第二天早上看一眼就知道有没有问题,不用翻日志。

1.4 批处理调度核心架构图

下面这张图,是我根据多年经验总结的批处理调度核心架构。它涵盖了从作业提交到数据落地的完整链路:

批处理调度核心架构 作业提交 调度引擎 定时触发 · 依赖解析 · 优先级队列 作业执行器 任务拆分 · 并行执行 作业执行器 任务拆分 · 并行执行 作业执行器 任务拆分 · 并行执行 状态管理 持久化 · 断点续传 · 重试 容错机制 重试策略 · 死信队列 · 告警 数据存储层 关系型DB · 消息队列 · 对象存储 说明:作业提交后进入调度引擎,调度引擎根据时间/依赖关系分发到执行器,执行器并行处理任务,状态管理记录进度,容错机制处理异常,最终数据写入存储层

1.5 本章小结

批处理调度,说白了就是「在正确的时间,用正确的方式,把正确的数据处理好」。

这一章我们聊了:

  • 批处理是什么——攒一批活儿,一次性干完
  • 和实时处理的区别——延迟、吞吐、容错策略都不一样
  • 核心概念——作业与任务、调度策略、数据一致性、容错、监控

这些是基础中的基础。后面的章节,我们会深入到每个细节里去——调度引擎怎么设计、数据一致性怎么保证、分布式环境下怎么容错……

嗯,先把地基打牢,后面才好盖楼。