生产运维与故障恢复:服务上线后要做的事
文章目录
- 生产运维与故障恢复:服务上线后要做的事
-
- 概览
- [1. 重启耗时构成:三档场景与两个变量](#1. 重启耗时构成:三档场景与两个变量)
- [2. 监控指标:五组信号与首个处置动作](#2. 监控指标:五组信号与首个处置动作)
- [3. 常见故障与处置:十项历史案例的最低限度动作](#3. 常见故障与处置:十项历史案例的最低限度动作)
- [4. 变更流程六步:修改配置的正确做法](#4. 变更流程六步:修改配置的正确做法)
- [5. 缓存目录管理:属主与跨机迁移](#5. 缓存目录管理:属主与跨机迁移)
- [6. 镜像升级七步:新镜像的使用流程](#6. 镜像升级七步:新镜像的使用流程)
- [7. 已知约束清单:六项长期登记条目](#7. 已知约束清单:六项长期登记条目)
- [8. 交接说明与常用 make 目标](#8. 交接说明与常用 make 目标)
概览
- 重启耗时有明确构成 :全热 376 秒、半冷 520 秒、全冷(NFS)21 分钟起步。差异来自两个独立变量,页缓存是否命中、
cache/中的 JIT 产物是否完整。 - 监控指标共五组 :权威存活探针
/health(而不是/v1/models)、waiting 队列长度、MTP 接受长度守卫(接受长度低于 1.5 表示投机解码未生效)、KV 池账实核对(部署形态二热重启基线为 1,320,553 tokens)。 - 常见故障与处置 :软链接空挂、三卡
TP=3不合法、KV 池未设上限、custom all-reduce 预热失败、首个请求 OOM、端口被占用、双实例同时加载、探活前缀误匹配、中间件未挂载导致 401,以及一桩至今未复现的步时异常。 - 变更流程共六步 :备份、重启、准入检查、采样(运行基准测试)、生成表格、复盘。
.env不入库,未走完流程的变更没有回滚依据。 - 镜像升级共七步:拉取新镜像后先做环境自检(digest 变化会被检出),再以新镜像为基底重新生成补丁并核对双启动路径,最后必须通过准入检查与对比基准测试。
1. 重启耗时构成:三档场景与两个变量
- 运维首先要记住三档场景的到就绪时间:
| 场景 | 条件 | 权重加载 | init engine | 总到就绪 |
|---|---|---|---|---|
| 全热(首选) | 页缓存命中且 cache/ 中四类 JIT 产物完整 |
228-245 s | 31.5-36.1 s | 约 376 s |
| 半冷 | 页缓存命中,但更换了并行度或 cache/ 为空 |
261-293 s | 182.09 s | 约 520 s |
| 全冷 | 新机器或页缓存未命中 | I/O 占主导 | 同半冷 | 21 分钟起步 |
- 耗时差异只由两个独立因子决定:页缓存是否命中 决定权重加载耗时,并行度是否变更 决定
init engine耗时。两者可以分别处理:预热脚本(warm_cache.sh)针对前者,cache/中四类 JIT 产物(vllm、triton、tilelang、inductor)的完整性针对后者。
#mermaid-svg-DCThAsBWhQJKvzUy{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DCThAsBWhQJKvzUy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DCThAsBWhQJKvzUy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DCThAsBWhQJKvzUy .error-icon{fill:#552222;}#mermaid-svg-DCThAsBWhQJKvzUy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DCThAsBWhQJKvzUy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DCThAsBWhQJKvzUy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DCThAsBWhQJKvzUy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DCThAsBWhQJKvzUy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DCThAsBWhQJKvzUy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DCThAsBWhQJKvzUy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DCThAsBWhQJKvzUy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DCThAsBWhQJKvzUy .marker.cross{stroke:#333333;}#mermaid-svg-DCThAsBWhQJKvzUy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DCThAsBWhQJKvzUy p{margin:0;}#mermaid-svg-DCThAsBWhQJKvzUy .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DCThAsBWhQJKvzUy .cluster-label text{fill:#333;}#mermaid-svg-DCThAsBWhQJKvzUy .cluster-label span{color:#333;}#mermaid-svg-DCThAsBWhQJKvzUy .cluster-label span p{background-color:transparent;}#mermaid-svg-DCThAsBWhQJKvzUy .label text,#mermaid-svg-DCThAsBWhQJKvzUy span{fill:#333;color:#333;}#mermaid-svg-DCThAsBWhQJKvzUy .node rect,#mermaid-svg-DCThAsBWhQJKvzUy .node circle,#mermaid-svg-DCThAsBWhQJKvzUy .node ellipse,#mermaid-svg-DCThAsBWhQJKvzUy .node polygon,#mermaid-svg-DCThAsBWhQJKvzUy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DCThAsBWhQJKvzUy .rough-node .label text,#mermaid-svg-DCThAsBWhQJKvzUy .node .label text,#mermaid-svg-DCThAsBWhQJKvzUy .image-shape .label,#mermaid-svg-DCThAsBWhQJKvzUy .icon-shape .label{text-anchor:middle;}#mermaid-svg-DCThAsBWhQJKvzUy .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DCThAsBWhQJKvzUy .rough-node .label,#mermaid-svg-DCThAsBWhQJKvzUy .node .label,#mermaid-svg-DCThAsBWhQJKvzUy .image-shape .label,#mermaid-svg-DCThAsBWhQJKvzUy .icon-shape .label{text-align:center;}#mermaid-svg-DCThAsBWhQJKvzUy .node.clickable{cursor:pointer;}#mermaid-svg-DCThAsBWhQJKvzUy .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DCThAsBWhQJKvzUy .arrowheadPath{fill:#333333;}#mermaid-svg-DCThAsBWhQJKvzUy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DCThAsBWhQJKvzUy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DCThAsBWhQJKvzUy .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DCThAsBWhQJKvzUy .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DCThAsBWhQJKvzUy .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DCThAsBWhQJKvzUy .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DCThAsBWhQJKvzUy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DCThAsBWhQJKvzUy .cluster text{fill:#333;}#mermaid-svg-DCThAsBWhQJKvzUy .cluster span{color:#333;}#mermaid-svg-DCThAsBWhQJKvzUy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DCThAsBWhQJKvzUy .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DCThAsBWhQJKvzUy rect.text{fill:none;stroke-width:0;}#mermaid-svg-DCThAsBWhQJKvzUy .icon-shape,#mermaid-svg-DCThAsBWhQJKvzUy .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DCThAsBWhQJKvzUy .icon-shape p,#mermaid-svg-DCThAsBWhQJKvzUy .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DCThAsBWhQJKvzUy .icon-shape .label rect,#mermaid-svg-DCThAsBWhQJKvzUy .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DCThAsBWhQJKvzUy .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DCThAsBWhQJKvzUy .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DCThAsBWhQJKvzUy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 要等多久?
页缓存命中且 cache 目录完整:约 376 秒就绪
更换了并行度或 cache 目录为空:追加约 150 秒 JIT 编译
页缓存也未命中:21 分钟起步,先预热页缓存
- 一条容易被忽略的运行约束:双实例并存时,权重加载本身需要排队。实测两个实例同时加载权重时,checkpoint 反序列化会把 230 秒的加载拖到 690 秒以上,慢约三倍,同一时段的压测数据也随之作废。仓库的处理方式是文件锁加错峰启动:加载阶段持独占锁、测量阶段持共享锁。
2. 监控指标:五组信号与首个处置动作
- 建议同时监控五组信号,每组信号都对应一个明确的判读结论与首个处置动作:
| 监控信号 | 观测内容 | 判读 / 行动建议 |
|---|---|---|
| 存活 | GET /health 返回 200 |
引擎已死时 /health 返回 5xx,而 /v1/models 仍可能返回 200,需以 /health 为准 |
| 负荷 | 日志中的 running / waiting 队列行 | waiting 持续增长意味着并发已打满 |
| 投机解码健康度 | 接受长度是否低于 1.5 | 接受长度低于阈值时,先确认投机解码是否真的生效 |
| 账实相符 | 可用 KV 池与基线比对 | KV 池差额超过一成时,先怀疑参数未生效,而不是显存异常 |
| 步时 | 与 25.66 毫秒参考值的偏差 | 记录:某次步时从 25.6 升到 31.5 并持续约 15 分钟后自行恢复,至今未复现------建议先重启引擎恢复服务 |
3. 常见故障与处置:十项历史案例的最低限度动作
- 每条处置分两级:第一反应先恢复服务,根治动作再定位根因。
| 编号 | 症状关键词 | 第一反应 | 根治动作与来源 |
|---|---|---|---|
| 1 | 流水并行不支持报错 | 检查镜像版本 | 换用包含多流交接实现的 backport 镜像 |
| 2 | 加载期连续显存分配失败 | 核对分配策略键 | 确认 expandable_segments:True 在位(01 篇与根 README 的分配器配置说明) |
| 3 | 32k 请求导致引擎崩溃 | 确认投机解码与 KV 上限是否配套 | 显式设置 8 GiB 或 16 GiB 上限(02 篇实测案例 2) |
| 4 | 预热阶段 custom all-reduce 报 164 错 | 核查部署形态一的开关设置 | 将该开关置 1,或切换到部署形态二(03 篇) |
| 5 | 首个真实请求即 OOM | 检查总显存占用是否超额 | 把上下文上限降到 512k、KV 池设为 8 GiB,或切换到部署形态二以启用 1M 上下文(E3 实验结论) |
| 6 | 端口被占用 | 停止旧容器 | 停服后重新启动,或修改监听端口 |
| 7 | 双实例同时加载导致三倍变慢 | 先停掉其中一个实例 | 错峰启动或等待就绪(05 篇测量准则 4) |
| 8 | 探活误报其他实例仍存活 | 复查匹配策略 | 改用 docker inspect 精确匹配,不使用前缀过滤(仓库已修复,勿回退) |
| 9 | 仅 Anthropic 客户端返回 401 | 确认中间件挂载 | 核对该行与鉴权目录挂载(04 篇) |
| 10 | 权重路径类仓库校验错 | 检查软链接 | 在环境文件中写真实绝对路径(01 篇) |
- 一条原则:故障处置的第一个动作都是读日志,而不是重启;重启是第二个动作,且必须在证据保全之后执行。
4. 变更流程六步:修改配置的正确做法
- 对配置文件的任何永久性修改都必须走完以下六个步骤约束:
#mermaid-svg-dLXDyywuVyyeJchJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dLXDyywuVyyeJchJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dLXDyywuVyyeJchJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dLXDyywuVyyeJchJ .error-icon{fill:#552222;}#mermaid-svg-dLXDyywuVyyeJchJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dLXDyywuVyyeJchJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dLXDyywuVyyeJchJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dLXDyywuVyyeJchJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dLXDyywuVyyeJchJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dLXDyywuVyyeJchJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dLXDyywuVyyeJchJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dLXDyywuVyyeJchJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dLXDyywuVyyeJchJ .marker.cross{stroke:#333333;}#mermaid-svg-dLXDyywuVyyeJchJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dLXDyywuVyyeJchJ p{margin:0;}#mermaid-svg-dLXDyywuVyyeJchJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dLXDyywuVyyeJchJ .cluster-label text{fill:#333;}#mermaid-svg-dLXDyywuVyyeJchJ .cluster-label span{color:#333;}#mermaid-svg-dLXDyywuVyyeJchJ .cluster-label span p{background-color:transparent;}#mermaid-svg-dLXDyywuVyyeJchJ .label text,#mermaid-svg-dLXDyywuVyyeJchJ span{fill:#333;color:#333;}#mermaid-svg-dLXDyywuVyyeJchJ .node rect,#mermaid-svg-dLXDyywuVyyeJchJ .node circle,#mermaid-svg-dLXDyywuVyyeJchJ .node ellipse,#mermaid-svg-dLXDyywuVyyeJchJ .node polygon,#mermaid-svg-dLXDyywuVyyeJchJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dLXDyywuVyyeJchJ .rough-node .label text,#mermaid-svg-dLXDyywuVyyeJchJ .node .label text,#mermaid-svg-dLXDyywuVyyeJchJ .image-shape .label,#mermaid-svg-dLXDyywuVyyeJchJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-dLXDyywuVyyeJchJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dLXDyywuVyyeJchJ .rough-node .label,#mermaid-svg-dLXDyywuVyyeJchJ .node .label,#mermaid-svg-dLXDyywuVyyeJchJ .image-shape .label,#mermaid-svg-dLXDyywuVyyeJchJ .icon-shape .label{text-align:center;}#mermaid-svg-dLXDyywuVyyeJchJ .node.clickable{cursor:pointer;}#mermaid-svg-dLXDyywuVyyeJchJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dLXDyywuVyyeJchJ .arrowheadPath{fill:#333333;}#mermaid-svg-dLXDyywuVyyeJchJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dLXDyywuVyyeJchJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dLXDyywuVyyeJchJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dLXDyywuVyyeJchJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dLXDyywuVyyeJchJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dLXDyywuVyyeJchJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dLXDyywuVyyeJchJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dLXDyywuVyyeJchJ .cluster text{fill:#333;}#mermaid-svg-dLXDyywuVyyeJchJ .cluster span{color:#333;}#mermaid-svg-dLXDyywuVyyeJchJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dLXDyywuVyyeJchJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dLXDyywuVyyeJchJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-dLXDyywuVyyeJchJ .icon-shape,#mermaid-svg-dLXDyywuVyyeJchJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dLXDyywuVyyeJchJ .icon-shape p,#mermaid-svg-dLXDyywuVyyeJchJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dLXDyywuVyyeJchJ .icon-shape .label rect,#mermaid-svg-dLXDyywuVyyeJchJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dLXDyywuVyyeJchJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dLXDyywuVyyeJchJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dLXDyywuVyyeJchJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 一 备份:cp 加时间戳,.env 的唯一回滚依据
二 重启:serve 加 wait,等待三档耗时之一
三 准入检查:四关全部通过才可继续
四 采样:运行一轮基准测试并入库,标签按命名规范生成
五 生成表格:用渲染脚本重新生成表格,不再手工誊抄
六 复盘:在变更说明中写清口径与前后差值,供后续注释与复盘引用
-
仓库
CHANGELOG.md的开篇说明为这套流程提供了依据:性能数字只有在测量口径一致的前提下才会被记录,原始记录始终在bench/results/*.jsonl中,变更日志只是索引。这也解释了本系列每篇都要强调测量准则与实测案例的原因:口径不统一时,导致错误结论的往往不是工程师的操作,而是不可靠的测量结果。 -
除正式流程外,仓库也允许临时试验:管理员可以为一次性对照实验临时设置环境变量并启动服务,但长期方案必须写回配置文件并提交评审。临时值不会进入正式档案,CI 也不接受这种配置。这条「临时方案必须转为正式配置」的规则,避免了把一次性改动长期留在本地环境文件或临时文本中。
5. 缓存目录管理:属主与跨机迁移
cache/下的四类 JIT 产物(vllm、triton、tilelang、inductor)由容器以 root 身份创建,宿主普通用户直接删除会遇到属主权限限制,正确做法是通过容器执行删除,仓库提供的make clean-cache目标即为此。除供本机重启复用外,缓存目录还支持跨机迁移:相同 GPU 架构的机器之间可以整目录复制 ,做法是打包与解包,按CACHE_ROOT的相对结构打包成压缩件,传输到目标机器后在对应位置解压。- 缓存目录的收益:冷缓存下
init engine需要 182 秒,缓存命中后长期落在 31.5 至 36.1 秒区间。也就是说,每次重启可节省约 150 秒。另一个变量同样重要:重启前先运行一次预热脚本 (warm_cache.sh)是运维手册的明确要求,因为页缓存是否命中会显著影响权重加载耗时。两项措施同时落实后,从冷启动到第一个 token 的整个耗时过程都在可预估范围内。
多实例部署的四项必改变量:如果需要在同一台机器上运行两个实例(用于对照实验或按卡分配),仓库要求四个变量必须同时修改。任何一项遗漏都会导致后启动的实例影响先启动的实例:
#mermaid-svg-HORXVxtcG3ygiXaR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HORXVxtcG3ygiXaR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HORXVxtcG3ygiXaR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HORXVxtcG3ygiXaR .error-icon{fill:#552222;}#mermaid-svg-HORXVxtcG3ygiXaR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HORXVxtcG3ygiXaR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HORXVxtcG3ygiXaR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HORXVxtcG3ygiXaR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HORXVxtcG3ygiXaR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HORXVxtcG3ygiXaR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HORXVxtcG3ygiXaR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HORXVxtcG3ygiXaR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HORXVxtcG3ygiXaR .marker.cross{stroke:#333333;}#mermaid-svg-HORXVxtcG3ygiXaR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HORXVxtcG3ygiXaR p{margin:0;}#mermaid-svg-HORXVxtcG3ygiXaR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HORXVxtcG3ygiXaR .cluster-label text{fill:#333;}#mermaid-svg-HORXVxtcG3ygiXaR .cluster-label span{color:#333;}#mermaid-svg-HORXVxtcG3ygiXaR .cluster-label span p{background-color:transparent;}#mermaid-svg-HORXVxtcG3ygiXaR .label text,#mermaid-svg-HORXVxtcG3ygiXaR span{fill:#333;color:#333;}#mermaid-svg-HORXVxtcG3ygiXaR .node rect,#mermaid-svg-HORXVxtcG3ygiXaR .node circle,#mermaid-svg-HORXVxtcG3ygiXaR .node ellipse,#mermaid-svg-HORXVxtcG3ygiXaR .node polygon,#mermaid-svg-HORXVxtcG3ygiXaR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HORXVxtcG3ygiXaR .rough-node .label text,#mermaid-svg-HORXVxtcG3ygiXaR .node .label text,#mermaid-svg-HORXVxtcG3ygiXaR .image-shape .label,#mermaid-svg-HORXVxtcG3ygiXaR .icon-shape .label{text-anchor:middle;}#mermaid-svg-HORXVxtcG3ygiXaR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HORXVxtcG3ygiXaR .rough-node .label,#mermaid-svg-HORXVxtcG3ygiXaR .node .label,#mermaid-svg-HORXVxtcG3ygiXaR .image-shape .label,#mermaid-svg-HORXVxtcG3ygiXaR .icon-shape .label{text-align:center;}#mermaid-svg-HORXVxtcG3ygiXaR .node.clickable{cursor:pointer;}#mermaid-svg-HORXVxtcG3ygiXaR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HORXVxtcG3ygiXaR .arrowheadPath{fill:#333333;}#mermaid-svg-HORXVxtcG3ygiXaR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HORXVxtcG3ygiXaR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HORXVxtcG3ygiXaR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HORXVxtcG3ygiXaR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HORXVxtcG3ygiXaR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HORXVxtcG3ygiXaR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HORXVxtcG3ygiXaR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HORXVxtcG3ygiXaR .cluster text{fill:#333;}#mermaid-svg-HORXVxtcG3ygiXaR .cluster span{color:#333;}#mermaid-svg-HORXVxtcG3ygiXaR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HORXVxtcG3ygiXaR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HORXVxtcG3ygiXaR rect.text{fill:none;stroke-width:0;}#mermaid-svg-HORXVxtcG3ygiXaR .icon-shape,#mermaid-svg-HORXVxtcG3ygiXaR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HORXVxtcG3ygiXaR .icon-shape p,#mermaid-svg-HORXVxtcG3ygiXaR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HORXVxtcG3ygiXaR .icon-shape .label rect,#mermaid-svg-HORXVxtcG3ygiXaR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HORXVxtcG3ygiXaR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HORXVxtcG3ygiXaR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HORXVxtcG3ygiXaR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 容器名不同,否则后启动的实例会直接删除先启动的容器
端口号不同,否则启动时端口冲突
缓存根不同,否则两个实例争用同一份 Triton 缓存
日志文件不同,否则两路日志混写
约束:四项必须同时设置,缺一项会导致实例互相干扰、数据作废
6. 镜像升级七步:新镜像的使用流程
镜像升级会重新检验前面各篇的所有结论,流程必须严格按以下七步执行:
- 拉取与自检 :拉取新镜像后立即执行一次环境自检(
setup.sh --check),digest 变化会被明确报出;这一步每次升级都要执行; - 更新镜像字段 :更新
.env中的镜像字段,必要时固定IMAGE_DIGEST(可复现性要求,从项目初期就已采用); - 重建补丁 :以新镜像中的文件为基底重新生成 overlay 文件,然后重新施加本地补丁------严禁新旧两代 overlay 混用;若新镜像已自带修复,直接移除对应的挂载点;
- 核对双启动路径 :运行 compose 校验,并确认 compose 与
serve.sh两条启动路径的开关一致; - 启动与准入检查 :依次执行
serve.sh、wait_ready.sh与四关准入检查,任何一关未通过都应停止升级; - 对比基准测试:以相同口径运行一轮基准测试并以升级标签入库,与升级前的记录逐项对比;
- 准备回滚方案 :如果最终结果不理想,从带时间戳的备份恢复环境文件、回退镜像字段,再执行
wait_ready.sh等待三档耗时之一,重启一次即可回滚。
这套七步流程并非冗余:仓库曾出现过实际事故,镜像内某协议文件换代时,上一代补丁与新基底合并后不是行为失准就是完全未生效。检查只读挂载是否有效固然重要,但以新镜像中的文件为基底重新生成才是根本解决办法。这条警示在 overlays/README.md 中以粗体标注,是镜像升级中最关键的一条要求。
7. 已知约束清单:六项长期登记条目
- 本套件把所有已知限制公开登记,读者不必在遇到问题之后才发现这些限制一直存在。以下六项与根 README「已知约束」严格同号 (那份清单只保留"当前仍未解决"的条目,已修复的移入
CHANGELOG.md):
| 条目 | 摘要 |
|---|---|
1 mamba_cache_mode 只能用 align,且镜像不可回退 |
prefix caching 本身已于 2026-09-26 起的镜像修复并默认开启;残留两条:none 仍触发 CUDA illegal memory access,2026-09-10 及更早的镜像开了会返回空正文 |
| 2 投机解码与 KV 上限必须配套 | MTP 深度大于 1 时必须显式设置 KV 上限:部署形态一为 8 GiB,部署形态二为 16 GiB;留空会在 32k 请求上 CUDA OOM |
| 3 EP 与深 MTP 不叠加 | EP 单独使用收益明显(并发 8 提升 54%),叠加 MTP 后并发 421 对 421,单流 32k 反而下降 |
| 4 长上下文的单次读数不可信 | 1M token 上下文的 TTFT 三次测量均为 312 秒;早前一次 417 秒的孤立读数曾被写成「慢 34%」的结论,现已更正并记录在案 |
| 5 并行拓扑:TP 越大 prefill 越慢 | all-reduce 跨 PCIe 的代价。两条硬约束:TP=2×PP=2 装不下「1M + MTP 6 + CUDA graph」(默认上限 512k),且必须 DISABLE_CUSTOM_ALL_REDUCE=1;4 卡 TP=4 的 1M prefill 慢于 3 卡 PP=3(312 s 对 200 s) |
| 6 未定因的解码退化 | 长时间运行后 2k 档步时从 25.6 ms 升到 31.5 ms,约 15 分钟后重启恢复;已排除 KV 碎片化、持续负载、功耗节流与其他租户,尚未复现 |
8. 交接说明与常用 make 目标
bash
make doctor ------ 只读环境自检
make warm ------ 预热页缓存
make up ------ 启动服务
make wait ------ 等待就绪
make logs ------ 跟随日志
make down ------ 停止并删除容器
- 部署的目标不只是让服务运行起来,而是让下一个接手的人能追溯每一个数字的出处。本系列各篇的实验记录、本章的六项已知约束,以及通篇记录的测量口径,共同构成了这套部署的可追溯基础。