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

相关推荐
蒸蒸yyyyzwd13 分钟前
cpp选手秋招学习笔记day24-cs144项目总结
运维·服务器·网络
ang78418 分钟前
日常高频使用的 Ansible 命令,按使用频率和场景整理。
linux·运维·服务器
高亦真32 分钟前
今天是学习嵌入式的第35天
linux·学习·算法
mounter6251 小时前
eBPF 驱动的云原生网络变革:Cilium 的前世今生与全机套接字迭代技术演进
linux·ebpf·linux kernel·kernel
赵庆明老师1 小时前
用同一个用户登录宝塔面板的ftp与Linux的sftp
linux·运维·服务器
oushaojun21 小时前
深入理解 Linux I2C 框架:内核子系统分层解析(转)
linux
山君爱摸鱼1 小时前
堡垒机远程服务器故障收集
运维·服务器
不会就选b2 小时前
Linux之socket编程(六)----TCP-->模拟shell命令
linux·运维·tcp/ip
跨境数据猎手2 小时前
京东开放平台商品详情接口(jd.item_get):签名、缓存与批量采集
java·spring·缓存
比兔代理2 小时前
住宅代理IP的出口节点调度:ASN、BGP 与 IP 段信誉机制解析
linux·服务器·网络