04 稳定性与性能调优实录:OOM 崩溃、并发槽位、前缀缓存与 DSpark 调参

文章目录

  • [04 稳定性与性能调优实录:OOM 崩溃、并发槽位、前缀缓存与 DSpark 调参](#04 稳定性与性能调优实录:OOM 崩溃、并发槽位、前缀缓存与 DSpark 调参)
    • [1. 事故:长会话把显存顶爆(CUDA OOM)](#1. 事故:长会话把显存顶爆(CUDA OOM))
    • [2. 取舍:ncmoe(专家上 CPU)调节阀](#2. 取舍:ncmoe(专家上 CPU)调节阀)
    • [3. 可用性事故:单槽串行 + 大系统提示词](#3. 可用性事故:单槽串行 + 大系统提示词)
      • [`--cache-reuse 256`(跨请求前缀复用)](#--cache-reuse 256(跨请求前缀复用))
      • [`-np 2`(双槽位 + 连续批处理)](#-np 2(双槽位 + 连续批处理))
    • [4. DSpark 草稿调参:n_max 3 → 5](#4. DSpark 草稿调参:n_max 3 → 5)
    • [5. 思考控制通道实测(客户端集成必读)](#5. 思考控制通道实测(客户端集成必读))
    • [6. 与官方建议对齐清单](#6. 与官方建议对齐清单)
    • [7. 现网最终配置(速查)](#7. 现网最终配置(速查))

04 稳定性与性能调优实录:OOM 崩溃、并发槽位、前缀缓存与 DSpark 调参

《DeepSeek-V4-Flash 本地部署与公网服务化》系列 · 第 ④ 篇 / 共 5 篇

① 硬件选型与 llama.cpp 部署② API 鉴权与腾讯云公网桥接③ 多协议支持:Anthropic 与 Responses API④ 稳定性与性能调优实录(本篇)⑤ 客户端接入:pi 与各类 SDK
本篇是上线后 24 小时内踩的坑与调优全过程,全部附实测数据。结论先行:./serve.sh 8081 524288 4 1 2(DSpark n_max=5 + ncmoe=4 + 双槽位 + cache-reuse)是这台 192GB 机器上速度/稳定/并发的最优点

1. 事故:长会话把显存顶爆(CUDA OOM)

现象:公网请求突然全部 502(nginx Bad Gateway)。

定位

  • 502 = nginx 连不上上游 → 跳板机 8081 隧道还在,但隧道尽头没东西了 → llama-server 进程已死,tmux 会话 ds 消失。

  • 排除网络层:隧道 autossh 进程健在;iptables 的 ! -i lo 规则正确(回环放行、丢包数 0)。

  • 日志 /tmp/serve_dspark.log 尾部铁证:

    11.31.561.655 E CUDA error: out of memory
    ggml_cuda_error ← ggml_cuda_pool_vmm::alloc
    ← argsort_f32_i32_cuda_cub ← ggml_cuda_op_top_k ← ... ← llama_decode

崩溃在 top_k 采样的 argsort 显存分配 。DSpark 全 GPU 档(ncmoe=0)每卡只剩 ~2GB 余量(01 篇的显存核算),随着会话上下文增长、KV cache 膨胀,某个 decode 步骤的采样 scratch 分配就越过了红线。llama.cpp 的崩溃处理器用 gdb 抓了完整 backtrace 写进日志,对定位帮助很大(现场备份在 /tmp/serve_dspark.log.crash.oom)。

教训--fit off + 理论核算通过 ≠ 运行时安全------KV cache 是随会话长度动态增长的,余量要按"最长会话"而不是"启动时"来留。

2. 取舍:ncmoe(专家上 CPU)调节阀

-ncmoe N 把前 N 个 MoE 专家层放到 CPU(权重 mmap,随用随读),是最有效的显存阀门:

配置 decode 显存/卡 结论
ncmoe=0 45.9 tok/s 43--48 GB(余量 ~2GB) 最快,但长会话 OOM 实锤
ncmoe=4 25.3 tok/s 36--46 GB(余量 3--13GB) 稳定,速度打 55 折

两个容易误读的现象(当时用户也疑惑过):

  • 内存/CPU"没变化"不代表没生效 :CPU 专家权重走 mmap,常驻 page cache(free 的 buff/cache 列,186GB 里就有它),不进进程 RSS;CPU 只在生成 token 的瞬间工作,空闲时是 0。判断依据是显存确实降了 + 日志有 tensor overrides to CPU are used with mmap enabled
  • ncmoe=4 时务必配 numactl --interleave=all(双路 EPYC 8 个 NUMA 节点,避免单节点带宽热点)。

3. 可用性事故:单槽串行 + 大系统提示词

现象:在一个 pi 会话正常使用时,另一个会话发请求"很久都没有反应"。

定位(看 llama-server 的 slot 日志):

复制代码
task 704 | prompt processing, n_tokens = 49152 ... 167936
         t = 101s → 450s,吞吐 485 → 368 tok/s 一路递减

两个叠加问题:

  1. -np 1 单槽串行:一个请求的 prefill + 生成没跑完,其它请求全部排队,零反馈。
  2. 大 prompt prefill 昂贵 :pi 这类 agent 客户端的系统提示词 + 工具定义 + 会话历史动辄 80K--170K tokens;168K 的 prompt 光 prefill 就要 7.5 分钟 (吞吐随上下文变长递减,attention 成本上升)。而且之前响应里 cached_tokens 一直是 0~2------同样的系统提示词每次请求都从头算

药方

--cache-reuse 256(跨请求前缀复用)

把 KV cache 中 ≥256 token 的公共前缀复用给新请求。实测:同一个 ~2050 token 的系统提示词,第二请求 cached_tokens: 1022------一半 prefill 直接跳过。pi 的系统提示词在所有请求/会话间共享,收益巨大。

注意:开启后日志有警告 cache_reuse is not supported by this context, it will be disabled------指的是 DSpark 草稿模型的上下文不支持,主模型的前缀复用不受影响(实测 cached_tokens 正常),属于良性警告。

-np 2(双槽位 + 连续批处理)

-c 524288 -np 2 = 两个 256K 槽位,llama.cpp 的 continuous batching 会把一个槽位的 prefill 与另一个槽位的 decode 混批,多会话不再互相堵死。代价:单会话上下文上限 512K → 256K(槽位间静态平分),客户端的 contextWindow 要同步调小,否则超出会被服务端硬顶回来。

意外收获:总 KV 不变,但显存反而更省(GPU1 余量 2.9 → 9.8GB)------单槽 512K 时某些缓冲区按满配 ctx 分配。

4. DSpark 草稿调参:n_max 3 → 5

官方模型卡的 vLLM 配置用 num_speculative_tokens: 7;llama.cpp 的 --spec-draft-n-max 上限是 5(草稿训练块大小,日志里 block_size=5)。实测(同一路径、同类代码生成任务):

n_max decode 接受率 备注
3 25.3 tok/s 70%(mean len 3.10) 原配置
5 34.1 tok/s(+35%) 44%(mean len 3.75) 现网配置,显存无变化

接受率"下降"是正常摊薄------每步多提 2 个候选 token,命中率自然低,但每步净接受的 token 更多,wall-clock 才是真相。

5. 思考控制通道实测(客户端集成必读)

官方模型卡写明 reasoning_effort 只有 low / high / max 三档。对 llama-server 逐个实测(--reasoning-format deepseek 模式下):

请求字段 结果
reasoning_effort: low/high/max ✅ 接受(顶层或 chat_template_kwargs 内都行)
reasoning_effort: medium/minimal/none/off ⚠️ 200 但静默忽略(回退默认思考)
reasoning_effort: disabled 关不掉思考(reasoning_content 照出)
thinking: {type: "disabled"}(DeepSeek 官方 API 风格) ❌ 被忽略,仍思考
chat_template_kwargs: {enable_thinking: false} 唯一有效的关思考通道
两者同传(enable_thinking:false + reasoning_effort:max ✅ enable_thinking 胜出

一句话:档位用 reasoning_effort(low/high/max),开关用 chat_template_kwargs.enable_thinking,别指望 DeepSeek 官方 API 的 thinking 字段。客户端映射详见 05 篇

6. 与官方建议对齐清单

官方模型卡建议 落地
temperature=1.0;agentic top_p=0.95、其它 top_p=1.0 写入客户端 samplingParams(pi 是 agentic 场景,用 0.95)
reasoning_effort = low/high/max 客户端档位映射只发这三个值
high/max 档最大输出 384K tokens 客户端 maxTokens 设 32768(稳妥值,可按需上调)
DSpark num_speculative_tokens: 7 llama.cpp 上限 5,已调到 5
无 Jinja 模板(用 encoding/ 目录 Python 脚本编码消息) llama.cpp 内置 DeepSeek V4 模板,无需关心

7. 现网最终配置(速查)

bash 复制代码
./serve.sh 8081 524288 4 1 2
# port=8081, ctx=512K(2槽×256K), ncmoe=4, dspark=1(n_max=5), np=2
# + --cache-reuse 256 + --api-key-file

decode 34.1 tok/s,显存余量 9.8--22.9GB/卡,多会话并发,同前缀 prefill 减半。从"最快但会崩"(46 tok/s @ ncmoe=0)到"稳定且够快",这笔交易是划算的。


上一篇03 多协议支持 · 下一篇05 客户端接入:pi 与各类 SDK

相关推荐
微硬创新1 小时前
大点数模拟量采集落地:耐达讯自动化32路0-20mA适配PROFINET总线实践解析
运维·人工智能·网络协议·自动化·信息与通信
星卯教育tony1 小时前
NOI Linux 2.0 服务器多用户网页桌面部署方案(腾讯云轻量Ubuntu20.04专属版 CSP复赛比赛环境搭建免安装虚拟机 )
linux·服务器·腾讯云
csdn2015_1 小时前
springboot +mybatis 查询myql开启程序级别缓存
spring boot·缓存·mybatis
隔窗听雨眠1 小时前
缓存增强生成CAG:用预加载KV缓存突破RAG实时检索瓶颈
缓存
GIS数据转换器2 小时前
村镇无人机物流配送与跨域监测一体化平台
大数据·运维·人工智能·科技·无人机
Forever Nore2 小时前
LeetCode 14 最长公共前缀 - 纵向扫描
linux·服务器·leetcode
拂拉氏2 小时前
【知识讲解】 Linux权限相关知识讲解
linux·权限
倔强的石头1062 小时前
飞牛OS部署Mtab:Docker搭建自托管书签导航并实现远程访问
运维·docker·容器
Shadow(⊙o⊙)2 小时前
Linux网络部分——TCP协议服务端客户端交互接口,入门级硬核解析1.0
linux·网络·tcp/ip