Series · Aliyun PAI · Chapter 3

阿里云 PAI 实战(三):PAI-DLC——不用通宵刨坑的分布式训练

在 PAI-DLC 上提交真实多卡训练任务、看懂三种资源池(灵骏、通用、抢占)、用好 AIMaster + EasyCKPT 让一台抽风节点不会让你白干一天。

DSW Notebook 是给一个工程师 + 一张卡的。一旦你需要 8 卡跨 2 机,或者训练时间超过你愿意守着浏览器的 8 小时,就该切到 DLC。DLC 是 PAI 给托管 K8s 集群做的任务提交前端:你描述要什么(镜像、命令、资源、数据挂载),DLC 调度 pod,跑完,留下日志,告诉你结果。文档叫 Deep Learning Containers,我们口头就叫 “DLC 任务”。

文档真正承诺了什么

DLC 概览里有四个特性我想画重点,因为它们都很重要:

  • 多样算力 — 灵骏 AI 智算、ECS、ECI、神龙裸金属、灵骏裸金属。支持异构混合调度。
  • 多种分布式任务 — 内置支持 Megatron、DeepSpeed、PyTorch DDP、TensorFlow PS/Worker、Slurm、Ray、MPI、XGBoost。不需要自建集群。
  • 容错 — AIMaster(看门狗)、EasyCKPT(异步 checkpoint)、SanityCheck(节点预检)、节点自愈。
  • 训练加速 — 内置加速框架,数据并行、流水线并行、算子拆分、自动并行策略探索、拓扑感知调度、优化通信库。

第一条和第三条是 DLC 比自己租 GPU ECS 强的根本理由。

任务生命周期

DLC 任务从提交到完成走六个阶段:

DLC 任务生命周期

其中两个阶段——调度落 pod挂载 OSS / NAS——是几乎所有 “我的任务卡 PENDING” 工单的发源地。卡调度是资源池满;卡挂载是存储 RAM 角色错。和 DSW 一样,排查动作就是开个小 DSW 用同样的 OSS 挂载,跑一下 oss ls 看通不通。

选资源池

你提交到三种资源池中的一个。文档讲的是配额和账单,实际决策是"任务能容忍多少抖动"。

DLC 资源池

大多数团队答案就是通用算力 + 按量付费。灵骏适合卡数 >= 8 且需要节点间 RDMA 时——文档说 RDMA 在灵骏上可配,能"加速节点间通信",翻译成实操就是 NCCL AllReduce 比标准以太网快 5-10 倍。抢占式适合能干净 checkpoint 的任务,靠 EasyCKPT 大多数任务都行。

一个真实分布式任务

四节点、每节点 2 卡的 DLC 任务拓扑:

DLC 分布式训练拓扑

把 MNIST notebook 横向扩出去的最小 SDK 提交:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pai.job import TrainingJob

job = TrainingJob(
    name="mnist-ddp",
    image_uri="dsw-registry-vpc.cn-shanghai.cr.aliyuncs.com/pai/"
              "modelscope:1.28.0-pytorch2.3.1tensorflow2.16.1-gpu-py311-cu121-ubuntu22.04",
    command=(
        "torchrun --nproc_per_node=2 --nnodes=$WORLD_SIZE "
        "--node_rank=$RANK --master_addr=$MASTER_ADDR "
        "--master_port=$MASTER_PORT /mnt/data/code/train_ddp.py"
    ),
    job_type="PyTorchJob",
    instance_count=4,                # 4 个 worker 节点
    instance_type="ecs.gn7i-c16g1.4xlarge",  # 每节点 2 × A10
    datasets={"train": "oss://your-bucket/datasets/mnist"},
    code_uri="oss://your-bucket/code/mnist-ddp.zip",
    output_uri="oss://your-bucket/runs/mnist-ddp/",
    fault_tolerance=True,            # 开 AIMaster
    enable_easyckpt=True,            # 异步 checkpoint
)
job.submit(wait=False)
print(job.id, job.status)

几个文档里要翻翻才能找到的细节:

  • $WORLD_SIZE$RANK$MASTER_ADDR$MASTER_PORT 是 DLC 注入的。你不用自己做对端发现——DLC 帮你处理对端发现并在容器启动前写好这些环境变量。(参见 User Guide 的"内置环境变量"。)
  • fault_tolerance=True 启动 AIMaster sidecar 看每个 worker。worker pod 死了,AIMaster 标记它、申请替补、其他 worker 等而不是整任务挂掉。这是任务超过几小时时最重要的开关。
  • enable_easyckpt=Truetorch.save 换成异步路径,写 OSS 不阻塞训练步。70B 模型上 checkpoint 从 3 分钟卡顿变成 ~10 秒重叠。
  • 镜像 URL 是分区域的。 dsw-registry-vpc.cn-shanghai.cr.aliyuncs.com 前缀只在上海 VPC 里能拉,跨区域用对应前缀,否则拉镜像超时。

看任务跑

控制台 “Training Jobs” 视图给你日志、GPU 利用率、网络吞吐、AIMaster 事件。SDK 里能流式拉日志:

1
2
for line in job.tail_logs(follow=True):
    print(line)

长任务我把日志转发到 SLS,并设 CloudMonitor 告警 gpu_util < 0.3 持续 15 分钟——这是数据加载或分布式初始化卡住的标准信号。

常见失败和它们真正的原因

现象真实原因
任务 Pending >5 分钟资源池满或配额耗尽。换池或减小 instance_count
启动时 cannot mount oss://...RAM 角色没挂 AliyunPAIAccessingOSSRole。在工作空间设置里重新挂。
第一步 NCCL 卡死灵骏 RDMA 配错或节点抽风。开 SanityCheck 提前隔离。
从 checkpoint 恢复后 loss 爆炸EasyCKPT 保了 optimizer state 但你没加载。用 EasyCKPT 的 load helper,不是 torch.load
任务结束但 output_uri 是空的训练脚本写到了 /root 而不是挂载的 OSS 路径。复查 OUTPUT_DIR

成本现实

典型 7B SFT(4 × A10,6 小时)通用按量付费,差不多上海一顿不错的晚饭。70B QLoRA(8 × A100 80G,12 小时)大概是杭州一个长周末的开销。抢占式如果任务能扛住每几小时被杀,能省 30-50%——配 EasyCKPT 后基本能扛。

下一篇

第四篇 EAS —— 把训完的东西塞到一个会自动扩缩、能镜像流量、半夜不会挂的 HTTP 端点后面。EAS 是你阿里云月账单的大头,值得花时间做对。

Liked this piece?

Follow on GitHub for the next one — usually one a week.

GitHub