谁在吃我的GPU?调用方级归因揭开家庭GPU真相

通过调用方归因发现47%的GPU时间来自自己的助手,可观测性才能把"GPU忙"翻译成"谁、为何、多久"。
文章来自 homelab 实践系列,作者为自己的本地 GPU 监控系统引入了"调用方→服务端归因"能力,将每条 GPU 利用率采样打上发起请求的具体服务标签。在为期7天、共1,055条采样的统计中,RTX 3090上约10,555秒的GPU时间被逐一溯源:47%流向作者自己的语音助手核心,17%流向可观测性栈(Langfuse在转录追踪数据中附带的音频),3.4%来自CI流水线,3.4%来自纯粹保活的预热任务。文章核心论点是:`nvidia-smi`只能回答"哪个进程",而共享服务场景需要第三层——调用方级监控。归因的实现成本极低(在请求边界而非采样边界打标),却能将"GPU莫名飙升"的告警转化为有名有姓的诊断结论。
从"GPU满载"到"谁在用GPU"
几乎每个搭建过 homelab(家庭服务器)的人都遇到过这一幕:GPU 占用率飙到 100%,风扇狂转,而你完全不知道机器上二十几个服务里到底是哪个在作祟。你打开 nvidia-smi,它只显示一个进程,关掉窗口,谜团依旧。
问题的核心在于,nvidia-smi 回答的是"哪个进程在用 GPU"。而在 Docker 技术栈里,这个进程往往是容器运行时,而不是真正干活的服务。你真正想知道的,是"哪个服务在用 GPU,耗了多少时间,以及是谁发起的调用"。

