“回滚成功”以后,用户为什么还在报错?
新镜像上线后,结构化输出开始被截断。你执行了平台的回退操作,Pod 全部 Ready,错误却没有消失。继续检查才发现:旧镜像仍从同一个目录读取“最新”tokenizer;停止字符串在另一个可变配置中;队列里还有大量积压请求。命令恢复了一个对象,却没有恢复完整的服务行为。
上线不只是启动一个进程。你需要冻结能共同产生输出的制品,决定什么时候接流量,观察真实验收指标,还要准备有条件的退出动作。第 08 课的可行运行点给出了验收口径;第 09 课的资源安排则决定新旧版本能否暂时共存。
先确定:这次到底发布了什么?
模型发布至少包含权重与校验值、tokenizer、对话模板、生成配置、运行时镜像及版本、量化与关键调度配置。若服务依赖检索或外部特征,还要记录对应索引/模式与兼容条件。模板没有改变权重,也会改变模型实际收到的输入;它仍属于发布对象。
| 对象 | 应冻结的身份 | 容易遗漏的影响 |
|---|---|---|
| 权重与精度 | 版本、文件校验值、量化方法 | 加载成功不证明质量与数值一致 |
| tokenizer / 模板 | 内容校验值与兼容版本 | 输入 token 和控制标记改变 |
| 生成条件 | EOS、stop strings、输出上限、采样 | 结束拖尾或提前截断 |
| 运行时 / 调度 | 不可变镜像、引擎版本和配置 | 接口、缓存与排队行为改变 |
| 路由 / 外部依赖 | 目标制品、接口模式和退出路径 | 旧版可能仍不兼容当前数据 |
这里的 EOS 与 stop strings 是生成停止条件,和文本清洗中的“停用词”不同。temperature 改变采样分布,不能补救错误停止条件。JSON 截断可能由 stop、输出上限、模板或客户端解析等原因造成;先保存异常样本和结束原因,再把 diff 与版本对照结合起来,不能只猜一个参数。
把发布清单交给另一人,对方应能找到同一份文件和配置;把“model=latest”写在清单里并不足够。旧包也必须完整、可读、兼容且演练过。回退不是从当前文件夹里临时拼一个看似更旧的目录。
进程活着、能够接单、质量合格,是三个判断
Kubernetes 的 startup probe 给慢初始化留时间,例如加载权重与预热;它成功之前,liveness/readiness 探测不会按通常流程执行。liveness probe 判断进程是否需要重启,例如不能前进的死锁。readiness probe 判断现在能否接收 Service 流量;失败通常让 Pod 变为未就绪,并不因此重启容器。
不能用“TCP 端口能连”代替模型可用。应用应提供适合自己的就绪状态:模型文件与版本校验完成、关键初始化结束、处理通路可用。探针要轻量;每隔几秒跑一套昂贵黄金集会制造额外负载。质量验收由发布流程和受控请求执行,不能把一次 Ready 当成全部质量、容量与恢复能力的证明。候选副本应先留在隔离的 Service 或独立路由标签中,黄金集与约定门槛通过后,再更新生产路由或提升流量权重。普通 Deployment 的 Ready 会使匹配 Service 的副本可被路由,并推动滚动,它不自带等待人工质量审批的门。
慢启动若被 liveness 过早重启,就会出现“加载—重启—再加载”的循环。只把时间阈值调得很长又可能延误真正的死锁发现。先测加载与预热时间,再设置 startup 的容忍窗口;上线后仍保留适合运行阶段的 liveness 判断。readiness 的具体 endpoint 由应用实现,本课没有一个适用于所有引擎的通用地址。
滚动发布先要借到一块资源
一张卡、一个副本,能否无中断升级?
旧 Pod 使用 1 GPU,期望副本数为 1,设置 maxUnavailable=0,maxSurge=1。计划先启动一个新 Pod,等它就绪,再删除旧 Pod。新 Pod 加载时旧 Pod 还在服务,因此需要临时第 2 块 GPU。如果集群只有原来那 1 块,新 Pod 会 Pending;旧 Pod 继续运行,升级无法向前推进。配置允许额外一个副本,没有创造一块 GPU。
你可以补充兼容的空闲资源,安排批准的维护窗口,或采用经过验证的其他发布方案,但不能直接写“滚动升级保证零停机”。第 09 课中的训练作业、配额与设备分配可能正占着这个余量。终止中的 Pod 还可能继续占设备,实际资源使用也可能暂时超过“副本数+surge”的直觉估计;要观察资源实际释放。
旧 Pod 停止接单后,还需处理已有请求。退出宽限期、连接 draining、应用关闭逻辑与网关路由共同决定长请求是否被中断。把新副本标记 Ready 和把旧连接安全排空,是两个不同动作。最后要核对失败率和完成请求,不只数 Pod。
progressDeadlineSeconds 超时会报告 ProgressDeadlineExceeded,Kubernetes Deployment 本身不会因此自动回滚。平台可能另有控制器处理它,需要核对实际配置。kubectl rollout undo 回退的是 Deployment 的 Pod template;可变的外部权重、配置文件或数据库不会自动变旧。将制品身份固定在模板所引用的不可变对象中,才让平台回退与模型回退有机会一致。
故障动作需要证据,也需要可用前提
先停止继续放量,并按预案隔离影响;然后分清版本差异、负载变化与退出目标。金丝雀“5%”不是一个安全证明:流量要有代表性,样本数和观察窗口要足够;只有 20 次请求中的 1 次新版本请求,很难支持质量已经稳定的结论。
为当前现场选下一步
已停止继续放量。比较版本、输入负载与回退可用性,再选择最合理的下一步。
A 的新版本结构化输出完整率下降,同负载旧版正常,配置 diff 指向 EOS/stop;旧包已经验证。回退能利用版本差异证据,随后复测黄金样本、结束原因和时延。B 没有发布,到达率翻倍、新旧副本都变慢:回退不会增加容量,先按既定策略限制接纳、隔离长请求,观察队列是否回落。C 的旧 tokenizer 缺失、兼容性未知:盲切可能引入新故障,先启用已有且验证可用的降级路径,再补齐旧包。
这三类动作并非互斥口号。版本回归可能同时伴随积压,回退后仍需限流清理压力;降级也可能只是临时降低功能。每项动作都应写执行前提、验证指标和未恢复时的下一步。不能把“工具命令返回 0”直接写成“事故已解决”。
恢复验收要追到用户结果
按版本和同类负载比较输出质量、结构化完整率、结束原因、输出长度、成功时延与全尝试失败率。记录接纳、队列和超时,观察积压是否持续下降。窗口里的等待和被拒绝请求仍属于需要解释的业务结果,不能只看已经完成的漂亮样本。
| 现象 | 先核对 | 下一条证据 |
|---|---|---|
| JSON 仍截断 | 实际加载的模板、tokenizer 和 stop 配置 | 按请求版本保存输入、输出和结束原因 |
| 质量恢复,TTFT 仍高 | 队列积压、到达率、输入长度 | 限制接纳后的队列趋势与失败分母 |
| 新 Pod 一直 Pending | 设备、配额、节点兼容与 surge 余量 | 调度事件与真实可用 GPU |
| Pod Ready,黄金集失败 | 就绪只证明运行通路,验收尚未通过 | 停止放量并保留失败样本 |
交付一个别人能执行的退出方案
使用 教学发布清单模板 和 处置卡模板。它们没有真实模型、地址或凭证;将示例占位符换成你能够核对的对象,未验证项明确写“未知”。本课不要求你操作真实生产集群。
- 完整制品。列出当前与目标包的身份、配置与兼容依赖,指出平台回退会恢复哪些对象、哪些需另行恢复。
- 资源推演。按上面单 GPU 示例,分别说明新 Pod Pending、已 Ready、旧 Pod 正在退出时的服务与资源状态。给出余量不足时能执行的一条路线。
- 陌生事故。回退后 JSON 完整率恢复,TTFT 仍高;到达率没下降、队列继续增长。写出已确认与尚未确认的原因、下一动作、观察窗口和未恢复时的备选。
参考与验收
单 GPU 无空闲设备时,新 Pod Pending,旧版仍在;Ready 后需质量与SLO验收才可放量;旧 Pod 退出还可能占设备并持有连接。陌生事故支持“版本质量回归已缓解”,不支持“整起故障结束”;继续检查接纳与积压,按预案限制进入量并复测。验收要求:包可定位,前提可验证,动作可执行,指标含质量与失败,窗口与备选清楚。只写“有问题回滚”未完成。
对照平台承诺,检查退出边界
Kubernetes 探针:先写下重启与停止接单的区别,再读 startup/readiness/liveness 的职责。Deployment 文档:找到 maxSurge、终止资源、进度超时和 Pod template 回退;读后在自己的清单上标出仍需另行恢复的对象。Transformers 生成参数:核对 EOS、stop strings 与输出上限。核对日期 2026-10-04;具体引擎接口要单独确认。
下一步:换平台,也要有同样清楚的验收和退出
一个可退出的发布使硬件迁移有了安全边界。第 11 课会把软件栈、精度、质量、性能和总成本放进同一份合同,避免把一张宣传参数表当成已经可替换的系统。
留下本课的产出
本课产出:发布清单与故障处置卡。写下条件、证据、结果和仍不确定的事。保存不代表自动通过,下面的状态由你按验收条件自检。
记录只保存在当前浏览器。