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 作业执行流程是这样的:
- 提交作业:用户或 CI/CD 系统调用 SubmitJob API,带上作业队列名称和任务定义 ARN。
- 进入队列:作业进入指定的队列等待调度。队列根据优先级和空闲计算资源决定谁先执行。
- 调度到计算环境:调度器看到队列里有作业,就从关联的计算环境里找可用实例。如果实例不够,它会自动扩容(托管环境)。
- 拉取镜像运行:调度器通过 ECS(或 EKS)在实例上启动容器,容器运行你任务定义里指定的命令。
- 输出结果并销毁:作业完成后,日志会写入 CloudWatch,标准输出和错误会保留。托管环境可以配置 idle 超时后自动销毁实例。
避坑指南:我曾经把一个作业卡在队列里超过1小时,后来发现是计算环境里没有可用子网。检查一下子网、安全组和 ECS 服务角色是否都能通信。
下表快速对比各组件的作用
| 组件 | 职责 | 类比(你想想看) |
|---|---|---|
| 计算环境 | 提供实际运行资源的“机器池” | 工厂里的工人和设备 |
| 作业队列 | 缓冲、排序、分配作业 | 工厂门口的排队订单 |
| 任务定义 | 描述作业如何执行 | 产品制作的工艺标准书 |
这里我画了一张图,把流程和组件关系整理了一下
再说说作业状态的变化
你提交一个作业后,它的状态会经历一系列变化。我习惯用以下流程来监控:
- 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"
最后提醒一句:作业队列和计算环境创建后,想改配置一定要仔细,弄不好会重建全部资源。 我就曾经因为触发了一次重建,导致整个队列里的所有等待作业全部失败。嗯,动手前记得备份队列里正在排队的作业。