<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[【交作业】双 3090 从 SGLang 切到 QEngine：decode 244.8 t/s、32K prefill 3,513 t/s，重启后 132K 会话 2.45 秒接回（附完整命令与踩坑）]]></title><description><![CDATA[<p dir="auto">日期：2026-10-29 ｜ QEngine <code>1.3-vision</code>（sha256:9916432e）｜ driver 595.91.07 / CUDA 13.2<br />
前情：这台机器从 10-25 起跑 SGLang 0.5.22 + DFlash 投机解码，一直是我的主力 agent 后端。这次把 QEngine 拉上来做了两轮同口径 A/B，已切换上线。</p>
<h2>0. 机器（很简单，不用羡慕）</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>项</th>
<th>值</th>
</tr>
</thead>
<tbody>
<tr>
<td>GPU</td>
<td>2× RTX 3090 24G（TP=2，NVLink），PCIe 直插</td>
</tr>
<tr>
<td>内存 / CPU</td>
<td>48 GB DDR4-2400 / 16 vCPU（PVE 虚拟机，宿主双路 E5-2697 v4）</td>
</tr>
<tr>
<td>模型</td>
<td><code>RedHatAI/Qwen3.8-27B-INT4</code>（compressed-tensors pack-quantized，19.5 GB）+ QEngine release 的 <code>model_mtp_ft.safetensors</code> / <code>token_rank.bin</code></td>
</tr>
<tr>
<td>上下文</td>
<td>262,144（引擎自报 <code>max context</code>）</td>
</tr>
</tbody>
</table>
<h2>1. 部署（三步，一共十几分钟）</h2>
<pre><code class="language-bash"># 1) 镜像：纯文本版 1.16 GB；带视觉 8.9 GB（同一个引擎，多 PyTorch + ViT）
docker pull ghcr.io/bpx03/qengine:1.3-vision

# 2) 权重（本机到不了 huggingface.co，走 hf-mirror；GitHub 资产走代理）
REPO=RedHatAI/Qwen3.8-27B-INT4; DEST=/mnt/models/qengine-int4; BASE=https://hf-mirror.com/$REPO/resolve/main
curl -sf "https://hf-mirror.com/api/models/$REPO" | python3 -c 'import json,sys
for s in json.load(sys.stdin)["siblings"]:
  if s["rfilename"].endswith((".json",".safetensors",".jinja",".yaml")): print(s["rfilename"])' |
while read f; do curl -fL -C - --retry 8 -o "$DEST/$f" "$BASE/$f"; done
for a in model_mtp_ft.safetensors token_rank.bin SHA256SUMS; do
  curl -fL -C - --retry 8 -x http://myproxy:7890 -o "$DEST/$a" \
       "https://github.com/bpx03/QEngine/releases/download/v1.0/$a"; done
( cd "$DEST" &amp;&amp; sha256sum -c SHA256SUMS )
</code></pre>
<p dir="auto">compose 里真正起作用的就这些（其余按默认）：</p>
<pre><code class="language-yaml">image: ghcr.io/bpx03/qengine@sha256:9916432e...   # 1.3-vision
environment:
  - QE_GPUS=0,1
  - QE_MAX_SEQS=32
  - QE_RESERVE_GB=1.0,1.0        # 显存几乎全给 KV
  - QE_KV_ARCHIVE_GB=16          # 主机 pinned KV 层
  - QE_PREFIX_GB=4
  - QE_MEM_MARGIN_GB=6
  - QE_EXTRA_ARGS=--served-name Qwen3.8-27B --vision 1 --vision-device cuda:1
      --max-image-pixels 1048576 --disk-cache /app/cache/diskcache --disk-cache-gb 10 --persist-idle 60
</code></pre>
<p dir="auto">启动 105 秒就绪（权重 19.5 GB + 视觉塔 5.8s + pinned 池 12.6s），日志直接自报容量：</p>
<pre><code>vision encoder on cuda:1 in 5.8s (max 1.0 MPix per image)
KV pool: 330752 tokens shared by 32 sequence slots (max context 262144)
archive pool: 21.5 GB pinned in 12.6 s
</code></pre>
<p dir="auto"><strong>四个坑（都踩过）</strong>：<code>--vision-device</code> 要 torch 设备串（<code>cuda:1</code>，给裸数字直接崩）；host tier 默认按 48 GB×2 算，48 GB 内存的机器不调小会挤爆；<code>--max-image-pixels</code> 默认 4.2 MPix，会白吃掉 17 万 token 的 KV 池（改成 1 MPix 就回来了）；<code>max context = min(模型, 池)</code>，所以想让单流到 256K，必须先把池顶到 ≥262,144。</p>
<h2>2. 实测数据</h2>
<p dir="auto">方法：自建 harness，Python 直打 <code>/v1/chat/completions</code>（stream + include_usage），<strong>每档换一个唯一 seed 保证是真冷 prefill</strong>；并发用 N 路同时发同一 prompt 测每流 decode；另有质量 10 题 / NIAH / 工具调用 / 视觉四条腿。引擎不返 llama.cpp 的 <code>timings</code>，用 <code>max_tokens=1</code> 探针推定 prefill。</p>
<p dir="auto"><strong>prefill 随上下文深度</strong>（连贯散文语料，thinking off）</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>上下文</th>
<th>prefill t/s</th>
<th>首字</th>
</tr>
</thead>
<tbody>
<tr>
<td>8 K</td>
<td>2,975</td>
<td>2.63 s</td>
</tr>
<tr>
<td>32 K</td>
<td><strong>3,513</strong></td>
<td>9.28 s</td>
</tr>
<tr>
<td>131 K</td>
<td>2,779</td>
<td>47.1 s</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>单流超长上下文</strong>（重复 filler 语料，口径与上表不同，别混着比）：254,000 token 一口吞，首字 60.4 s（≈4,200 t/s），decode <strong>184 t/s</strong>。</p>
<p dir="auto"><strong>并发 decode（每流 tok/s，同一 prompt）</strong></p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th></th>
<th>1 路</th>
<th>2 路</th>
<th>4 路</th>
</tr>
</thead>
<tbody>
<tr>
<td>8 K</td>
<td><strong>244.8</strong></td>
<td>210.4</td>
<td>155.0</td>
</tr>
<tr>
<td>32 K</td>
<td>236.3</td>
<td>191.7</td>
<td>145.1</td>
</tr>
</tbody>
</table>
<p dir="auto">投机解码是 MTP（<code>--mtp-k 7</code> + 那两个 release 文件），<strong>平均 accept length 6.00、接受率 71.4%</strong>。</p>
<p dir="auto"><strong>KV 容量（GPU + 内存两级）</strong>：显存池 330,752 + 主机 pinned 21.5 GB。压力测试用 4 条<strong>全程互不相同</strong>的长会话（每 ~1500 token 插一段独占盐，杜绝块级共享）：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>场景</th>
<th>每条实际 token</th>
<th>合计 KV</th>
<th>结果</th>
</tr>
</thead>
<tbody>
<tr>
<td>4 路独立</td>
<td>132,358</td>
<td><strong>52.9 万</strong></td>
<td>4/4 成功，超出显存的部分走内存层</td>
</tr>
<tr>
<td>4 路独立</td>
<td>164,623</td>
<td><strong>65.8 万</strong></td>
<td>4/4 成功，其中一条从 archive 取回 131,072 token（日志：<code>cached 131072 from archive</code>）</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>重启不丢上下文</strong>（这条是我换它的真实动机）：<code>docker restart</code> 之后，同一条 132K 会话首字 <strong>2.45 s</strong>（全新冷吞要 60 s）；更早一次 20K 会话重启后追问 <strong>0.73 s</strong>，停机→可用 100 秒。</p>
<p dir="auto">质量腿：10 题 10/10，NIAH 16K / 131K 全中，工具调用 PASS，视觉 4/4（红/蓝/圆/矩形全对）。</p>
<h2>3. 和 SGLang 的对比</h2>
<p dir="auto">同机器、同一天、同一套探针（SGLang 0.5.22 + DFlash2 投机解码、<code>--context-length 262144</code>、hicache 8 GB）。注意两边权重不同（RedHatAI INT4 vs AutoRound W4A16），差异不能全归引擎；启动到启动本身有 ±10% 抖动。</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>项目</th>
<th>SGLang</th>
<th>QEngine</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>prefill 8K / 32K / 131K</td>
<td>2,498 / 2,266 / 1,622</td>
<td><strong>2,975 / 3,513 / 2,779</strong></td>
<td>×1.19 / ×1.55 / ×1.71</td>
</tr>
<tr>
<td>首字 32K / 131K</td>
<td>14.47 s / 80.8 s</td>
<td><strong>9.28 s / 47.1 s</strong></td>
<td>省 36% / 42%</td>
</tr>
<tr>
<td>每流 decode 8K（1/2/4 路）</td>
<td>176.7 / 171.3 / 136.1</td>
<td><strong>244.8 / 210.4 / 155.0</strong></td>
<td>+39% / +23% / +14%</td>
</tr>
<tr>
<td>每流 decode 32K</td>
<td>194.4 / 174.2 / 144.0</td>
<td><strong>236.3 / 191.7 / 145.1</strong></td>
<td>+22% / +10% / 持平</td>
</tr>
<tr>
<td>投机解码 accept length</td>
<td>3.7–4.3</td>
<td><strong>6.00</strong></td>
<td></td>
</tr>
<tr>
<td>冷启动</td>
<td>~12 分钟</td>
<td><strong>105 秒</strong></td>
<td></td>
</tr>
<tr>
<td>重启后缓存</td>
<td>全丢</td>
<td><strong>保留</strong>（disk-cache，2.45 s 接回 132K 会话）</td>
<td></td>
</tr>
<tr>
<td>KV 总量（GPU+内存）</td>
<td>~41 万 token</td>
<td><strong>~73 万 token</strong>（实测吃下 65.8 万）</td>
<td></td>
</tr>
<tr>
<td>跨请求部分前缀</td>
<td><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=a055419e292" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:1.4em;width:auto;vertical-align:middle" title="✅" alt="✅" /> radix 树，命中后 0.25 s</td>
<td><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=a055419e292" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:1.4em;width:auto;vertical-align:middle" title="✅" alt="✅" /> 块哈希（<code>cached … from other slot</code>），命中后 0.67–1.6 s</td>
<td>SGLang 更锋利</td>
</tr>
<tr>
<td>视觉</td>
<td>未配</td>
<td><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=a055419e292" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:1.4em;width:auto;vertical-align:middle" title="✅" alt="✅" /> <code>--vision 1</code></td>
<td></td>
</tr>
<tr>
<td>质量 / NIAH / 工具</td>
<td>10/10，16K+131K 全中</td>
<td>一样</td>
<td>打平（10 题不够狠，这点我不吹）</td>
</tr>
</tbody>
</table>
<p dir="auto">唯一明显输给 SGLang 的是<strong>热前缀的极致命中</strong>：同语料换问题，SGLang 首字 0.25 s，QEngine 0.67–1.6 s——它的缓存是按 prefill chunk 对齐的，尾部总有几 K token 要重算。但我实际体感是净赢：冷会话快 1.5–1.7 倍，而冷会话我每天遇到的次数远多于"完美命中前缀"。</p>
<h2>4. 结论</h2>
<ul>
<li><strong>值得换</strong>：显存紧张的双 3090/4090 档、多轮 agent（长 system + 工具往返）、讨厌重启代价的——收益最大。</li>
<li><strong>先算内存</strong>：48 GB 内存下 pinned KV 层只能到 ~21.5 GB（再大就挤爆），我准备加到 96 GB 后把 <code>QE_KV_ARCHIVE_GB</code> 提到 48，KV 总量能上 130 万 token。这台机器上"能装多少 KV"完全由内存决定，跟显存无关。</li>
<li>顺手把主机 THP 从 <code>madvise</code> 改成 <code>always</code>：pinned 池从 228 秒降到 12.6 秒。引擎会抱怨"大页覆盖只有 67%"，但实测 prefill/decode 没有任何可测差异——那个警告不值得追。</li>
<li>许可是 <strong>PolyForm Noncommercial 1.0.0</strong>：个人自用没问题，商用要另外拿授权。</li>
</ul>
<p dir="auto">有问题问，配置和测试脚本都在，可以复现。</p>
]]></description><link>https://lcz.me/topic/2682</link><generator>RSS for Node</generator><lastBuildDate>Tue, 10 Nov 2026 01:52:51 GMT</lastBuildDate><atom:link href="https://lcz.me/topic/2682.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 29 Oct 2026 06:42:47 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to 【交作业】双 3090 从 SGLang 切到 QEngine：decode 244.8 t/s、32K prefill 3,513 t/s，重启后 132K 会话 2.45 秒接回（附完整命令与踩坑） on Thu, 29 Oct 2026 07:00:08 GMT]]></title><description><![CDATA[<p dir="auto">本来想玩一下QEngine，看到不支持A卡，是N卡专属。性能上3090要比7900XTX好，A卡还有优化的空间</p>
]]></description><link>https://lcz.me/post/29039</link><guid isPermaLink="true">https://lcz.me/post/29039</guid><dc:creator><![CDATA[懒人烘培]]></dc:creator><pubDate>Thu, 29 Oct 2026 07:00:08 GMT</pubDate></item><item><title><![CDATA[Reply to 【交作业】双 3090 从 SGLang 切到 QEngine：decode 244.8 t/s、32K prefill 3,513 t/s，重启后 132K 会话 2.45 秒接回（附完整命令与踩坑） on Thu, 29 Oct 2026 06:45:36 GMT]]></title><description><![CDATA[<p dir="auto">附一张DSH代码开发实图，快的让我有点不太适应。<br />
<img src="https://upload.lcz.me/uploads/762172e0-b3a1-4706-a346-22dc256f7fd9.png" alt="屏幕截图 2026-10-29 142644.png" class="img-markdown  img-fluid" /></p>
]]></description><link>https://lcz.me/post/29034</link><guid isPermaLink="true">https://lcz.me/post/29034</guid><dc:creator><![CDATA[davidwei0826]]></dc:creator><pubDate>Thu, 29 Oct 2026 06:45:36 GMT</pubDate></item></channel></rss>