这篇来自 "The Local LLM Lab" 系列第 10 期的实测文章,作者给自己的 homelab 监控系统加上了一个关键能力:调用方→服务端的归因(caller→server attribution)。每一次 GPU 利用率采样都被打上标签——拥有该进程的服务,以及对于共享服务(如转录端点、嵌入端点),标注发起请求的调用方。过去 7 天里,归因系统记录了 1,055 条采样、约 110 万秒的 GPU 时间。结论很有意思。
实验设置:一张3090,两个共享服务
整套环境围绕一张 NVIDIA RTX 3090(24GB 显存,功耗限制 390W)展开。卡上运行着两个共享服务:
- Whisper ASR 转录服务——前面挂了一个 nginx 代理,作者的各类工具、可观测性栈、CI、以及一个预热任务都会打到这个代理。
- nomic-embed-text(Ollama)——一个嵌入端点,供 RAG 流水线使用。
整个设计里最关键的决定是:调用方信息来自请求本身,而不是进程。 当作者的助手核心把一段音频发给 whisper 代理时,这条采样被标记为 jarvis2-core → whisper-proxy,而不是 nginx → whisper。这正是"GPU 很忙"和"是我的助手在用它"之间的本质区别。
Whisper ASR 是 OpenAI 开源的自动语音识别模型,支持多语言转录与翻译,因其精度高、可本地部署的特点在 homelab 场景中广泛使用。它属于计算密集型推理任务——每次转录都会短时占满 GPU,是导致 GPU 利用率出现尖峰的典型工作负载。nomic-embed-text 是 Nomic AI 发布的文本嵌入模型,专为将文本转化为向量表示而设计,常用于 RAG(检索增强生成)流水线中的语义检索阶段。两个服务都属于"共享端点"——多个上游调用方会并发或交替地发送请求,这正是单靠 nvidia-smi 无法分辨真正消耗来源的根本原因:进程始终是同一个,但背后的请求发起方各不相同。
那个数字:47%
7 天内,GPU 的全部可归因时间中,47% 流向了同一个调用方——作者自己的助手核心(在总计 10,555 秒中占了 4,970 秒)。
| 调用方 | 秒数(7天) | 服务端 | 占比 |
|---|---|---|---|
| jarvis2-core(助手核心) | 4,970 | whisper-proxy | 47.1% |
| whisper-proxy(直接调用) | 920 | whisper 服务 | 8.7% |
| langfuse worker(可观测性) | 910 | whisper 服务 | 8.6% |
| langfuse minio(对象存储) | 860 | whisper 服务 | 8.1% |
| whisper-warmup(保活任务) | 360 | whisper 服务 | 3.4% |
| gh-runner(CI) | 360 | whisper-proxy | 3.4% |
| jarvis-server + watchtower | 410 | whisper-proxy/服务 | 3.9% |
| firefly importer | 80 | whisper 服务 | 0.8% |
| ollama-embed 调用方 | 210 | ollama-embed | 2.0% |
| UptimeKuma(健康检查) | 20 | whisper 服务 | 0.2% |
GPU 最大的消耗者,既不是某个大模型,也不是跑分或训练任务,而是助手在转录它自己录下的音频。语音备忘、会议录音、以及可观测性栈采集的追踪数据里附带的音频,统统流经 Whisper 端点,并被归因到各自的发起方。
归因带来的改变
没有调用方归因时,这张卡 7 天的故事只有一句话:"Whisper 服务用掉了 10,555 秒 GPU 时间。" 这只是个数字,无法指导任何行动。
有了调用方归因,故事就立体了:
助手是头号租户。 47% 的 GPU 时间都是作者自己的工具链消耗的,服务本就是为它而生,用量超过其余所有调用方之和。这既说明设计符合预期,也解释了为什么这个服务要 7×24 常驻而非按需启动。
可观测性栈是第二大租户。 Langfuse 的 worker 和 MinIO 合计吃掉 17% 的 GPU 时间——它们在转录存储的 LLM 追踪里附带的音频。这是一笔没人预算过的成本:追踪栈本身在用 GPU 干活,叠加在它所追踪的 LLM 之上。
CI 是一个真实但很小的租户。 GitHub runner 占了 3.4%——CI 运行时转录的测试夹具。量不大,但"意料之外":没人会想到 CI 会碰 GPU。
预热任务占 3.4%。 一个每隔几分钟 ping 一次端点、让模型保持热态的保活任务。这就是"保持温热"的成本被量化出来了——整整一周 3.4% 的 GPU 时间,什么也没做,只是待命。
结论是:GPU 并不是像告警暗示的那样"莫名其妙地忙"。它是因为一些具体、有名有姓的原因在忙,而这些原因加起来,是一个正常运转的技术栈,而非故障。 "GPU 100%"的告警是症状,归因才是诊断。
Langfuse 是一个开源的 LLM 可观测性平台,用于记录和分析大语言模型的调用链路、输入输出及性能指标,类似于分布式追踪系统在 LLM 场景的专项实现。其 worker 进程负责异步处理追踪数据,MinIO 则作为对象存储后端保存原始 payload,包括用户与模型交互时可能附带的音频文件。这解释了为何可观测性栈会意外产生 GPU 负载:当追踪数据中包含音频附件时,Langfuse 的处理流水线会自动调用 Whisper 端点进行转录,从而在"观测 LLM"这一动作本身上叠加了额外的推理成本。这类隐性开销在没有调用方归因之前几乎不可能被发现。
反驳:归因本身是不是开销?
一个合理的质疑:给每条 GPU 采样打上调用方标签是额外的记账工作,在热路径里就是开销。归因必须足够廉价,不能拖慢它所测量的推理。
作者采用的实现从设计上就很便宜:标签在请求边界设置,而非采样边界。请求进来时记录一次调用方,然后附加到这次请求产生的每一条采样上。每条采样的成本只是读一个字段,而非一次查找。在 1,055 条采样上,这点开销低于功率计的分辨率——你根本没法在 2 小时的统计桶里测出它来。
另一个质疑:归因只对经过请求边界的服务有效。一个在进程内加载并直接使用的模型(训练任务、直接脚本)没有调用方可标。对这类情况,服务级标签是能做到的最好结果,但也仍然聊胜于无。归因是一个光谱:请求驱动的服务做到调用方级,其余的做到服务级。
这里涉及一个可观测性设计的通用权衡原则——测量本身不能显著改变被测量的系统行为。常见的高开销归因方案包括:在每次 GPU 采样时反向查找进程所属容器(需要系统调用)、对每条采样做网络请求打标(引入 I/O 延迟)、或在推理热路径中插入同步埋点(阻塞推理线程)。本文作者采用的"请求边界设置标签、采样时仅读字段"的方式,本质上是将归因的代价从 O(每次采样) 降低到 O(每次请求),在请求数远少于采样数的推理服务场景中,这一比例差距可达数十倍。这与分布式追踪中"在请求入口注入 trace context、在链路中传播而非重新计算"的设计哲学一脉相承。
如果重新设计监控面板
作者给出了一个很实用的架构建议——GPU 监控面板应该分三层:
- 卡级: 利用率、显存、功耗、温度,也就是
nvidia-smi显示的那些。 - 服务级: 哪个容器拥有进程,占用了多少显存和时间,类似 Docker stats 但按 GPU 细分。
- 调用方级: 对共享端点,是哪个客户端的请求产生了每条采样。这是现有工具都不显示的一层,也恰恰是能回答"谁在用我的 GPU"的那一层。
第三层才是把仪表盘变成工具的关键。GPU 飙升时,你不用打开 nvidia-smi 瞎猜,直接看归因就能看到名字。某个服务失控(跑飞的任务、重试风暴)时,调用方列表会在同一视图里暴露它。真正有价值的数字不是"GPU 100%",而是"jarvis2-core 这周用了 4,970 秒,这里是导致它的请求"。
结论
一周的调用方级 GPU 归因给出了清晰答案:47% 的卡时流向作者自己的助手,17% 给了可观测性栈,3.4% 给 CI,3.4% 给一个纯粹待命、什么也不干的预热任务。GPU 从来就不是"神秘地忙",它是因为有名有姓的原因在忙,而归因是唯一能把这些原因展示出来的视角。
给所有搭建 homelab 的人一个启示:如果你的 GPU 飙升却不知原因,解药不是换一张更快的卡,而是给每一条采样打上调用方标签。 可观测性的价值,往往不在于更多指标,而在于能把"忙"翻译成"谁、为什么、花了多久"。
相关推荐

零成本搭建AI超级员工系统:智能体自动工作流全解析
深度拆解B站演示的AI超级员工系统:Agent智能体编排、数字人口播、地图与企业获客、24小时智能客服及法务模块全覆盖。分析零成本开户背后的商业逻辑与合规风险,帮助创业者判断这套AI数字员工系统的真实投产比。

Chatbot与AI Agent的本质区别:从对话到执行的跨越
Chatbot和AI Agent有什么区别?本文基于Learn Tech频道的MCP系列讲解,用订机票、笔记摘要等实例说明:Chatbot只给答案,Agent通过思考-行动-观察循环真正完成任务,并拆解模型、工具、记忆、目标四大部件及MCP的桥梁作用,同时讨论Agent的适用边界与权限风险。

免费GitHub仓库:342小时AI课程,从数学到MCP服务器
一个免费GitHub仓库提供342小时AI课程,包含523节课、20个阶段,覆盖数学基础到Agent构建和MCP服务器。支持目标驱动学习,每节课产出可留存的prompt、skill或agent,已有近10万人开始学习。