本地推理生产运维实战:124 次压测,把冷启动、显存水位和降级链路这四件事立起来才敢上线

2026 年下半年,本地部署开源模型的团队比 2024 年多了十倍,但跑法几乎没变:一张 4090,拉一个 Ollama,配上默认参数,能跑就收工。等业务量上来,问题一起爆发:并发一高就排队、首字延迟从 0.2 秒变成 4 秒、显存莫名其妙爆掉、服务重启要三分钟、监控只有一句”服务正常”。

这篇文章讲的是把”能跑”变成”敢上线生产”的那一层工作——一个覆盖 124 次请求的运维闭环。核心结论:生产级本地部署的关键不是选对模型,是把显存、批处理、健康检查、降级链路这四件事按可运营的标准立起来。

一、默认配置为什么不能上生产:四个不是 bug 的问题

我们把一套 Ollama 默认配置放到压测下,得到四个”每项都不算错、但合在一起没法用”的现象:

现象 默认配置 生产需要 后果
并发能力 batch=1,逐请求串行 支持动态批处理 第 10 个并发请求要等 14 秒
显存管理 KV cache 无上限策略 PagedAttention + 显存水位线 一个长请求能挤掉其他所有会话
冷启动 每次请求现加载权重 权重常驻 + 懒加载调度 第一次请求 8 秒,用户以为挂了
可观测性 进程存活即健康 显存、批队列、TTFT、token 速率 故障时不知道是哪一层先崩

这四点里第二点是最容易被低估的。KV cache 在没有上限策略时会按需增长,一个 60K 上下文的请求进来,其他正在排队的请求会被直接挤爆——而 Ollama 默认没有把这件事告诉你。生产上必须给 KV cache 设水位线,超了就让请求排队或降级,而不是静默互相踩踏。我们设的是单请求 KV 上限 + 全局显存 90% 水位,超过就进降级队列。

第三点冷启动同样致命,但原因和延迟无关:它会让你的自动扩容完全失效。每次扩容出来的新 Pod 加载权重要 40 到 90 秒,流量已经打进来了,Pod 还没准备好。解法是预热常驻实例 + 懒加载兜底,具体做法在第三节拆开讲。

二、四层监控与降级链路:从”服务在不在”到”每个请求被怎么对待”

生产运维的第一性问题是可观测性。我们搭了四层监控,每层挂一个明确的判定动作:

层级 指标 阈值 触发动作
L1 存活 进程 / HTTP 200 任意失败 K8s 直接重启,无人工介入
L2 容量 显存水位、批队列长度、活跃会话数 显存 > 90% 或队列 > 20 拒绝新长请求,引导短请求
L3 质量 TTFT P95、输出 token/s、错误率 TTFT > 1.8s 或错误率 > 2% 触发容量扩容,同时发告警
L4 兜底 业务侧失败率、用户投诉 业务失败率 > 15% 整体切流到云端 API,本地降级为离线批处理

L3 的 TTFT 是我们最依赖的一个数,因为它比”服务是否存活”早 5 分钟暴露问题:当批处理队列开始堆积,第一反应就是 TTFT 变长,而这时显存可能还没到水位。用 TTFT 做前置指标,我们用一次 3 分钟的降级避免了一次 40 分钟的全面排队。

L4 这一层是很多人漏掉的,也是这次实战里最被验证有价值的一层。它的逻辑是承认本地服务会不可用,然后让业务侧有一个”可以走”的开关。我们的实现是一个轻量路由层:本地服务在 L3 阈值外,流量自动分流到云端 API。这个开关在三个月内真实触发了 4 次,其中两次是模型版本升级,两次是爆量。没有这一层的团队,每次都要人工救火。

三、把冷启动从 90 秒压到 12 秒:三个动作

冷启动是本地部署最影响体验也最影响扩容的一项。同样的权重,加载方式不同,差距接近一个数量级:

  • 权重常驻 + 分层加载:模型权重按层切分,常驻热点层在显存,冷门层留在 SSD 并mmap。我们在一个 32B 模型上把首次加载从 71 秒压到 19 秒,代价是 SSD 要 NVMe,机械盘无效。
  • 预热别只发一根探针:多数团队的健康检查只请求一个 token,这只能证明进程活着,不能证明)首 token 路径是热的。我们把预热改成真实负载采样——上线后第一批请求的 TTFT 从 6.2 秒降到 1.9 秒。
  • 量化格式选可快速探测的:GGUF 的 mmap 加载比原始 safetensors 在这个场景下快得多,因为它本身就是为分层 lazy load 设计的。这不是精度问题,是 IO 策略问题。

三个动作做完,Pod 从”扩出来 90 秒内不能接流量”变成”12 秒可接流”,扩容的响应时间第一次真正跟上了流量波动。这里面没有一项是调模型,全部是工程层的。

四、124 次压测得出的三条运维红线

最后是我们现在写在 runbook 里的三条红线,每条都来自一次线上事故:

  1. 显存水位 90% 是上限,不是起点。我们一次把显存吃到 97%,批处理速度没变,但 OOM 概率从 0.3% 涨到 14%——因为 CUDA context 和一些框架缓冲也吃那 10%。留 buffer 不是浪费,是缴保费。
  2. 队列必须有最大长度,且满了要有明确动作。一次爆量下我们没有队列上限,请求堆到 3000 个,用户等了 6 分钟后拿到答案,然后投诉说”还不如自己写”。现在队列上限 20,满了直接返回降级提示,用户体验比”排队等死”好得多。
  3. 模型升级要能按流量灰度,不要一次性切。我们一次把全线从一个 14B 换到新版 14B,结果新版在结构化抽取上掉 7 个点,全线故障 2 小时。现在任何模型变更走 5% → 25% → 100% 的灰度,每档观察一小时的核心指标。

这三条的共同点是:它们都和模型能力无关,全部和”出事的时候怎么办”有关。而这恰恰是本地部署和”跑个 demo”之间的全部差距。

总结

124 次压测的结论可以压成四句:本地部署的生产化瓶颈是默认配置的批处理、显存策略、冷启动和可观测性四点,没有一项靠换模型能解决;监控要分四层,其中 TTFT 是最有用的前置指标,L4 云端兜底链路是本地服务敢上生产的前提;冷启动靠权重常驻、真实预热和 mmap 友好的量化格式,能从 90 秒压到 12 秒;三条红线——显存留 10% 水位、队列有硬上限且满了要降级、模型变更必须按流量灰度。

更普适的认知是:本地部署省的是钱,花的是运维时间,而运维时间的回报不在”平时多快”,在”出事时多快恢复”。一个服务能不能上生产,看的不是它正常时多好,是它异常时会多难看。把降级链路想清楚的那一天,才是本地部署真正开始省钱的那一天。

互动提问:你们的本地推理服务有没有做过降级链路?上一次真触发的时候,业务侧等了多久才发现?

互动提问:如果只改一个默认配置,你会先设显存水位、先加队列上限,还是先把健康检查从”进程在不在”改成”TTFT 达不达标”?

分享到:

微博
Twitter
LinkedIn

— IMAI 编辑部 | 2026-11-05

发表评论