别人正在跑的训练任务谁能停:共享算力的作业权限与留痕

一、先把它当一次写操作,而不是一个按钮
据公开报道,某研究机构内部发生过一起用程序反复关停同事训练作业的纠纷,处理结果走到了辞退与索赔。我们不评价是非,也不复述经过。它留下的工程问题很具体:在同一套 GPU 池里,”把别人正在跑的作业停掉”在许多系统里只是一个按钮,甚至只是一行脚本。
写操作有三层含义:它改变状态、它难以撤销、它需要留下记录。停错一个作业的代价也分两层。浅的一层是算力,按小时折算,财务口径算得清。深的一层是别人攒了几周的中间状态:检查点有没有来得及落盘、优化器统计量还在不在、这一轮数据增强的随机序列能不能复现、跑了大半的超参搜索还剩多少价值。深的那一层通常更贵,事后更难自证。最麻烦的是第三层:如果系统里没有留下谁、在什么时候、以什么理由停了它,所有解释就退回到口头上,代价从算力变成信任。
治理的重点不是禁掉抢占。禁掉之后长任务会把短任务饿死,队列照样会坏。真正要治的是四件事:作业有没有主、动作向谁开放、抢占按什么语义发生、事后留下什么。这四件事应该由系统约束,不该由人际默契兜着。十几个人共用几张卡时默契够用,池子扩到几十人、跨两个部门、还接了外部合作方的算力时,默契必然失效。
二、作业要有主,但主往往不是同一个人
最常见的建模错误,是调度系统里只留一个 owner 字段。真实组织中,一个训练作业至少牵出四种归属:发起并写出这段代码的创建者;对结果负责、能回答这个作业为什么在跑的人;出钱出卡、结论要进其报告或产品的受益项目;以及作业读写的训练数据、产出的权重与中间指标这些产出物的权利归属人。四者常常分属不同的人,甚至分属不同的法人主体。
归属拆开之后,权限问题才有明确主语。谁能停这个作业,如果不先回答这个作业属于谁,就只能变成平台管理员谁都能停,最后退化成没人负责。建议落库的最小归属字段是:创建者身份、负责人身份、受益项目标识、数据与产出物的权利归属、有效期以及到期后是否自动下线、出事时第一个被联系的人。有效期这一格最容易被留空,而恰恰是它决定了三个月后那个已经没人认领的作业该不该被自动回收。
四种归属还直接影响停作业的后果由谁承担。如果产出物的权利人和创建者不是一家,典型场景是合作课题、外包标注、跨部门借用算力,那么停掉别人正在跑的作业就不只是打断,而是处置了别人的资产。这类作业要打独立标记,权限比常规作业再收紧一档,抢占动作一律要求书面事由。
三、核心交付物:动作权限矩阵
矩阵的意义在于把是否需要第二个人确认写成单独一列,而不是留在审批人的手感里。需要双人确认的动作大体两类:会影响别人正在运行的东西,以及改完之后别人看不见现场的东西。
| 动作 | 允许的角色 | 是否需要双人确认 | 必须落下的留痕字段 |
|---|---|---|---|
| 查看作业详情、日志与指标 | 同项目成员 | 否 | 按敏感级别决定是否记录读取行为 |
| 调整自己作业的排队位与优先级 | 创建者、负责人 | 否 | 调整前后的值、提交时的队列快照 |
| 调整他人作业的优先级 | 队列管理员、值班运维 | 是 | 操作者、被影响作业的负责人、书面理由 |
| 抢占或停止他人正在运行的作业 | 队列管理员限本项目,跨项目需负责人同意 | 是 | 操作者、事由、是否先通知与通知回执 |
| 暂停并保留检查点 | 创建者、负责人、值班运维 | 他人作业需通知 | 检查点保留期限、恢复优先级的算法版本 |
| 删除作业及其产出物 | 负责人,且需产出物权利人同意 | 是 | 被删对象清单、可恢复期、审批人 |
| 修改项目配额或借用他人额度 | 平台管理员 | 是 | 变更前后配额、额度来源项目、生效时段 |
| 停掉由服务账号发起的作业 | 值班运维 | 是 | 触发的流水线标识、提交人、调用来源 |
矩阵落地时有两个陷阱。一是把角色定义成部门而不是能力边界,结果是同一个人在不同项目里有不同权限,规则无法自动判定;角色应该绑定到项目与作业集合上。二是把是否需确认做成前端提示,后台仍然接收单条请求,这样绕过界面直接调接口就等于绕过确认。确认状态必须由服务端在事务里检查,缺第二条确认记录就拒绝执行。
四、抢占与排队的语义要写在文档里,不能留给实现
被抢占之后保留什么、多久、怎么回来,这三问各有常见事故。
检查点保留时长要写成显式配置,而不是靠存储没满。建议按作业标记分档:普通作业保留到下一次同配额作业开始,重要作业按天保留并明确到期清理规则,涉及外部数据源的产出物保留期由权利人确认。所有档位都要有一个兜底:过期清理动作本身也进审计流水,否则事后会出现我的数据是被谁清掉的这种追问。
恢复优先级不能按先到先得算。被抢占的作业回到队尾,等于把抢占变成一种变相的清场手段,谁有权限谁就能把别人的长任务永久推后。合理的做法是回队时沿用抢占前的优先级,并把已排队时长继续累加;抢占者要在下一次自己成为被抢占者时接受同一套算法,规则才能被所有人接受。
长作业应当设最大连续占用时长与到期续期动作。到期不是自动停止,而是要求负责人确认仍在推进并说明预期剩余时间,确认记录进审计。这一条同时保护作业主人:他有了明确的续期窗口,不必靠半夜爬起来看队列。
优雅抢占窗口是最能减少损失的一条。抢占请求落地前,先向运行中的作业发出准备信号,给出有限时间让训练循环把当前检查点写完;超时未响应再强制停止,并在审计里标注是优雅退出还是强制中断。这两种结果的差异,几周之后会体现在能不能复现上。
五、防住用脚本绕开界面停人:三条硬约束
第一条,停作业只能走带鉴权的服务接口。节点上的进程控制权、容器运行时权限、调度器的底层命令行入口,这些都不向普通研发开放,值班排障另有独立的临时通道。任何能在节点上直接 kill 进程的口子,都会让上面那张矩阵变成装饰品。
第二条,批量操作有速率与影响面上限。一次批量停止覆盖的作业数、涉及的项目数、单位时间内的调用次数都要设上限,跨项目批量必须走额外审批。这一条防的不只是恶意,更多是误操作:脚本写错一个标签选择器,可能把整个队列清空。
第三条,任何非本人操作都进入不可编辑的审计流水。审计存储与业务库分离,运维账号只有写入与读取权限、没有删改权限,保留期在制度里写明。审计的最小字段集是:操作者真实身份(不是共享账号)、时间、目标作业标识与其四种归属、动作类型、调用来源与是否为脚本发起、执行结果、是否通知负责人及回执、当时的队列快照(被停作业时队列中还有哪些作业与优先级分布)、变更前后状态摘要、关联的工单或事由编号。队列快照这一项经常被省掉,但它恰恰是复盘时唯一能回答当时抢得过来吗、停下来之后资源给了谁的东西。
六、三个失守点、取证顺序与培训
把这套规则落到调度系统时,最常出现三个洞。第一个是共享服务账号:流水线、定时任务、实验脚本共用一个令牌,审计里只看到账号名看不到人名,所有留痕在源头就废了。做法是每个自动化身份也要能反查到提交人与触发来源,令牌按项目与用途拆分。第二个是运维临时权限未回收:排障时给的破例入口,故障结束后留在系统里,成为长期旁路。临时授权要有到期时间与一次性凭证,到期自动失效并在审计里留下回收记录。第三个是管理员后门:为了紧急处理留的直连接口不走确认、不写审计,平时看不出问题,出事时恰好是唯一的解释缺口。所有旁路调用必须与正常调用写进同一条流水,并单独设置告警。
事故复盘的取证顺序也要固定下来。先固定审计流水与队列快照的不可编辑副本,再取调度器的作业事件日志与节点侧进程记录,然后核对被停作业的检查点写入时间与完整性,最后才是访谈与责任认定。顺序颠倒,现场就会被后续操作覆盖。洹拓科技自己做算力交付时,把这套顺序做成了复盘模板的第一页:先拉流水、再看快照、最后才坐下来讨论。对研发人员的培训要具体到动作,而不是讲理念。新人第一批要拿到的说明里应当写明:不允许对他人作业做什么、抢占申请怎么提、自己的作业被抢占后现场还剩什么、出问题找谁。这三条写进上手文档的第一屏,比在事故报告里追加一句加强意识有用得多。