本地跑 Ollama 做服务端,单机自测挺顺,一挂到业务上就发现请求开始排队、首字越来越慢,甚至有人以为它天生只能一个请求一个请求地跑。这篇不猜数字,只给判断路径:先搞清并发是被显存、模型体量还是服务参数卡住,再按清单调参、压测、加排队与降级,最后知道什么情况下单机方案根本不适用。
本地跑 Ollama 做服务端,单机自测挺顺,一挂到业务上就发现请求开始排队、首字越来越慢,甚至有人以为它天生只能一个请求一个请求地跑。这个问题没有标准答案,因为并发上限不是产品写死的,而是被你的显存、模型体量和服务参数共同决定的。
这篇不猜数字,只给判断路径:先搞清并发是被显存、模型体量还是服务参数卡住,再按清单调参、压测、加排队与降级,最后知道什么情况下单机方案根本不适用。具体型号对应的参考数值,到 /models/deploy 按实际模型和卡型核对当时的数字。
并发到底被什么卡住:先分清四层瓶颈
问「支持多少并发」之前,先接受一个事实:同一台机器,跑不同的模型、开不同的上下文长度,能同时扛的请求数可以差好几倍。所以先别找数字,先定位是哪一层先满了。
- 显存层
- 同一时刻能塞进多少份上下文和 KV 缓存,取决于剩余显存和单个请求的上下文长度,不是固定值。
- 参数层
- Ollama 有控制同时处理请求数的服务端参数,设小了排队,设大了直接爆显存,两者是同一枚硬币。
- 模型层
- 同一张卡跑小模型和大模型,能同时扛的请求数差好几倍,先确认自己在跑哪个体量。
- 外部层
- 调用方是不是长连接流式、有没有超时重试放大请求量,往往比模型本身更容易把服务压垮。
四层里任何一层先满,并发数就停在那。排查顺序建议从外往里:先看入口请求量是否被重试放大,再看参数是不是设得太保守,最后才动模型和显存。反向查容易改了半天参数,其实问题是客户端在疯狂重连。
| 现象 | 大概率先卡在哪层 | 先做哪个动作 |
|---|---|---|
| 一加压就报显存不足 | 显存层或参数层 | 把并行数往下退一档再压,确认是否立刻恢复 |
| 接口能返回但首字很慢 | 参数层或模型层 | 看服务日志里的排队情况,再判断是不是算力不够 |
| 失败率随并发陡增 | 外部层 | 先关掉客户端重试,单独压一次看基线 |
| 换个小模型就正常 | 模型层 | 说明瓶颈在模型体量,不是服务配置 |
调参清单:把并发从「能跑」推到「稳跑」
调参最大的坑是同时改多个变量,最后不知道哪个起了作用。正确做法是先固定条件,再单变量往上推,每次只动一档。
- 固定变量锁死一个模型、一个上下文长度、一种卡型,再动参数,否则调出来的数没有可比性。换任何一项都要重新来。
- 估算显存按「并行数 × 上下文长度」估算占用,留出安全余量;每次只往上推一档,观察是否出现显存不足或明显变慢。
- 盯对指标流式输出场景下,真正影响体验的是排队等待和首字延迟,不是吞吐总量,调参目标要跟着场景变。
- 一起看日志把服务日志和系统层面的显存、GPU 利用率一起看,单看接口返回判断不了是排队还是算得慢。
- 写进配置调完把参数写进部署配置和文档,别只留在某次命令行里,换机器就复现不出来。
- 先确认自己在跑哪个模型、多长上下文,这两个是分母。
- 单变量往上推,每次只动一档,记录现象。
- 显存不足就退一档,别硬撑。
- 参数名以你装的版本文档为准,版本间可能改名,别照抄旧教程。
- 调好的结果落文档,否则下一次部署等于从零开始。
还有一点常被忽略:上下文长度本身就是并发杀手。同一个模型,把上下文从短改到长,能同时处理的请求数可能直接腰斩。如果你的业务里请求长度差异很大,按最长的那个来估并发,会比按平均长度估安全得多。
怎么量、怎么排队:压测与限流落地
压测的目标不是找最大值,而是找拐点。最大值意味着贴着报错边缘跑,拐点才是能稳定服务的区间。
| 并发档位 | 首字延迟 | 完成时间 | 失败率 | 判断 |
|---|---|---|---|---|
| 低档 | 稳定 | 稳定 | 接近零 | 线性区,可以往上加 |
| 中档 | 开始变长 | 还在可接受范围 | 偶发 | 接近拐点,准备刹车 |
| 高档 | 明显跳升 | 翻倍 | 上升 | 已过拐点,不该上生产 |
| 极限 | 不可用 | 不可用 | 大量失败 | 只是测出了崩溃点 |
- 用一批固定长度的假请求逐步加压,记录各档位的首字延迟、完成时间和失败率。
- 业务并发上限设在拐点以下,不要贴着报错边缘跑。
- 入口侧加排队和并发闸门,超出能力的请求排队或快速失败,比全部塞进去一起变慢体验更好。
- 对可重试的失败做退避,避免失败即重试把瞬时压力翻倍,重试预算和并发上限一起设。
- 想知道自己链路的延迟基线,先用 /tools/speed-test 量一遍,再决定压测从哪个档位起。
本地服务同样需要限流这一层,别因为是自己机器就省掉。排队和快速失败看着是「拒绝用户」,实际上是把可控的等待换成不可控的雪崩。
什么情况下这套调法不成立
前面所有做法都建立在一个前提上:单机、单租户、能接受一定排队。只要有一条不满足,调并发参数就不是主要矛盾了。
- 要求多租户隔离、请求优先级、按量计费时,单机本地服务缺这些能力,调参解决不了。
- 需要跨机器横向扩展时,要考虑路由和会话粘性,方案重心从调参转到服务编排。
- 模型体量超过单卡容量、必须多卡切分时,并发表现由切分方案决定,不再是单机参数问题。
- 合规要求数据不出内网、又不接受排队延迟时,只能加机器或降级模型,没有参数层面的解法。
判断顺序很简单:先问是不是单机、是不是单租户、能不能接受排队。三个都是「是」,就按前面三节的清单调;有一个是「否」,就该换路线,而不是继续在参数上磨。
下一步如果你想先确认自己在跑的模型和卡型大概能撑到什么程度,到部署参考页按实际配置核对当时的数字,再决定是调参还是换架构。→常见问题
Ollama 是不是天生只能一个一个处理请求?
不是。它支持同时处理多个请求,但能同时扛多少取决于显存、模型体量和服务端并行参数,同一台机器换模型换上下文长度结果就变。所以没人能给你一个通用数字,只能在自己的硬件和参数下压测出拐点。
并发一高就变慢,是该继续加参数还是加机器?
先看显存有没有打满。显存没打满、延迟却飙升,说明瓶颈可能在别处,盲目加并行数只会更糟;显存已经接近上限,加参数也压不出更多并发,这时才考虑多机或换更小的模型。加之前先量出当前拐点在哪。
怎么快速判断变慢是排队还是算得慢?
看单个请求的实际计算时间和从进队列到开始计算之间的等待时间。等待时间长、计算时间正常,就是排队;两者一起涨,多半是资源被占满。把这两段分开记录,比只看总耗时有用得多。