离线任务的四大核心特性
做调度系统这几年,我接触过各种各样的离线任务。说实话,离线任务和实时任务最大的区别在哪?实时任务你盯着它跑就行,离线任务你得提前想好它怎么跑。今天我就把离线任务的四个核心特性掰开揉碎了讲清楚。
批处理任务:一次处理一批数据
离线任务最典型的特征就是批处理。什么意思?它不是来一条处理一条,而是攒够一批数据再统一处理。
我举个例子。你想想看,每天凌晨跑的用户画像计算,它要处理的是全量用户数据。几千万甚至上亿的用户,一条一条处理?那得跑到猴年马月去。所以必须批处理,一批数据一起算。
批处理任务的典型特征:
- 数据量级大,通常是 GB 甚至 TB 级别
- 执行时间长,从几分钟到几小时不等
- 资源消耗高,需要独占或半独占计算资源
- 对延迟不敏感,但要求数据一致性
我在项目中遇到过一个问题:有个批处理任务每次跑都要 3 小时,但业务方说数据必须 2 小时内出。后来一查,发现是数据倾斜导致某些节点负载过高。嗯,这里要注意,批处理任务的数据分布一定要均匀,不然就会出现「木桶效应」——一个节点拖慢整个任务。
依赖关系:任务不是孤岛
离线任务很少是独立存在的。它们之间往往有复杂的依赖关系。说白了,就是 A 任务跑完了,B 任务才能开始跑。
依赖关系一般分两种:
| 依赖类型 | 说明 | 典型场景 |
|---|---|---|
| 数据依赖 | 下游任务依赖上游任务产出的数据 | ETL 任务完成后才能跑报表任务 |
| 资源依赖 | 多个任务共享同一份资源 | 多个任务共用同一个数据库连接池 |
我曾经踩过一个坑:有个离线任务依赖上游 5 个数据源,但上游任务经常延迟。结果下游任务每天都要等很久才能开始。后来我加了个超时机制——如果上游任务超过 30 分钟还没完成,就自动触发告警并尝试从备份数据源拉取。这才把问题解决。
我的建议:设计依赖关系时,一定要考虑「依赖链断裂」的情况。比如上游任务挂了,下游任务怎么办?是等待重试,还是跳过?这些都要提前想好。
资源需求预估:别让任务饿死
离线任务对资源的需求不是固定的。有的任务吃 CPU,有的任务吃内存,有的任务吃磁盘 IO。如果你不提前预估好资源需求,很容易出现资源争抢甚至任务饿死的情况。
我个人习惯的做法是:
- 历史数据统计:看过去 7 天这个任务的平均资源消耗
- 峰值预估:按历史峰值的 1.5 倍来申请资源
- 动态调整:如果任务连续 3 次资源利用率低于 50%,就自动降配
注意:资源预估不是越精确越好。我见过有人把资源算得死死的,结果业务量一增长,任务直接 OOM。留 20%-30% 的余量是合理的。
这里我画了一张图,帮你理解资源预估的核心逻辑:
任务优先级:谁先跑谁后跑
离线任务多了,资源不够用怎么办?这时候就得靠优先级来排定顺序。
我见过很多团队把优先级分成 P0、P1、P2、P3 四级。但说实话,真正执行的时候,P0 和 P1 的区别往往很模糊。我的做法是:
- P0:核心业务链路,延迟直接影响收入
- P1:重要业务,延迟影响用户体验
- P2:常规任务,可以等一等
- P3:临时任务,有空就跑
优先级调度的核心原则:
- 高优先级任务可以抢占低优先级任务的资源
- 同优先级任务按 FIFO 顺序执行
- 长时间等待的低优先级任务可以临时提升优先级(防饿死)
我曾经遇到过一个场景:P0 任务每天凌晨 2 点跑,但有个 P2 任务因为数据量大,要跑 4 小时。结果 P2 任务把资源占满了,P0 任务只能排队等。后来我加了资源预留机制——P0 任务开始前 30 分钟,自动释放低优先级任务的资源。这才把问题解决。
一个小技巧:优先级不是一成不变的。我习惯在调度系统里加一个「动态优先级」功能——如果某个任务连续 3 次被抢占,就自动提升一级优先级。这样能避免低优先级任务永远跑不出来的情况。