Ollama + 4090(48GB)推理性能榨干从“显存占满但 GPU-Util=0”到“速度/吞吐可控拉满”
1. 先把目标说清楚:吞吐 vs 速度(延迟)
你必须先选一个主目标,否则你会陷入“怎么调都不满意”:
- 吞吐(Throughput)优先:单位时间处理更多请求、更多总 tokens/s
核心手段:提高并发、让 GPU 长时间忙、允许排队 - 速度(Latency)优先:单请求更快、首 token 更快、单路 tokens/s 更高
核心手段:降低并发、缩小上下文、控制输出长度、减少争用
同样一张 4090,同样一个模型,吞吐型配置往往会牺牲单请求速度;速度型配置也不追求“GPU-Util 99%”。
2. 为什么“显存占很高但功耗 12W、频率 210MHz”
你贴出来的 dmon 非常典型:
pwr 12~21W、pclk 210MHz、mclk 405MHz、sm 0
这代表 GPU 处于省电态(基本空闲),当时没有持续推理在跑,或者推理非常短/没有形成持续 kernel 负载。
换句话说:
显存占用高 ≠ 正在推理
显存高往往只是模型常驻 + KV cache/上下文缓存占住了空间。
3. 正确的性能指标:用 tokens/s 说话
判断“快不快”,最稳的方法是:
- 用非流式接口拿到统计字段(例如 eval_count / eval_duration)
- 计算 tokens/s:
tokens/s = eval_count / eval_duration * 1e9(eval_duration 若为 ns)
同时辅助看:
- 推理时的 功耗 是否上到几百瓦
- P-State 是否进入 P0
- clocks 是否显著上升
GPU-Util 可以看,但不要当“唯一标准”。
4. 双 4090(2×48GB)怎么用最合理
这是一个很多人会误解的点:
两张卡不是自动变成一块 96GB 大显存。对 Ollama 来说更现实的经验是:
- 如果模型能完整放进单卡 48GB,单实例通常只会用其中一张卡(减少跨 PCIe 传输,单请求更快)
- 想让两张卡都忙、吞吐翻倍,最佳实践是:
两个 Ollama 实例,每个实例绑定一张 GPU,再做负载均衡/轮询
也就是说:
- 吞吐优先:双实例(11434/11435),上层分发请求
- 单请求速度优先:单卡单实例,避免跨卡
5. systemd 配置模板
你已经有 GPU0/GPU1 两份 unit,我给你两类模板:吞吐型(burn)和速度型(speed)。
5.1 吞吐型(burn):让 GPU 更“忙”,总吞吐更高
适用:你希望“压测时功耗爆表、两张卡都在干活、总体处理能力最大”。
GPU0(11434)示例(GPU1 同理改端口和 CUDA_VISIBLE_DEVICES):
[Unit]
Description=Ollama (GPU0) - burn mode
After=network-online.target
Wants=network-online.target
[Service]
User=ollama
Group=ollama
ExecStart=/usr/local/bin/ollama serve
Restart=always
RestartSec=1
Environment="CUDA_VISIBLE_DEVICES=0"
Environment="OLLAMA_HOST=0.0.0.0:11434"
Environment="OLLAMA_MODELS=/usr/share/ollama/.ollama/models"
Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KEEP_ALIVE=-1"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
Environment="OLLAMA_MAX_QUEUE=2048"
Environment="OLLAMA_CONTEXT_LENGTH=4096"
Environment="OLLAMA_NUM_PARALLEL=6"
Environment="OLLAMA_GPU_OVERHEAD=2147483648"
Environment="OLLAMA_NEW_ENGINE=1"
[Install]
WantedBy=multi-user.target
说明:
NUM_PARALLEL提升吞吐,但会牺牲单请求速度CONTEXT_LENGTH不建议一上来 16K,吞吐型更推荐 4K/8K,把 KV cache 压小让并发上得去GPU_OVERHEAD预留显存,减少碎片/偶发抖动
5.2 速度型(speed):单请求尽可能快
适用:你觉得“慢”,更关心单次推理、首 token、单路 tokens/s。
[Unit]
Description=Ollama (GPU0) - speed mode
After=network-online.target
Wants=network-online.target
[Service]
User=ollama
Group=ollama
ExecStart=/usr/local/bin/ollama serve
Restart=always
RestartSec=1
Environment="CUDA_VISIBLE_DEVICES=0"
Environment="OLLAMA_HOST=0.0.0.0:11434"
Environment="OLLAMA_MODELS=/usr/share/ollama/.ollama/models"
Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KEEP_ALIVE=-1"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
Environment="OLLAMA_NUM_PARALLEL=1"
Environment="OLLAMA_MAX_QUEUE=256"
Environment="OLLAMA_CONTEXT_LENGTH=4096"
Environment="OLLAMA_GPU_OVERHEAD=2147483648"
Environment="OLLAMA_NEW_ENGINE=1"
[Install]
WantedBy=multi-user.target
关于 OLLAMA_KV_CACHE_TYPE=q8_0:
它更像“省显存/撑更大 ctx”的工具,不一定让速度更快。速度优先建议先用默认 KV(通常更快),再做 A/B 测试决定是否加。
生效命令(两种配置都一样):
sudo systemctl daemon-reload
sudo systemctl restart ollama-gpu0
sudo systemctl restart ollama-gpu1
6. GPU 侧两条“必做”的性能开关
让 GPU 不要频繁进省电态,减少抖动、提高稳定频率:
sudo nvidia-smi -pm 1
sudo nvidia-smi -pl 450
如果你散热/供电非常稳,可以再尝试锁频(不是必须,且不稳会降频或报错):
sudo nvidia-smi -lgc 2100,2700
7. 请求侧才是真正的“速度旋钮”
服务端 env 解决的是“并发、队列、上限”,但每一次请求的 options 才决定你这次到底是快还是慢。
速度型请求建议:
num_ctx:2048/4096 优先,越大越慢num_predict:控制输出长度(生成越多当然越慢)num_batch:对长 prompt 的 prefill 很关键(512/1024 常用档位)stream=true:体感首 token 更好
示例(速度型):
curl -s http://127.0.0.1:11434/api/generate -d '{
"model":"gemma3:27b-it-q8_0",
"prompt":"用三句话解释 CAP 定理。",
"stream":true,
"options":{
"num_ctx":4096,
"num_batch":512,
"num_predict":256,
"temperature":0.2
}
}'
吞吐压测(让功耗/频率真正起来)的关键是:长输出 + 足够并发 + 较长 prompt(让 prefill 也忙)。很多人压测只给一句话 prompt,然后觉得“GPU 不满”,本质是负载形态太弱。
8. 为什么你用 gemma3:27b-it-q8_0 仍觉得慢
一个很现实的工程经验:
Q8 通常不是“最快”的量化档。它更接近高精度/更高算力消耗,很多情况下 Q4/Q5/Q6 会明显更快。
如果你追求“速度极致”,最直接的提速路径往往是:
- 换更快的量化(如果你能接受轻微精度变化)
- 把上下文降到 2K/4K
- 把并发降到 1(速度型)或合适值(吞吐型)
9. 最终调参路线图
你可以按这个顺序,最快收敛到最优点:
- 先选目标:速度型 or 吞吐型
- 固定 GPU:
-pm 1+-pl 450 - 用同一条请求基准测试(固定 prompt、固定 options)
- 调
num_ctx:2048 vs 4096 - 调
num_batch:256/512/1024 - 若吞吐型,再调
OLLAMA_NUM_PARALLEL:4 → 6 → 8 - 再决定是否启用 KV cache 量化(做 A/B)
10. 结尾给一份“速度极致清单”
- systemd 用 speed mode:
NUM_PARALLEL=1、MAX_QUEUE=256、CONTEXT_LENGTH=4096 - GPU:
nvidia-smi -pm 1、nvidia-smi -pl 450 - 请求:
num_ctx=2048/4096、num_batch=512、num_predict控制长度、尽量流式 - 量化:如果你真的觉得慢,优先考虑更轻的量化档,而不是盯
GPU-Util
更多推荐



所有评论(0)