闲置Mac组建分布式GPU集群:LLM推理完整实操指南

把闲置 Apple Silicon Mac 组成分布式 LLM 推理集群的完整实践路径。
本文围绕将实验室多台闲置 Apple Silicon Mac 改造成分布式 LLM 推理集群展开:先通过 arp-scan 枚举局域网中的 M2 Max、M3 Ultra、M1 Pro 等设备并记录 CPU/GPU/内存信息,再用 Exo 的 mDNS 点对点网络完成组网;利用 Apple 统一内存消除 PCIe 拷贝,通过 llama.cpp 的 --n-gpu-layers 将尽量多的模型层卸载到 GPU;用 Ray 做请求路由、Exo 做模型分片,Ray Serve 按队列长度调度并允许单 GPU 承载多个 actor;最后用 powermetrics 与 Prometheus 监控 GPU 利用率,基于告警与 launchd 实现按需唤醒的自动扩缩,并核算出四台 Mac 全天运行电费不足 0.04 美元。
为什么要用闲置Mac做LLM推理?
大多数开发者的Mac在夜间都处于闲置状态,但一台M2 Max Mac Studio已经能以每秒8个token的速度运行Llama-2-7B推理。当实验室里有四台Apple Silicon机器时,把它们组成分布式推理集群,就能把空闲算力变成实用的LLM服务能力。

