AWS Batch 概述:核心组件与工作流程

聊到 AWS Batch,说白了它就是帮你搞定大规模批处理作业的编排服务。你不需要自己去搭建一套调度系统,也不用管底层要起多少台机器。我个人习惯把它看作一个“智能的作业调度中台”,你把任务丢进去,它自动负责扩缩容、排队和分发。

我记得刚接触那会儿,最容易混淆的就是计算环境、作业队列和任务定义这三个东西。嗯,这里我先把它们拆开讲清楚。

三大核心组件

1. 计算环境(Compute Environment)

计算环境是你所有作业实际运行的“底盘”。它管理着底层的 EC2 实例或 Fargate 容器。

  • 托管型:AWS Batch 帮你管理实例的创建和销毁,你只需设定组大最小 vCPU 数量以及实例类型。我项目中经常用的是托管型,省心。
  • 非托管型:你自己手动管理一组 EC2 实例,然后告诉 Batch 直接用这些现成的机器。这种场景不多,除非你已经有现成的集群不想动。

这里有一个配置示例:

{
  "computeEnvironmentName": "my-batch-env",
  "type": "MANAGED",
  "computeResources": {
    "type": "EC2",
    "minvCpus": 0,
    "maxvCpus": 256,
    "instanceTypes": ["c5.large", "c5.xlarge"],
    "subnets": ["subnet-12345"],
    "securityGroupIds": ["sg-67890"],
    "instanceRole": "ecsInstanceRole"
  }
}
警告:我曾经踩过一个坑,把 maxvCpus 设得太高,结果下班后忘了关环境,半夜跑了大量按需实例。控制好 vCPU 上限,特别是生产环境。

2. 作业队列(Job Queue)

作业提交后不会直接跑到计算环境里,它们先进入一个队列。队列负责缓冲、排序和分发。你可以给一个队列关联多个计算环境,并设定优先级。

  • 队列的 优先级 决定了作业被调度时的顺序。
  • 队列可以关联多个计算环境,比如先往按需计算环境上派,满负载后再往 Spot 集群上派。

举个例子,你创建一个队列:

aws batch create-job-queue \
    --job-queue-name "high-priority-queue" \
    --state ENABLED \
    --priority 10 \
    --compute-environment-order order=1,environment="my-batch-env"

3. 任务定义(Job Definition)

任务定义相当于一份“菜谱”,它描述了作业运行时的样子:用什么镜像、要多少 vCPU、内存多大、环境变量是什么?

我每次写新项目时都会先创建一个任务定义,把它当模板用。

{
  "jobDefinitionName": "my-mpi-job",
  "type": "container",
  "containerProperties": {
    "image": "myrepo/mpi:latest",
    "vcpus": 4,
    "memory": 8192,
    "command": ["run.sh", "arg1", "arg2"],
    "environment": [
      {"name": "VAR1", "value": "hello"}
    ]
  }
}
小提示:任务定义可以基于同一个镜像派生多个版本。你升级业务代码时只需更新镜像标签,然后创建一个新的任务定义修订版就行了。

完整工作流程

把上面三个组件串起来,一次典型的 AWS Batch 作业执行流程是这样的:

  1. 提交作业:用户或 CI/CD 系统调用 SubmitJob API,带上作业队列名称和任务定义 ARN。
  2. 进入队列:作业进入指定的队列等待调度。队列根据优先级和空闲计算资源决定谁先执行。
  3. 调度到计算环境:调度器看到队列里有作业,就从关联的计算环境里找可用实例。如果实例不够,它会自动扩容(托管环境)。
  4. 拉取镜像运行:调度器通过 ECS(或 EKS)在实例上启动容器,容器运行你任务定义里指定的命令。
  5. 输出结果并销毁:作业完成后,日志会写入 CloudWatch,标准输出和错误会保留。托管环境可以配置 idle 超时后自动销毁实例。
避坑指南:我曾经把一个作业卡在队列里超过1小时,后来发现是计算环境里没有可用子网。检查一下子网、安全组和 ECS 服务角色是否都能通信。

下表快速对比各组件的作用

组件职责类比(你想想看)
计算环境提供实际运行资源的“机器池”工厂里的工人和设备
作业队列缓冲、排序、分配作业工厂门口的排队订单
任务定义描述作业如何执行产品制作的工艺标准书

这里我画了一张图,把流程和组件关系整理了一下

AWS Batch 核心组件与工作流程 用户 / CI 提交 作业队列 任务定义 计算环境 EC2 / Fargate 实例 运行作业容器 输出 & 日志 流程概要 ① 用户通过 SubmitJob 将作业送入作业队列 ② 队列关联计算环境,调度器读取任务定义 ③ 计算环境在 EC2 或 Fargate 上启动容器 ④ 容器运行完成后将结果和日志写回 CloudWatch

再说说作业状态的变化

你提交一个作业后,它的状态会经历一系列变化。我习惯用以下流程来监控:

  • SUBMITTED — 作业刚提交,还没被队列调度器拾取。
  • PENDING — 队列已接受,但还在等可用计算资源。
  • RUNNABLE — 作业可以被调度了,但容器还没启动。
  • STARTING — 容器正在拉取镜像并初始化。
  • RUNNING — 作业正在执行命令。
  • SUCCEEDED / FAILED — 执行完毕或出错。
小技巧:如果你发现作业长时间卡在 RUNNABLE 状态,多半是计算环境资源满了,或者队列优先级没有正确配置。

实际项目中的选取策略

我一般在批处理任务较多时,会选择托管计算环境 + 按需实例作为主干活机器,Spot 实例作为省钱备选。这样的组合既能保证任务准时交付,又能降低成本。

# 创建一个混合计算环境,默认走按需,当按需满负载时回退到 Spot
aws batch create-compute-environment \
    --compute-environment-name "hybrid-env" \
    --type MANAGED \
    --compute-resources type=EC2,minvCpus=0,maxvCpus=100,instanceTypes=["c5.large","c5.xlarge"],bidPercentage=50,spotIamFleetRole="arn:aws:iam::xxx:role/spot-fleet-role"

最后提醒一句:作业队列和计算环境创建后,想改配置一定要仔细,弄不好会重建全部资源。 我就曾经因为触发了一次重建,导致整个队列里的所有等待作业全部失败。嗯,动手前记得备份队列里正在排队的作业。