1. 文档说明
本文档用于指导团队在 Ubuntu 20.04 + 双卡 A100 环境中完成 Ollama 的部署、启停、巡检、故障排查、升级与回滚,形成一套可直接执行的生产落地手册。
适用对象:
- 运维工程师
- 平台工程师
- AI 应用研发工程师
- 项目负责人 / 交付负责人
本文档目标不是“介绍 Ollama 是什么”,而是确保团队可以完成以下事情:
- 正确部署双实例 Ollama
- 让 GPU0、GPU1 分别承载一个推理实例
- 保证模型常驻与自动预热
- 支持 Python 侧轮询分发与失败切换
- 能完成日常巡检、故障定位、升级和回滚
2. 交付目标
本次交付最终目标如下:
2.1 服务目标
ollama-gpu0.service正常运行ollama-gpu1.service正常运行ollama-prewarm.service可正常执行- 默认
ollama.service停用,避免端口冲突
2.2 资源目标
- GPU0 对应端口
11434 - GPU1 对应端口
11435 - 两张 A100 可同时接收推理请求
- 模型保持常驻,减少冷启动抖动
2.3 调用目标
- Python 客户端支持双实例轮询
- 客户端支持实例探活
- 客户端支持失败切换
- 客户端支持预热与常驻调用
2.4 运维目标
- 服务可开机自启
- 支持日志追踪
- 支持健康检查
- 支持升级与回滚
- 支持日常巡检
3. 交付架构说明
整体采用 双实例双端口 模式,而不是一个实例同时管理两张 GPU。
架构如下:
-
ollama-gpu0- 绑定
CUDA_VISIBLE_DEVICES=0 - 监听
0.0.0.0:11434
- 绑定
-
ollama-gpu1- 绑定
CUDA_VISIBLE_DEVICES=1 - 监听
0.0.0.0:11435
- 绑定
-
ollama-prewarm- 在两个实例启动完成后自动执行预热
- 确保模型提前加载进显存
-
Python 调用层
- 将
11434与11435作为实例池 - 按轮询方式分发请求
- 失败时自动切换实例
- 将
这样设计的原因很直接:
- 边界清晰
- 便于定位问题
- 更利于吞吐优先场景
- 一张卡异常不会直接拖垮另一张卡
4. 目录规划
推荐目录结构如下:
/data/ollama/models # 模型目录
/etc/systemd/system/ # systemd 服务目录
/usr/local/bin/ # 运行脚本目录
最终落地文件如下:
/etc/systemd/system/ollama-gpu0.service
/etc/systemd/system/ollama-gpu1.service
/etc/systemd/system/ollama-prewarm.service
/usr/local/bin/ollama-prewarm.sh
/usr/local/bin/ollama-healthcheck.sh
/usr/local/bin/ollama_bi_gpu_client.py
/data/ollama/models
5. 环境前提
部署前需确认以下前提:
5.1 系统环境
- Ubuntu 20.04
- systemd 可正常使用
- 网络正常,可访问模型下载源或已有离线模型
5.2 GPU 环境
执行:
nvidia-smi
nvidia-smi -L
确认:
- 两张 A100 可正常识别
- 驱动工作正常
- GPU 编号或 UUID 可获取
5.3 Ollama 已安装
执行:
which ollama
ls -l /usr/local/bin/ollama
预期路径:
/usr/local/bin/ollama
如果实际路径不是这个,后续 ExecStart 需要同步修改。
5.4 ollama 用户存在
执行:
id ollama
如果不存在,需先创建服务用户。
6. 部署步骤
6.1 创建模型目录并赋权
sudo mkdir -p /data/ollama/models
sudo chown -R ollama:ollama /data/ollama
sudo chmod 755 /data
sudo chmod 755 /data/ollama
sudo chmod 755 /data/ollama/models
验证目录链路:
namei -l /data/ollama/models
验证 ollama 用户可写:
sudo -u ollama bash -lc 'cd /data/ollama/models && touch .perm_test && rm -f .perm_test && echo ok'
如果返回 ok,说明目录权限已打通。
6.2 写入 ollama-gpu0.service
[Unit]
Description=Ollama GPU0 Service
After=network-online.target
[Service]
ExecStart=/usr/local/bin/ollama serve
User=ollama
Group=ollama
Restart=always
RestartSec=3
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Environment="OLLAMA_HOST=0.0.0.0:11434"
Environment="CUDA_VISIBLE_DEVICES=0"
Environment="OLLAMA_MODELS=/data/ollama/models"
Environment="OLLAMA_KEEP_ALIVE=-1"
Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KV_CACHE_TYPE=q8_0"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_MAX_QUEUE=1024"
Environment="OLLAMA_CONTEXT_LENGTH=8192"
[Install]
WantedBy=multi-user.target
6.3 写入 ollama-gpu1.service
[Unit]
Description=Ollama GPU1 Service
After=network-online.target
[Service]
ExecStart=/usr/local/bin/ollama serve
User=ollama
Group=ollama
Restart=always
RestartSec=3
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Environment="OLLAMA_HOST=0.0.0.0:11435"
Environment="CUDA_VISIBLE_DEVICES=1"
Environment="OLLAMA_MODELS=/data/ollama/models"
Environment="OLLAMA_KEEP_ALIVE=-1"
Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KV_CACHE_TYPE=q8_0"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_MAX_QUEUE=1024"
Environment="OLLAMA_CONTEXT_LENGTH=8192"
[Install]
WantedBy=multi-user.target
6.4 写入预热脚本 ollama-prewarm.sh
#!/usr/bin/env bash
set -e
MODEL="${1:-gemma3}"
for port in 11434 11435; do
echo "[prewarm] checking ${port}"
curl -sf "http://127.0.0.1:${port}/api/version" > /dev/null
echo "[prewarm] loading ${MODEL} on ${port}"
curl -sf "http://127.0.0.1:${port}/api/generate" \
-d "{\"model\":\"${MODEL}\",\"keep_alive\":-1}" > /dev/null
echo "[prewarm] verifying ${MODEL} on ${port}"
curl -sf "http://127.0.0.1:${port}/api/ps"
done
赋权:
sudo chmod +x /usr/local/bin/ollama-prewarm.sh
6.5 写入预热服务 ollama-prewarm.service
[Unit]
Description=Prewarm Ollama Models
After=ollama-gpu0.service ollama-gpu1.service
Wants=ollama-gpu0.service ollama-gpu1.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/ollama-prewarm.sh gemma3
[Install]
WantedBy=multi-user.target
6.6 停用默认单实例服务
sudo systemctl disable --now ollama || true
目的:
- 避免占用
11434 - 避免与双实例方案混用
- 保持服务治理边界清晰
6.7 重新加载并启动服务
sudo systemctl daemon-reload
sudo systemctl enable --now ollama-gpu0
sudo systemctl enable --now ollama-gpu1
sudo systemctl enable ollama-prewarm
sudo systemctl start ollama-prewarm
7. 参数设计说明
本次推荐参数如下:
OLLAMA_KEEP_ALIVE=-1
OLLAMA_FLASH_ATTENTION=1
OLLAMA_KV_CACHE_TYPE=q8_0
OLLAMA_MAX_LOADED_MODELS=1
OLLAMA_NUM_PARALLEL=4
OLLAMA_MAX_QUEUE=1024
OLLAMA_CONTEXT_LENGTH=8192
参数解释
OLLAMA_KEEP_ALIVE=-1
作用:
- 模型常驻内存
- 避免频繁卸载/重载
- 降低冷启动对时延的影响
OLLAMA_FLASH_ATTENTION=1
作用:
- 降低大上下文场景的内存开销
- 提高上下文扩展场景的稳定性
OLLAMA_KV_CACHE_TYPE=q8_0
作用:
- 降低 KV Cache 占用
- 在质量与显存之间取得平衡
OLLAMA_MAX_LOADED_MODELS=1
作用:
- 每实例只维持一个主服务模型
- 避免多模型竞争显存
- 避免行为复杂化
OLLAMA_NUM_PARALLEL=4
作用:
- 提高单实例并发承载能力
- 适合双实例吞吐优先场景
注意:
并发和上下文不是独立关系,而是联动关系。
实例压力近似与:
OLLAMA_NUM_PARALLEL × OLLAMA_CONTEXT_LENGTH
共同相关。
OLLAMA_MAX_QUEUE=1024
作用:
- 给短时高峰提供缓冲
- 降低瞬时尖峰导致的快速失败
注意:
队列不是性能放大器,只是缓冲区。
OLLAMA_CONTEXT_LENGTH=8192
作用:
- 控制单请求上下文预算
- 更适合吞吐优先型服务
如果业务是超长上下文任务,再单独为该类服务调整,而不要默认全局拉太高。
8. 启停与运维命令
8.1 启动
sudo systemctl start ollama-gpu0
sudo systemctl start ollama-gpu1
sudo systemctl start ollama-prewarm
8.2 停止
sudo systemctl stop ollama-prewarm
sudo systemctl stop ollama-gpu0
sudo systemctl stop ollama-gpu1
8.3 重启
sudo systemctl restart ollama-gpu0
sudo systemctl restart ollama-gpu1
sudo systemctl restart ollama-prewarm
8.4 查看状态
systemctl status ollama-gpu0 --no-pager -l
systemctl status ollama-gpu1 --no-pager -l
systemctl status ollama-prewarm --no-pager -l
8.5 查看日志
journalctl -u ollama-gpu0 --no-pager --follow --pager-end
journalctl -u ollama-gpu1 --no-pager --follow --pager-end
journalctl -u ollama-prewarm --no-pager --follow --pager-end
9. 日常巡检手册
建议每天巡检一次,重点检查以下内容。
9.1 服务状态巡检
systemctl is-active ollama-gpu0
systemctl is-active ollama-gpu1
预期都应返回:
active
9.2 API 可达性巡检
curl http://127.0.0.1:11434/api/version
curl http://127.0.0.1:11435/api/version
9.3 模型运行状态巡检
curl http://127.0.0.1:11434/api/ps
curl http://127.0.0.1:11435/api/ps
确认:
- 两个实例都有运行模型
- 模型未异常卸载
- 上下文配置符合预期
9.4 GPU 巡检
ollama ps
watch -n 1 nvidia-smi
关注点:
ollama ps中模型是否为100% GPU- 两张卡是否都有显存占用
- 两张卡是否都有推理活动
9.5 目录权限巡检
namei -l /data/ollama/models
确认目录链路权限未被变更。
10. 健康检查手册
可直接执行:
/usr/local/bin/ollama-healthcheck.sh
也可手工检查:
curl http://127.0.0.1:11434/api/version
curl http://127.0.0.1:11435/api/version
curl http://127.0.0.1:11434/api/ps
curl http://127.0.0.1:11435/api/ps
判断标准:
version接口可返回ps接口能看到模型- 模型状态正常,无异常卸载
11. 故障排查手册
下面列出最常见问题及处理方法。
11.1 服务启动失败,提示端口被占用
典型报错:
bind: address already in use
处理步骤:
sudo ss -lntp | grep 11434
sudo ss -lntp | grep 11435
sudo lsof -i:11434 -P -n
sudo lsof -i:11435 -P -n
如果默认 ollama.service 在运行:
sudo systemctl disable --now ollama
必要时释放端口:
sudo fuser -k 11434/tcp
sudo fuser -k 11435/tcp
11.2 服务启动失败,提示目录权限不足
典型报错:
permission denied: ensure path elements are traversable
处理步骤:
sudo mkdir -p /data/ollama/models
sudo chown -R ollama:ollama /data/ollama
sudo chmod 755 /data
sudo chmod 755 /data/ollama
sudo chmod 755 /data/ollama/models
namei -l /data/ollama/models
验证:
sudo -u ollama bash -lc 'cd /data/ollama/models && touch .perm_test && rm -f .perm_test && echo ok'
11.3 模型首包很慢
排查方向:
- 是否未预热
- 是否未设置
keep_alive=-1 - 模型是否反复被卸载
检查:
curl http://127.0.0.1:11434/api/ps
curl http://127.0.0.1:11435/api/ps
必要时手工预热:
/usr/local/bin/ollama-prewarm.sh gemma3
11.4 压测时吞吐不高
排查方向:
- Python 客户端是否真的轮询了两个实例
- 是否所有请求都只打了一个端口
OLLAMA_NUM_PARALLEL是否过低OLLAMA_CONTEXT_LENGTH是否过高- 是否发生 CPU offload
检查:
ollama ps
watch -n 1 nvidia-smi
11.5 出现 503 overloaded
原因:
- 请求超出当前实例承载能力
- 队列已满或实例过载
处理建议:
- 检查调用侧是否做了均衡分流
- 检查并发是否过高
- 检查上下文是否过大
- 必要时适当调整
OLLAMA_NUM_PARALLEL或OLLAMA_MAX_QUEUE
12. 升级手册
12.1 升级前准备
先记录当前版本:
ollama --version
备份服务文件:
sudo cp /etc/systemd/system/ollama-gpu0.service /etc/systemd/system/ollama-gpu0.service.bak
sudo cp /etc/systemd/system/ollama-gpu1.service /etc/systemd/system/ollama-gpu1.service.bak
sudo cp /etc/systemd/system/ollama-prewarm.service /etc/systemd/system/ollama-prewarm.service.bak
备份脚本:
sudo cp /usr/local/bin/ollama-prewarm.sh /usr/local/bin/ollama-prewarm.sh.bak
sudo cp /usr/local/bin/ollama-healthcheck.sh /usr/local/bin/ollama-healthcheck.sh.bak
sudo cp /usr/local/bin/ollama_bi_gpu_client.py /usr/local/bin/ollama_bi_gpu_client.py.bak
12.2 升级步骤
停止服务:
sudo systemctl stop ollama-prewarm
sudo systemctl stop ollama-gpu0
sudo systemctl stop ollama-gpu1
替换 ollama 二进制后,执行:
sudo systemctl daemon-reload
sudo systemctl start ollama-gpu0
sudo systemctl start ollama-gpu1
sudo systemctl start ollama-prewarm
12.3 升级后验证
ollama --version
systemctl status ollama-gpu0 --no-pager -l
systemctl status ollama-gpu1 --no-pager -l
/usr/local/bin/ollama-healthcheck.sh
ollama ps
13. 回滚手册
如果升级后异常,按如下步骤回滚。
13.1 停止当前服务
sudo systemctl stop ollama-prewarm
sudo systemctl stop ollama-gpu0
sudo systemctl stop ollama-gpu1
13.2 恢复旧版配置与脚本
sudo cp /etc/systemd/system/ollama-gpu0.service.bak /etc/systemd/system/ollama-gpu0.service
sudo cp /etc/systemd/system/ollama-gpu1.service.bak /etc/systemd/system/ollama-gpu1.service
sudo cp /etc/systemd/system/ollama-prewarm.service.bak /etc/systemd/system/ollama-prewarm.service
sudo cp /usr/local/bin/ollama-prewarm.sh.bak /usr/local/bin/ollama-prewarm.sh
sudo cp /usr/local/bin/ollama-healthcheck.sh.bak /usr/local/bin/ollama-healthcheck.sh
sudo cp /usr/local/bin/ollama_bi_gpu_client.py.bak /usr/local/bin/ollama_bi_gpu_client.py
13.3 恢复旧版 Ollama 二进制
用备份的可执行文件覆盖当前版本。
13.4 重新加载并启动
sudo systemctl daemon-reload
sudo systemctl start ollama-gpu0
sudo systemctl start ollama-gpu1
sudo systemctl start ollama-prewarm
13.5 验证回滚结果
ollama --version
systemctl status ollama-gpu0 --no-pager -l
systemctl status ollama-gpu1 --no-pager -l
/usr/local/bin/ollama-healthcheck.sh
14. Python 接入说明
Python 侧推荐使用实例池方式,不要把调用写死到单一端口。
启动示例:
from ollama_bi_gpu_client import ProductionOllamaPool
pool = ProductionOllamaPool(
endpoints=[
"http://127.0.0.1:11434",
"http://127.0.0.1:11435",
]
)
pool.prewarm("gemma3")
resp = pool.generate("gemma3", "用中文介绍一下向量数据库。")
print(resp.get("response", ""))
接入原则:
- 所有业务统一走实例池
- 禁止直接写死单端口
- 探活失败后自动切换实例
- 所有关键请求建议保留
keep_alive=-1
15. 上线前最终检查清单
服务层
ollama-gpu0.service正常运行ollama-gpu1.service正常运行ollama-prewarm.service可执行成功- 默认
ollama.service已停用
路径层
which ollama路径确认无误/data/ollama/models存在ollama用户具备读写权限- 父目录链路可遍历
API 层
11434/api/version正常11435/api/version正常11434/api/ps可见模型11435/api/ps可见模型
GPU 层
ollama ps显示100% GPU- 双卡都有显存占用
- 双卡都有推理活动
调用层
- Python 客户端具备轮询
- Python 客户端具备探活
- Python 客户端具备失败切换
- 压测时两个实例都收到流量
调优层
load_duration在预热后明显下降prompt_eval_duration无异常飙升- 未出现持续性
503 overloaded - 参数收敛在稳定区间
16. 结语
到这里,这套 双卡 A100 + Ollama 的交付手册已经完整闭环了。
它不是一份“命令汇总”,而是一套真正可执行的落地方案,涵盖了:
- 部署
- 配置
- 权限
- 启停
- 预热
- 巡检
- 故障处理
- 升级
- 回滚
- Python 接入
真正的交付价值,不在于你把某个服务“拉起来了”,而在于:
这套东西交到别人手里,对方也能按文档把它稳定接住。