当算力成为稀缺资源:如何把社会公平写进调度规则

2026-07-24 19 预计阅读时间: 1 分钟
来源: ruanyifeng.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:8 分钟

当 AI 训练、推理和数据处理开始争夺同一批 GPU,算力就不再只是采购问题,也变成了资源分配问题。谁能获得资源、等待多久、为此支付多少成本,都会影响个人、团队乃至组织参与技术创新的机会。讨论“资源、社会公平与算力”,真正值得工程师追问的是:公平能否从抽象原则变成可检查、可执行的系统规则?

算力分配不只有吞吐量

传统调度器通常优化利用率、吞吐量或任务完成时间。这些指标很重要,但它们没有回答资源应该优先服务谁。

例如,一支拥有大量预算的团队可以持续提交长时间 GPU 任务。如果系统只采用先到先得策略,小团队的短任务可能长期排队;如果完全按照价格竞价,资金优势又会直接转化为算力优势。两种策略都很容易实现,却未必符合组织希望维护的公平边界。

工程上可以把公平拆成几个可测量的问题:

  • 每个团队获得的 GPU 时长是否与约定份额一致?
  • 小任务和交互式实验是否存在最大等待时间?
  • 是否为教学、公益研究或低预算项目保留基础额度?
  • 高优先级任务能否抢占资源,谁有权设置优先级?
  • 配额、排队时间和拒绝原因是否对使用者透明?

这些问题不能只靠一句“使用公平调度”解决。配额控制的是上限,优先级决定排队次序,抢占机制处理资源冲突,审计日志则负责解释结果。它们需要组合使用。

从平均分配转向可解释分配

平均分配看似公平,但不同任务的需求并不相同。一次课程实验可能只需要一张 GPU 和两个小时,模型训练则可能连续占用八张 GPU 数天。简单地给每个团队相同数量的设备,可能造成一边闲置、一边拥堵。

更实用的办法是建立“基础保障加弹性借用”模型:每个租户拥有最低保障额度;空闲算力可以被其他租户借用;当原租户需要资源时,系统通过排队或抢占逐步收回。这样既避免资源静置,也不会让长期高负载用户永久占据公共资源。

但权重本身也是政策。团队人数、历史使用量、项目价值和付费水平都可以成为权重来源,而每一种选择都会产生不同结果。因此,调度规则至少应具备版本记录、审批流程和定期复核,而不是作为一组无人解释的配置长期运行。

可以这样实践:模拟加权公平分配

下面的 Python 程序演示一种简化的加权分配方法。它先满足各团队的基础保障,再按照权重逐个分配剩余 GPU,同时不超过团队申报的需求。

运行前只需要安装 Python 3;可以修改 TOTAL_GPUSTEAMS,观察不同配额与权重如何改变结果。

from dataclasses import dataclass


@dataclass
class Team:
    name: str
    demand: int
    guaranteed: int
    weight: int
    allocated: int = 0


TOTAL_GPUS = 16
TEAMS = [
    Team("teaching", demand=6, guaranteed=3, weight=3),
    Team("research", demand=12, guaranteed=4, weight=2),
    Team("commercial", demand=16, guaranteed=2, weight=1),
]


def allocate(total: int, teams: list[Team]) -> None:
    # 先发放基础保障,但不超过实际需求。
    for team in teams:
        grant = min(team.demand, team.guaranteed, total)
        team.allocated += grant
        total -= grant

    # 按权重轮转分配剩余资源,直到资源或需求耗尽。
    while total > 0:
        progressed = False
        for team in teams:
            for _ in range(team.weight):
                if total == 0:
                    break
                if team.allocated < team.demand:
                    team.allocated += 1
                    total -= 1
                    progressed = True
        if not progressed:
            break


allocate(TOTAL_GPUS, TEAMS)
for team in TEAMS:
    print(
        f"{team.name:12} demand={team.demand:2} "
        f"allocated={team.allocated:2} "
        f"satisfaction={team.allocated / team.demand:.0%}"
    )

这段代码适合讨论规则,不适合直接充当生产调度器。真实系统还必须处理任务时长、GPU 型号、显存容量、节点拓扑、抢占成本和恶意申报等问题。更重要的是,应同时记录“请求了多少”“等待了多久”和“为什么没有得到资源”,否则只能看到分配结果,无法判断过程是否公平。

如果使用 Kubernetes,可以这样实践:先用命名空间配额建立硬边界。下面假设集群中的 GPU 资源名为 nvidia.com/gpu,实际名称应按设备插件调整。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: gpu-quota
  namespace: teaching
spec:
  hard:
    requests.nvidia.com/gpu: "4"
    limits.nvidia.com/gpu: "4"
    count/pods: "20"

应用并检查配额:

kubectl apply -f gpu-quota.yaml
kubectl describe resourcequota gpu-quota -n teaching
kubectl get pods -n teaching --sort-by=.metadata.creationTimestamp

ResourceQuota 只能限制资源总量,不能单独保证等待时间或实现跨团队加权公平。生产环境通常还需要队列、优先级、准入控制以及可观测性组件协同工作。

落地前检查这五件事

算力公平不是让所有人得到完全相同的资源,而是让差异化分配拥有公开理由、明确下限和申诉空间。落地时可以检查以下事项:

  1. 定义目标:明确系统优化的是利用率、等待时间、最低保障,还是几者之间的平衡。
  2. 公布规则:让用户知道配额、优先级、抢占条件和预计等待时间。
  3. 保留审计:记录请求、分配、拒绝、抢占和规则版本。
  4. 防止固化:定期检查权重是否让既有优势不断累积。
  5. 小范围试运行:先在一个队列或命名空间验证,再扩大影响范围。

算力越稀缺,默认规则的影响就越大。工程团队不可能用调度算法解决全部社会问题,但可以避免把未经讨论的价值判断隐藏在队列、价格和配置文件里。


相关推荐