本文基于一篇完整的技术实践指南,拆解从网络拓扑发现、统一内存优化、Ray+Exo编排到监控告警的全流程。
第一步:清点硬件与构建网络拓扑
搭建集群的起点是枚举局域网内所有Apple Silicon设备。使用 arp-scan --localnet | grep -i apple 可以返回MAC地址和主机名。
一个典型实验室配置可能包含:两台M2 Max(38核GPU,400 GB/s带宽)、一台M3 Ultra(80核GPU,800 GB/s)和一台M1 Pro(16核GPU)。需要把每台主机、GPU核心数和统一内存大小记录到YAML配置文件中。
关键动作:在每台Mac上运行 exo cluster init --config inventory.yaml,让Exo通过mDNS建立点对点网状网络。这是整个集群的通信基础。
mDNS 与 Exo 的组网方式
mDNS(Multicast DNS,多播 DNS)是 Bonjour 背后的协议,允许局域网设备在不依赖中心 DNS 服务器的情况下,通过多播地址 224.0.0.251(IPv4)或 ff02::fb(IPv6)宣告并发现自身服务。每台 Mac 运行 exo cluster init 后会以类似 _exo._tcp.local 的服务类型广播主机名、IP 与端口,其他节点监听同一多播域即可自动建立点对点连接,无需手动填写所有 IP。
Exo 依赖这一机制形成「网状网络」(mesh):节点之间可以两两直连,模型分片信息与请求状态通过该网络传播。这种方式在实验室、家庭等同一二层局域网内开箱即用,但跨子网或启用 AP 隔离的 Wi-Fi 下多播常被阻断,需要改用显式地址列表或确保网络支持多播。首次组网后,建议用 dns-sd -B _exo._tcp 验证服务是否被正确发现,并确保所有 Mac 的防火墙允许对应端口入站,否则会出现节点可见但无法建立完整网格的情况。
统一内存:天然的共享张量缓冲区
Apple统一内存架构让CPU和GPU可以寻址同一物理页面,彻底消除了PCIe拷贝开销。这是Apple Silicon跑推理的独特优势。
llama.cpp 0.3.0通过 --n-gpu-layers 参数利用这一特性。在M2 Max上,7B模型可以卸载35层(32层模型实际可超量分配);而M3 Ultra的80核GPU可以直接承载全部32层:
./llama-server -m model.gguf -c 4096 --n-gpu-layers 35 --port 8080
验证层驻留情况可以用:llama-server -m model.gguf --verbose 2>&1 | grep "gpu_layers"。
实践建议:把 --n-gpu-layers 设置为每台机器GPU内存能容纳的最大层数,发挥各自硬件上限。
读懂 --n-gpu-layers 与「层驻留」
LLM 在 llama.cpp 等推理引擎中按 Transformer 层顺序执行,每层包含注意力、前馈网络及归一化模块。--n-gpu-layers N 的含义是把模型最靠近输入端的 N 层参数放在 GPU(Metal)上运算,剩余层回退到 CPU。由于统一内存让 CPU 与 GPU 共享同一块物理内存,这些「卸载到 GPU」的层只是把计算任务交给 GPU 核心,数据并不需要副本。
在 Apple Silicon 上,能卸载多少层取决于 Metal 后端可用的推荐最大工作集(recommendedMaxWorkingSetSize),它通常接近统一内存总量的一部分。若 N 设置得接近甚至略高于实际层数,引擎会把全部层放入 GPU;文中提到 M2 Max「35 层、32 层模型可超量分配」,是因为部分非层权重也占显存,实际可容纳层数由运行时按可用内存动态校核。验证时查看日志里的 gpu_layers 或 offloaded N/N layers 即可判断是否全部驻留 GPU。若出现溢出或回退,会显著拖慢速度,因此「设为 GPU 内存能容纳的最大层数」是性能与稳定性的平衡点。
编排:Ray负责路由,Exo负责分片
Ray处理请求路由,Exo负责把模型分片到整个网状网络中。
在性能最强的节点上启动head:
ray start --head --port=6379 --dashboard-host=0.0.0.0
在每个worker节点上运行:
ray start --address=<head-ip>:6379 --resources='{"GPU": 1}'
部署一个Ray Serve入口,把每个prompt转发给队列最短的actor:
@serve.deployment(ray_actor_options={"num_gpus": 0.25})
class Llama:
def __init__(self):
self.llm = LlamaCPP(model_path="model.gguf", n_gpu_layers=35)
async def __call__(self, request):
return self.llm(request.json()["prompt"])
注意 num_gpus 设为0.25,这允许单个GPU同时承载多个actor实例,提高资源利用率。
Ray Serve 与 num_gpus=0.25 的含义
Ray Serve 是一个构建在 Ray 之上的模型服务框架,它把每个 Python 部署(deployment)转换成可被 HTTP 调用的服务,并自动完成请求排队、副本编排与横向扩展。@serve.deployment(ray_actor_options={"num_gpus": 0.25}) 中的 num_gpus 并非要求物理 GPU 的精确切分,而是向 Ray 的调度器声明资源配额:一个 actor 只占用 0.25 个「GPU 单位」。这样同一块 GPU 上可以同时驻留最多 4 个 actor 副本,从而让内存占用不大的小模型或多实例推理提高利用率。
不过 num_gpus 只是逻辑声明,它不会自动隔离显存;真正决定能否并存的仍是统一内存容量与 llama.cpp 的内存占用。对于 7B 模型,若每个 LlamaCPP 实例已占用大量统一内存,启动多个 actor 反而可能互相挤占导致 OOM。因此实践中常把 num_gpus 设小,并配合副本数量、批处理大小和显存监控来调优:先以单副本稳定运行,再逐步提高副本数观察 GPU 利用率和内存水位,避免资源声明与实际占用脱节。
监控、自动扩缩与成本核算
用Apple原生的 powermetrics 采集GPU利用率:
sudo powermetrics --samplers gpu_power -i 1000 -n 1
把输出喂给自定义的Prometheus exporter(mac_gpu_exporter),每10秒抓取一次。
成本方面非常可观:四台Mac总功耗约120W,按美国平均电价约$0.015/kWh计算,24小时运行成本不到$0.04。这几乎是白送的算力。
添加告警规则触发自动扩缩:
avg_over_time(mac_gpu_utilization[5m]) > 0.8
通过简单的launchd任务唤醒休眠的Mac,实现按需扩容。
powermetrics、Prometheus exporter 与 launchd 的衔接
powermetrics 是 macOS 自带的底层性能采样工具,需要 sudo 权限,--samplers gpu_power 会输出 GPU 功耗、利用率、频率等指标,-i 1000 -n 1 表示每 1000 毫秒采样一次、只取一份后退出。与 NVIDIA 上的 nvidia-smi 不同,macOS 没有原生、常驻的 GPU 指标 HTTP 端点,因此文中用 mac_gpu_exporter 这种自定义组件周期性地执行 powermetrics、解析文本输出,再转换成 Prometheus 可抓取的 /metrics 格式。
自动扩缩的另一半是 launchd:它是 macOS 的初始化与服务管理守护进程,相当于 Linux 的 systemd。通过编写 plist 文件并放在 ~/Library/LaunchAgents 或 /Library/LaunchDaemons 下,可以定义「被调用时启动 Exo 与 Ray worker」的任务。Prometheus 告警规则触发后,由一个轻量控制器调用 launchctl load 或 SSH 唤醒目标 Mac;当利用率回落,再用 launchctl unload 使其休眠。这样无需常开所有机器,既省电又能应对突发负载,但要注意唤醒延迟(秒级到十秒级)需与业务超时匹配。
一个晚上就能跑起来
整套流程的门槛比想象中低:在每台闲置Mac上运行 exo cluster init,再把单个Ray Serve端点指向集群,第二天早上你就拥有了一个可用的分布式推理池。
值得关注的几个技术选择:Exo负责模型分片、Ray负责调度、统一内存消除数据搬运开销、powermetrics做本土化监控——这套组合充分利用了Apple生态的独特能力,而非生搬硬套NVIDIA集群的方案。
对于个人开发者和小型团队来说,这是一种把已有硬件资产价值最大化的务实路径。
相关推荐

Workbuddy零基础入门:桌面AI智能体如何落地工作流
Workbuddy桌面AI智能体零基础教程解读:从安装、积分领取到文件管理与自动化工作流搭建,对比CodeX的适用场景与成本差异,帮助职场人完成从AI提问者到AI管理者的思维转变。

OpenAI智能体新栈:计算机操作、决策API与超速工作流
OpenAI Dev Day发布智能体新栈:Computer Use操作速度超越普通人,Decisions API基于Luna实现极低延迟分类,Agents API开放同源计算机操作能力,GPT-6.1 Sol成本仅为Astra七分之一。本文梳理核心更新、实测数据与开发者落地要点。

梁文峰开源推理框架DeepInfo,硬刚美国禁令
DeepSeek在开源模型后再开源推理框架DeepInfo,包含GPU/CPU交叉流水线、小模型预判大模型复核、华为昇腾与英伟达芯片全面适配等技术,直面美国联邦禁令。本文解析其对AI产业落地的意义与开源策略。