3. 任务编排核心概念
在金融场景中,一个日终批处理往往包含行情拉取、估值计算、风险指标生成、对账、报表输出等数十个任务。这些任务并非孤立运行,而是存在明确的先后与依赖关系。任务编排的核心,就是把这些关系用可描述、可调度、可重试的结构表达出来,并交给调度器与执行器落地。本节围绕七个核心概念展开:DAG、工作流、调度器、执行器、依赖解析、并发控制与资源隔离。
一、核心原理:从DAG到执行器
DAG(有向无环图)是任务编排的数学基础。每个节点代表一个任务实例,每条有向边代表依赖方向:A→B 表示 B 必须在 A 成功完成后才能开始。“无环”是关键约束——若存在环,依赖解析将陷入死循环,调度器无法确定任何任务的起始点。金融批处理中常见的“估值→风控→报表”就是典型链式DAG,而“多市场行情并行拉取→汇总→统一估值”则是扇入型DAG。
工作流是DAG的业务化封装,除拓扑结构外,还携带调度周期、重试策略、超时、告警、参数模板等元数据。可以理解为:DAG描述“谁依赖谁”,工作流描述“何时跑、怎么跑、失败怎么办”。
调度器负责在正确的时间点触发工作流,并持续跟踪每个任务实例的状态。它通常维护一张状态表,记录任务从“等待依赖”到“就绪”“运行中”“成功”“失败”“重试中”的迁移。执行器则是真正拉起进程、容器或远程调用的组件,它从调度器领取就绪任务,执行后回写状态与日志。
二、方法流程:一次调度的完整链路
- 调度器按周期或事件触发工作流实例,生成任务实例并初始化状态为“等待依赖”。
- 依赖解析器读取DAG边关系,计算每个任务的入度;入度为0且上游成功的任务进入就绪队列。
- 并发控制器根据工作流级与任务级并发上限,从就绪队列中选取可执行任务。
- 资源隔离层为任务分配队列、标签或容器资源,确保高优先级估值任务不被低优先级报表任务挤占。
- 执行器拉起任务,采集退出码、耗时与日志;成功则更新状态并触发下一轮依赖解析,失败则进入重试策略。
下面是一段简化的DAG定义与调度参数示例,展示了依赖、重试与资源标签如何同时表达:
workflow: eod_valuation
schedule: "0 18 * * *"
tasks:
- id: fetch_market_data
executor: python
retries: 3
retry_delay: 60
resources: {queue: "market", cpu: 2}
- id: valuation
depends_on: [fetch_market_data]
executor: spark
retries: 1
resources: {queue: "compute", memory: "16Gi"}
- id: risk_report
depends_on: [valuation]
executor: python
resources: {queue: "report"}
concurrency:
workflow_limit: 5
task_limit: 2
三、案例场景:多市场估值批处理
某券商日终需处理A股、港股、三个市场的行情,再统一估值并生成风控报表。若串行执行,总耗时约90分钟;若不加控制地全部并行,又会因行情接口限流和计算资源争抢导致大量超时。合理的编排方式是:三个行情拉取任务并行,但通过资源隔离限制在“market”队列且总并发不超过3;估值任务依赖三者全部成功,使用独立“compute”队列;报表任务依赖估值,使用“report”队列。这样既缩短了关键路径,又避免了资源冲突。
四、误区与复盘
误区一:把DAG当成流程图。流程图描述“人怎么操作”,DAG描述“任务依赖什么”。若把条件分支、人工审批直接画进DAG边,会导致依赖解析复杂化。正确做法是用任务状态与条件网关表达分支,保持DAG本身无环且语义单一。
误区二:忽视并发控制的粒度。只设工作流级并发,可能导致同一工作流内多个重任务同时抢占资源;只设任务级并发,又可能让多个工作流实例叠加压垮下游。实践中应同时配置工作流级与任务级上限,并为关键队列设置独立配额。
误区三:资源隔离只靠“标签”。标签只是声明,若执行器不按标签路由,隔离形同虚设。必须确保调度器将标签映射到实际队列或容器资源池,并在执行器侧强制校验。
| 概念 | 核心职责 | 金融场景关注点 |
|---|---|---|
| DAG | 描述任务依赖方向与无环约束 | 估值依赖行情,报表依赖估值 |
| 工作流 | 封装调度周期、重试、告警等元数据 | 日终批、盘中定时、事件触发 |
| 调度器 | 触发实例、跟踪状态、驱动依赖解析 | 交易日历、时区、延迟容忍 |
| 执行器 | 拉起任务并回写结果 | Python/Spark/Shell多运行时 |
| 依赖解析 | 拓扑排序,判定任务就绪 | 上游失败时阻断下游 |
| 并发控制 | 限制同时运行的任务数量 | 接口限流、计算资源配额 |
| 资源隔离 | 按队列/标签分配执行资源 | 估值与报表互不抢占 |