前阵子朋友打电话来,说公司弄了台双卡3090的Linux服务器,要部署大模型做内部AI应用,问我第一步该干什么。我说你先别急着装环境,先想清楚你要的是"能用"还是"能扛并发"。这句话听起来简单,但实际部署路径差别非常大——测试用的Ollama一条命令就能跑起来,生产服务却要考虑到显存规划、并发调度、服务托管和故障恢复。这篇就把我在Linux服务器上部署大模型的全过程拆开讲,覆盖方案选型、硬件测算、环境核查、Ollama快速落地、vLLM生产化以及部署后的常见故障排查,整套流程都是我实测过的路径,命令和参数基本可以照抄。
1. 部署前先想清楚:单机体验还是服务化部署,选型差远了
1.1 大模型部署的本质:把权重变成可调用的服务
很多人第一次接触"部署大模型",以为就是把模型文件下载下来,然后让网页跟它聊天。这个理解没有错,但只说对了一半。真正的部署,核心是把模型权重加载进内存或显存,跑起一个推理服务,对外提供HTTP接口,让内部其他系统、web页面、甚至手机端都能调用。它跟你本地用ChatGPT网页版不一样——你需要的是自己的推理服务。
这个过程中,权重文件本身只是"食材",推理引擎才是"灶台"。同样一份DeepSeek权重,你用不同的推理引擎,跑出来的吞吐、延迟、并发能力完全两样。有些引擎适合开发调试,有些适合生产环境扛流量,有些甚至能在纯CPU上跑小模型。所以我建议所有准备部署的人,先把"模型"和"推理引擎"这两件事分开理解,后面才不会混乱。
1.2 主流部署框架横向对比:Ollama、vLLM、TGI、llama.cpp怎么选
目前社区里用得最多的几套方案,我全都试过,简单说下各自定位:
| 框架 | 适合场景 | 并发/吞吐能力 | 上手难度 | 主要特性 |
|---|---|---|---|---|
| Ollama | 个人测试、小团队内网使用 | 中等,连续批处理较简单 | 极低,一条命令拉模型 | 模型管理方便,支持GGUF量化 |
| vLLM | 生产环境API服务 | 高,PagedAttention+Continuous Batching | 中等,需配Python环境 | OpenAI兼容接口,吞吐优秀 |
| TGI | HuggingFace生态、生产RAG/Agent服务 | 高 | 中等 | 原生支持messages API,功能全 |
| llama.cpp | 无GPU、CPU推理、嵌入式设备 | 低 | 中等 | GGUF格式,内存占用极小 |
| TensorRT-LLM | 极致性能、NVIDIA推理卡专用 | 极高 | 高,需编译engine | 延迟最低,但调试成本高 |
个人视角下的判断标准很简单:如果你只是要快速验证一个模型能不能干活,选Ollama;如果你要做一个稳定跑在线的服务,选vLLM;如果你完全没有GPU,只有一台大内存CPU服务器,选llama.cpp。TensorRT-LLM适合那些专门做AI交付、有精力去压榨性能的团队,普通业务场景不值得一上来就碰。
1.3 我的选型结论:组合拳而不是选一个框架
我的实际做法是:同一台服务器上同时装Ollama和vLLM。Ollama用来日常测试模型效果、临时看某个模型行为是否满足需求;vLLM用来承载正式的业务流量。两者可以共存在一台机器上,只要显存规划时给它们各自预留空间。这个组合让我既享受了快速试错的便利,又保住了生产环节的稳定。后面我会把两套方案的部署细节都写出来。
2. 硬件测算与系统环境:99%的部署翻车发生在这里
2.1 显存怎么算:参数量、精度、KV Cache一个都不能漏
部署大模型,第一道计算题就是显存够不够。这里有个常用公式:
所需显存 ≈ 模型参数量 × 精度字节数 + KV Cache + 激活值模型参数量好理解,7B就是70亿参数。精度字节数是关键:如果用FP16/FP32混合精度,每个参数占2字节;如果做INT8量化,每个参数占1字节;INT4量化则只需要0.5字节左右。所以一个7B模型:
- FP16:约需要 7 × 2 = 14GB 显存
- INT8:约需要 7 × 1 = 7GB
- INT4:约需要 7 × 0.5 = 3.5GB
这只是权重部分。KV Cache是模型在生成token时缓存历史计算结果的显存开销,它跟上下文长度、并发请求数强相关。一个经验值是:7B模型在2K上下文、单并发下,KV Cache大概占用几百MB到1GB。并发每增加一倍,这个数字基本也翻一倍。所以如果你规划10个并发请求,每个请求上下文到4K,那么"权重14GB + KV Cache约4-6GB"是一个相对安全的估算。
我当时部署DeepSeek-R1-7B时,先用FP16装上,发现同时4个请求就出现OOM,后来改成了Ollama默认的Q4量化版本,权重从14GB压缩到4.7GB,同一块卡能扛的并发立刻翻了几倍。这就是量化的意义。
2.2 系统环境五项检查:驱动、CUDA、内存、磁盘、内核参数
我在部署前给服务器做的清单有五项,每一项都有对应的命令:
# 1. 确认显卡型号和驱动 lspci | grep -i nvidia nvidia-smi # 2. 确认CUDA版本(注意:nvidia-smi里的CUDA Version和nvcc不一样) nvcc --version # 3. 确认系统内存 free -h # 4. 确认磁盘空间(模型文件动不动几十GB) df -h # 5. 确认内核和发行版 uname -a cat /etc/os-release这里面最容易翻车的是第2项。你可能会发现nvidia-smi显示的"CUDA Version: 12.4"和nvcc --version显示的系统CUDA版本对不上——这是正常的,因为nvidia-smi显示的是驱动支持的最高CUDA版本,不是当前环境实际使用的版本。对于Ollama来说它自带CUDA runtime,你只要驱动版本够新就行;但对于vLLM这类基于PyTorch的框架,你的CUDA驱动版本必须不低于PyTorch要求的版本。
另外一个常被忽略的问题是磁盘IO。大模型权重动辄几十GB,加载时如果不做缓存,每次重启服务都要从磁盘重新读一遍。如果磁盘是机械盘,冷启动可能要等好几分钟;换成NVMe固态,基本几十秒就能完成加载。有条件的话,把模型文件放在SSD或NVMe分区下,体验天差地别。
2.3 时间同步与文件句柄:两个容易被忽略的隐藏坑
服务器运维里有一类问题,只看应用日志永远排查不出来:认证失败、证书验证报错、多机通信突然中断。这类问题很多时候是系统时间漂移导致的。部署大模型前我习惯顺手做一次时间同步检查:
timedatectl status timedatectl set-ntp true如果服务器本来就不准,建议直接配置NTP服务让它持续同步。尤其是后面要跑分布式多卡推理,NCCL通信对时间一致性很敏感,几个节点时间差太大会出现莫名其妙的连接超时。
另外,如果模型服务连接数一多就报"Too many open files",那是Linux文件句柄上限太低。可以临时调高,也可以写进服务配置里:
ulimit -n 65535生产环境建议在systemd服务单元里加LimitNOFILE=65535,防止服务被句柄上限卡死。
3. 快速落地第一套:Ollama部署DeepSeek并发布API
3.1 安装Ollama:curl脚本背后的逻辑
Ollama的安装确实是一条命令:
curl -fsSL https://ollama.com/install.sh | sh但我不建议直接闭眼执行。这个脚本会默认做三件事:把ollama的二进制装到/usr/local/bin,创建ollama系统用户,注册systemd服务。如果你机器上已经有自己的用户管理习惯,安装完成后最好确认一下服务和数据目录:
systemctl status ollama ls -la /usr/share/ollama/.ollama/models默认模型存储目录是/usr/share/ollama/.ollama/models,如果你的根分区不大,建议安装后立刻修改环境变量OLLAMA_MODELS指向大磁盘分区。具体做法是编辑systemd服务文件:
mkdir -p /etc/systemd/system/ollama.service.d cat > /etc/systemd/system/ollama.service.d/override.conf << 'EOF' [Service] Environment="OLLAMA_MODELS=/data/ollama/models" Environment="OLLAMA_HOST=0.0.0.0:11434" EOF systemctl daemon-reload systemctl restart ollama注意这里OLLAMA_HOST=0.0.0.0:11434是让Ollama监听所有网卡,如果你只想本机访问,这个就不要写。
3.2 拉模型慢或失败?试试手动导入GGUF
Ollama拉取模型走的是它自己的仓库,速度有时不理想,尤其在国内网络环境下经常中断。这里我分享一个实测有效的方案:不通过ollama pull,而是从国内的模型社区下载GGUF文件后手动导入。
先去ModelScope等平台搜索目标模型的GGUF版本,比如DeepSeek-R1-Distill-Qwen-7B-GGUF。下载后用modelscope命令行工具:
pip install modelscope modelscope download --model 'deepseek-ai/DeepSeek-R1-Distill-Qwen-7B-GGUF' --local_dir /data/models/deepseek-r1-7b-gguf然后准备一个Modelfile,内容非常简单:
FROM /data/models/deepseek-r1-7b-gguf/DeepSeek-R1-Distill-Qwen-7B-Q4_K_M.gguf最后执行:
ollama create deepseek-r1-7b -f Modelfile ollama list这样拉取的不是在线仓库依赖,而是本地文件直接转换,整个过程稳定可控。这个路径适合所有GGUF模型。
3.3 把Ollama变成局域网可调用的API服务
Ollama自带两个接口,一个用于生成补全,一个用于对话:
curl http://localhost:11434/api/generate -d '{ "model": "deepseek-r1-7b", "prompt": "简述Linux服务器部署大模型的注意事项", "stream": false }'如果你想用更通用的/v1/chat/completions接口,Ollama也兼容OpenAI格式:
curl http://localhost:11434/v1/chat/completions -H "Content-Type: application/json" -d '{ "model": "deepseek-r1-7b", "messages": [{"role": "user", "content": "你好,介绍一下你自己"}] }'如果其他机器访问不通,先确认防火墙是不是只放行了ssh端口:
firewall-cmd --permanent --add-port=11434/tcp firewall-cmd --reload3.4 验证推理:一次最简单的请求
部署完成后,我习惯先做一次最基础的连通性验证,看三件事:模型是否被正确加载、首次推理延迟是多少、显存占用是否在预期范围。先跑一次:
time curl http://localhost:11434/api/generate -d '{"model": "deepseek-r1-7b", "prompt": "1+1=?", "stream": false}'观察输出的total_duration和eval_count,可以算出生成速度。如果首次请求特别慢(比如几十秒),多半是模型在冷加载阶段,后续请求会明显提速。同时另一终端开个nvidia-smi看一眼显存占用,如果和你第2章的测算结果差距过大,就去检查量化精度是否对齐。
4. 生产级部署:vLLM推理服务从零到压测通过
4.1 为什么生产环境我推荐vLLM而不是Ollama
Ollama非常好用,但它的优势是"开箱即用",而不是"性能极致"。生产环境我要的是稳定吞吐、低延迟波动和结构化管理。vLLM之所以厉害,在于两个核心技术:PagedAttention和Continuous Batching。
PagedAttention可以类比操作系统的虚拟内存分页——它不再为每个请求的KV Cache分配一整块连续显存,而是拆成小块按需分配,显存碎片化问题被大幅缓解。Continuous Batching则实现了"在同一个批次里动态加入新请求",而不是等到当前批次全部结束再开启下一批。这两个技术叠加,让vLLM在高并发下的吞吐量通常能达到Ollama的数倍。实测同样的DeepSeek-R1-7B在vLLM上32并发仍然稳定,Ollama到了8并发左右延迟就明显飘了。
4.2 模型下载、虚拟环境安装、启动服务一条线
vLLM是Python生态,我建议用虚拟环境隔离,避免和服务器上其他Python应用冲突:
python3 -m venv /opt/vllm-env source /opt/vllm-env/bin/activate pip install --upgrade pip pip install vllm模型下载依然走ModelScope,但这次下载的是原始HuggingFace格式(非GGUF):
modelscope download --model 'deepseek-ai/DeepSeek-R1-Distill-Qwen-7B' --local_dir /data/models/DeepSeek-R1-Distill-Qwen-7B下载完成后启动服务,新版vLLM推荐直接使用vllm serve命令:
vllm serve /data/models/DeepSeek-R1-Distill-Qwen-7B \ --served-model-name deepseek-r1-7b \ --max-model-len 8192 \ --gpu-memory-utilization 0.9 \ --port 8000这里几个参数别乱填。gpu-memory-utilization=0.9表示让vLLM最多使用90%的显存做模型和KV Cache,留10%给CUDA context和临时激活值;max-model-len=8192控制了上下文窗口的最大值,设得越大,KV Cache按这个上限预留的显存就越多,如果设成32768,7B模型都够你喝一壶。
启动后看到Uvicorn running on http://0.0.0.0:8000说明服务正常。调用方式完全兼容OpenAI接口:
curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-r1-7b", "messages": [{"role": "user", "content": "用一句话介绍Linux"}] }'4.3 systemd托管:让推理服务开机自启、崩溃自拉
这里参考我完整写过的systemd部署教程,vLLM非常适合做成系统服务。创建服务单元:
[Unit] Description=DeepSeek vLLM Inference Service After=network-online.target Wants=network-online.target [Service] Type=simple User=root WorkingDirectory=/opt/vllm-env/bin Environment="CUDA_VISIBLE_DEVICES=0,1" ExecStart=/opt/vllm-env/bin/vllm serve /data/models/DeepSeek-R1-Distill-Qwen-7B \ --served-model-name deepseek-r1-7b \ --max-model-len 8192 \ --gpu-memory-utilization 0.9 \ --port 8000 Restart=always RestartSec=10 LimitNOFILE=65535 [Install] WantedBy=multi-user.target这里有几个细节值得注意。CUDA_VISIBLE_DEVICES写多少取决于你打算让vLLM用哪几块卡;如果服务器上还有Ollama占用一块卡,这里就必须显式指定,否则两个框架抢显存会一起崩溃。Restart=always的意义在于,推理进程一旦被OOM killer干掉,10秒后自动拉起来。
启用并执行:
systemctl daemon-reload systemctl enable vllm-deepseek systemctl start vllm-deepseek journalctl -u vllm-deepseek -f4.4 并发压测与吞吐观察:PagedAttention到底强在哪
部署完不能只自己测一个请求就宣布大功告成。我建议用简单到不能再简单的并发脚本,先把服务打一遍。这里用Python的concurrent.futures发同步请求即可:
import concurrent.futures import requests PROMPT = "讲一个程序员的故事,字数在200字左右。" def call_once(_): resp = requests.post( "http://localhost:8000/v1/chat/completions", json={ "model": "deepseek-r1-7b", "messages": [{"role": "user", "content": PROMPT}], "max_tokens": 256, }, timeout=300, ) return resp.status_code, resp.elapsed.total_seconds() with concurrent.futures.ThreadPoolExecutor(max_workers=16) as pool: results = list(pool.map(call_once, range(64)))观察两个指标:一个是所有请求是否都成功返回200,另一个是请求耗时分布。如果64个并发请求几乎都能在几十秒内完成,说明Continuous Batching在正常工作;如果大量请求超时、甚至vLLM日志里出现CUDA OOM,说明参数还需要回调。压测时另一终端开一个监控:
watch -n 1 nvidia-smi你会看到vLLM的显存占用曲线、GPU利用率锯齿状波动,这是正常的——只要没有显存OOM、GPU利用率不是长期0%,整体就是健康的。
5. 部署后的故障排查:OOM、慢响应、连不上的真实案例
5.1 显存不够不是只能换卡:OOM的排查与参数调整
vLLM日志里出现CUDA out of memory是生产环境最常见的报错之一。大部分人第一反应是换更大的卡,实际上很多时候是参数规划出了问题。
排查链路我建议这样走:先用nvidia-smi看当前显存分配,再用vllm serve --gpu-memory-utilization一步步往下调,比如从0.9调到0.7,观察OOM是否消失。如果显存占用不足以支撑你的并发请求,先把--max-model-len从8192降到4096,这个参数对KV Cache空间的压榨立竿见影。如果业务确实需要长上下文,再考虑换量化模型——用AWQ或GPTQ量化版权重替换原始FP16权重,显存需求直接减半。
有个很容易踩的坑是:以为是显存不够,其实是同一张卡被别的进程占了一部分。排查命令是:
fuser -v /dev/nvidia*把占用卡的其他进程清掉再重启服务,问题往往直接消失。
5.2 并发一高就慢:从单请求延迟和吞吐两个维度找原因
很多人在服务器上部署完大模型,抱怨"两个人同时用就卡死"。这个问题的本质通常不是模型选错,而是你没有给推理引擎足够的并发空间,甚至可能你部署的压根是只支持单请求串行推理的框架。
排查思路分两块。第一块看显存利用率:如果显存利用率很高、GPU计算单元却只有个位数百分比,说明模型在等I/O,可能是磁盘瓶颈或数据加载慢。第二块看请求是否排队:Ollama默认的并发策略相对保守,如果多路并发请求都积压在队列里,那就是引擎本身的调度上限,不算Bug,只能换vLLM或TGI这类支持动态批处理的引擎。
一般来说,如果你的服务在高并发下每请求耗时是按秒级增长而不是线性增长,大概率是框架批处理能力不够。这时候用vLLM重跑一遍刚才的压测脚本,对比同样并发下平均耗时,你会明显看到差距。
5.3 API服务暴露在公网和内网的防火墙与鉴权处理
部署好了不等于安全了。我发现很多开发者的习惯是:本地测试用0.0.0.0监听,然后直接不管了,结果模型服务裸奔在内网甚至不小心暴露到公网。这里几条经验:
如果你只在内网使用,那就用防火墙把端口限制在可信网段:
firewall-cmd --permanent --zone=internal --add-source=192.168.1.0/24 firewall-cmd --permanent --zone=internal --add-port=8000/tcp firewall-cmd --reload如果你需要对外开放,vLLM新版支持--api-key参数直接做Token鉴权;Ollama则建议在前面挂个Nginx反向代理,用auth_basic或自定义Header校验来挡掉未授权请求。千万别让任何一台模型的端口在没有鉴权的情况下直接暴露在公网。
6. 进阶玩法:多卡并行与容器化部署
6.1 多卡张量并行:tensor-parallel-size怎么设
服务器有两张或更多卡时,可以启用张量并行,让模型权重和计算分布在多张卡上。vLLM里就是加一个参数:
vllm serve /data/models/DeepSeek-R1-Distill-Qwen-7B \ --tensor-parallel-size 2 \ --gpu-memory-utilization 0.9设成2代表模型按张量维度切分到两张卡上。这时候有几条注意事项:多卡之间通过PCIe或NVLink通信,如果你的服务器是PCIe连接且没有NVSwitch,张量并行规模不要盲目开大,否则通信开销可能抵消计算收益。另外两张卡的显存型号建议一致,如果一张3090一张A100,显存小的那卡会拖慢整体速度。对于70B这种级别的大模型,四卡并行是常态,但前提是服务器支持足够高的卡间带宽。
6.2 用Docker跑vLLM:镜像选择、显存直通与数据挂载
容器化部署现在几乎是标配。vLLM官方提供了预构建镜像,我通常这样跑:
docker run -d \ --name vllm-deepseek \ --gpus all \ --shm-size=4g \ -p 8000:8000 \ -v /data/models:/data/models \ vllm/vllm-openai:latest \ vllm serve /data/models/DeepSeek-R1-Distill-Qwen-7B \ --served-model-name deepseek-r1-7b这里两个容易翻车的地方。第一,--gpus all必须加,否则容器内看不到GPU;第二,--shm-size建议至少2-4GB,PyTorch的数据加载器在多进程模式下很依赖共享内存。如果你自己制作镜像,注意基础镜像的CUDA版本必须和宿主机驱动匹配,凡是遇到"could not select device"或"CUDA driver version is insufficient",基本都是这个原因。
另外容器里跑模型,日志管理更简单。直接用docker logs -f vllm-deepseek看实时日志,用docker update --cpus、--memory限制资源。不过有个心理准备:vLLM镜像本身比较大,下载时可以挂到内网镜像源,不要频繁重建容器,日常更新模型版本时只挂载新的权重目录进去即可。
6.3 监控与日志:没有可观测性,上面的一切都是裸奔
最后一条经验,我强烈建议在生产环境部署完大模型后,把监控体系搭起来。不需要一开始上很重的方案,先做到三个最小闭环:
第一,日志。用systemd或Docker的日志机制,把vLLM/Ollama的启动日志和请求日志统一收集,至少保证服务崩溃时能知道崩溃前发生了什么。
第二,GPU指标。写个简单的定时任务,每30秒把nvidia-smi的显存利用率、温度、功耗输出到文件或对接文本格式的监控工具。即便不做可视化,留个历史记录对排查问题也有极大帮助。
第三,服务探测。用crontab每两分钟执行一次:
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8000/v1/models如果返回的不是200,就触发告警。这样至少不会出现"模型挂了三天没人发现"的尴尬。说实话,我见过太多团队部署完模型没有监控,等服务被用户投诉才发现进程早就不在了。这最后一步的成本极低,收益却极大。
以上这一整套,从方案选型、硬件测算、环境准备,到Ollama和vLLM两套方案的落地部署,再到故障排查、多卡和容器化进阶,就是我目前在Linux服务器上部署大模型的完整路径。如果你是从零开始,建议严格按顺序走一遍,不要跳过第2章的环境检查项,很多部署失败其实在最开始就已经埋下了伏笔。