💥 案发现场
在搭建 8x RTX 4090 的 Ollama 高并发集群时,我编写了脚本来启动多个实例。然而在调试过程中,当我试图停止脚本或重启服务时,遇到了一个让人血压升高的现象:
并没有任何模型在跑,但 nvidia-smi 显示 8 张显卡依然被塞得满满当当!
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.129.03 Driver Version: 535.129.03 CUDA Version: 12.2 |
|-----------------------------------------+----------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
|=========================================+======================+======================|
| 0 NVIDIA GeForce RTX 4090 Off | 00000000:19:00.0 Off | Off |
| 31°C P0 30W / 450W | 18292MiB / 24564MiB | 0% Default |
|-----------------------------------------+----------------------+----------------------+
| 1 NVIDIA GeForce RTX 4090 Off | 00000000:1A:00.0 Off | Off |
| 30°C P0 28W / 450W | 18292MiB / 24564MiB | 0% Default |
| ... (以此类推,8张卡全红) |
+---------------------------------------------------------------------------------------+
症状总结:
- 高显存占用:每张卡都被占了约 18GB(正好是 Gemma-27B 模型的显存量)。
- 零算力利用:GPU-Util 为 0%,说明进程虽然占着坑,但没在干活。
- 杀不掉:尝试普通的
kill命令无效,显存依然不释放。
🕵️♂️ 原因分析
这是典型的 “僵尸进程” (Zombie/Orphan Processes) 问题。
当你强制终止(Ctrl+C)一个 Shell 脚本时,有时候只能杀掉脚本本身(父进程),而脚本启动的 Ollama 子进程(实际上是底层的 llama_runner)并没有收到退出信号,或者因为程序内部卡死(Deadlock)而忽略了普通的终止信号(SIGTERM)。
这些“孤儿”会继续霸占着显存不肯走,导致你无法启动新的服务,甚至导致 OOM(显存溢出)错误。
🛠️ 解决方案:从温柔到暴力
针对这种情况,我们有三层手段来处理。
方案一:精准狙击(推荐)
如果你只想清理卡住的集群实例,但想保留那个默认的 11434 全局服务,不要用 killall。
# 1. 查找所有 ollama serve 进程
ps -ef | grep "ollama serve"
# 2. 排除掉全局服务(11434),杀掉其他的
# awk '{print $2}' 提取进程ID (PID)
# xargs kill -9 传递给 kill 命令执行强制查杀
ps -ef | grep "ollama serve" | grep -v "11434" | awk '{print $2}' | xargs kill -9
- 关键点:必须使用
-9参数。普通的kill发送的是 SIGTERM(请你退出),卡死的进程听不见;-9发送的是 SIGKILL(强制处决),由操作系统内核直接把进程干掉,不容反驳。
方案二:按硬件查杀(最直观)
如果你不知道是哪个进程在捣乱,只知道显卡被占用了,可以直接问显卡驱动:“谁在用我的显卡?”
1. 查看占用者:
# -v 显示详细信息
sudo fuser -v /dev/nvidia*
你会看到一串 PID,这就证实了确实有残留进程。
2. 核弹清理(慎用):
这条命令会杀掉所有正在使用 NVIDIA 显卡的进程。如果你的服务器上还有别的人在跑训练,慎用!
# -k: kill (杀掉)
# -9: SIGKILL (强制)
# -v: verbose (显示过程)
sudo fuser -k -9 -v /dev/nvidia*
执行完这条,世界瞬间清净了。
方案三:地毯式轰炸(最简单)
如果你确定服务器上除了 Ollama 没别的显卡应用,且不在乎重启全局服务,直接用 pkill。
# 强制杀掉所有名字里带 "ollama" 的东西
sudo pkill -9 ollama
注意:这会连同 Systemd 管理的全局 Ollama 服务一起杀掉。执行完后,记得用 systemctl start ollama 把全局服务拉起来。
🛡️ 如何避免?
为了防止以后每次都要手动“收尸”,建议不要直接在前台跑 Shell 脚本,而是将你的集群脚本注册为 Systemd 服务。
Systemd 在停止服务时,会利用 cgroup 管理机制,确保把该服务启动的所有子子孙孙进程全部清理干净,不会留下僵尸进程。
Systemd 服务文件示例 (/etc/systemd/system/ollama-cluster.service):
[Unit]
Description=Ollama 8-GPU Cluster
After=network.target
[Service]
Type=forking
ExecStart=/bin/bash /root/scripts/start_cluster.sh
# 这一行是关键:服务停止时,杀掉控制组内的所有进程
KillMode=control-group
Restart=always
[Install]
WantedBy=multi-user.target
📝 总结
遇见“显存占满但 GPU 利用率为 0”的情况,不要慌张:
- 先用
nvidia-smi确认显存确实没释放。 - 使用
sudo fuser -v /dev/nvidia*揪出幕后黑手。 - 使用
kill -9或fuser -k -9执行“死刑”。 - 切记:在 Linux 下处理卡死的显卡进程,只有
-9(SIGKILL) 才是真正的终结者。
希望这篇避坑指南能帮各位“炼丹师”节省宝贵的排查时间!🚀
版权属于:soarli
本文链接:https://blog.soarli.top/archives/789.html
转载时须注明出处及本声明。