模型权重散落在每台 GPU?用 RustFS 给 vLLM 做共享权重库

多卡推理集群要面对一个现实:模型权重散落在每台机器上,节点越多越难管。A 节点还跑着上周的量化版,B 节点已经换上新 checkpoint,排查「为什么两台机器输出不一样」时,第一反应往往是去比对本地缓存。扩容一台新机器,光把几十 GB 的权重从 Hub 拉到本地盘就要等半天。把权重收进一个统一的对象存储桶,让所有节点只读同一份源,这个老问题其实有更省心的解法。

权重留在节点本地,代价是三件事

传统做法里,每台 GPU 机器先把模型权重下载到本地盘再起 vLLM,表面上各管各的不互相打扰,代价会随集群变大显出来。

第一是空间浪费。真实 serving 的模型权重比 demo 大得多:7B 模型半精度(fp16,一种用两个字节表示一个浮点的压缩精度)约 14GB,70B 约 140GB。十台机器各自存一份(以 70B 计),就是上 TB 的重复占用,而且和对象存储、日志、临时文件抢同一块本地盘。

第二是版本漂移。权重以文件形式躺在各节点本地,没有统一的版本锚点,谁先更新、谁没更新很难一眼看清。一次回滚要逐台机器去替换文件,容易漏。

第三是扩容慢。新节点上线第一件事是下载权重,集群越大、模型越大,冷启动时间越长。

把权重放进 RustFS 这样的对象存储,相当于给集群一个单一事实源:权重只存一份,所有节点以只读方式挂载同一份源,换版本靠桶内前缀切换,回滚就是换个前缀。在集群里,每个 GPU 节点都跑一份只读挂载,扩节点不再需要等下载,新节点加入时只要挂上同一个桶就能立刻拿到完全一致的那份权重。顺序读大对象的吞吐没有公开基准数字,要按自己集群的网络和磁盘去测,但「一次上传、处处只读」的架构本身就把上面三件事消掉了。

官方已经走通的验证路径

RustFS 官方给出了 vLLM 接对象存储的验证流程(RustFS 官方 vLLM 集成指南),用的是 vllm/vllm-openai-cpu(vLLM 0.30.0)镜像、RustFS 侧用 rustfs/rustfs-x86-musl:v2.3.1 部署,在纯 CPU 主机上对 facebook/opt-125m 跑通。思路是:权重留在 RustFS,各节点把桶只读挂载成本地目录,vLLM 当作本地文件读,容器本身无状态。

先把模型上传到 RustFS。用 rclone(一个能把对象存储桶挂成目录的工具)配置指向 RustFS 的 S3 端点,再建桶、拷文件:

ini 复制代码
[rustfs]
type = s3
provider = Other
access_key_id = <your-access-key>
secret_access_key = <your-secret-key>
endpoint = http://<your-rustfs-endpoint>:9000
region = us-east-1

rc 的命令假设同名别名已配好,装好 rc 后先执行:rc alias set rustfs http://<your-rustfs-endpoint>:9000 <your-access-key> <your-secret-key>(rc 的安装说明见官方 rc 手册)。

bash 复制代码
rc mb rustfs/vllm-models
rclone copy ./opt-125m rustfs:vllm-models/opt-125m --transfers 4

--transfers 4 开四个并发拷贝,文件多的 HuggingFace 目录能明显快一些。每个模型占一个独立前缀(目录),多个模型可以共用同一个桶。

然后在跑 vLLM 的机器上把桶只读挂出来,供其它用户访问:

bash 复制代码
mkdir -p /mnt/vllm-models
rclone mount rustfs:vllm-models /mnt/vllm-models \
  --allow-other --daemon
ls /mnt/vllm-models/opt-125m/

最后起 vLLM,把挂载目录以只读方式映射进容器,让它按本地路径读权重:

bash 复制代码
docker run -d --name vllm -p 8000:8000 --shm-size=2g \
  -v /mnt/vllm-models:/models:ro \
  vllm/vllm-openai-cpu:latest \
  --model /models/opt-125m --served-model-name opt-125m \
  --dtype float32 --max-model-len 256 --gpu-memory-utilization 0.15

--shm-size=2g 给 CPU 引擎的共享内存留出空间,否则张量交换会报 /dev/shm 不足。等服务就绪,用 OpenAI 兼容接口就能直接打推理请求,Python 客户端不用改一行。

为什么走挂载,而不是直接 s3:// 读

vLLM 0.30 通过内置的 RunAI model streamer(一个负责流式拉取权重的组件)去读 s3:// 路径,但它对自定义 S3 端点的分段读取目前有个硬限制:任何非零偏移的读取都会报 File access error,模型权重又正好是分段大文件。于是把桶挂成文件系统、让 vLLM 按本地文件读,成了经过验证的方式。

代价是多了 FUSE(用户态文件系统,把对象存储映射成目录的那一层)这一道。对模型加载这种「一次读一个大文件」的场景,开销基本可以忽略;但如果是极高 QPS 的小文件反复读,FUSE 层会吃一部分性能,那时候该考虑在节点本地加一层缓存,避免反复穿对象存储。

上生产还要补的四件事

官方示例是 CPU 主机的本地集成测试,不面向生产,真要上 GPU 集群还得补几块。

只读挂载加缓存。反复加载同一个模型时,给 rclone 加 --vfs-cache-mode full(缓存全部文件内容,重复读不再穿对象存储)和较短的 --dir-cache-time,能让节点复用本地缓存、减轻对象存储压力;缓存只是读加速,权威源仍在桶里,换前缀后旧缓存会随目录缓存过期自然失效。调试阶段加 --dir-cache-time 10s 能避免挂载目录缓存过期导致 vLLM 找不到权重。

先算带宽账。十台节点并发首次加载,入站流量是「模型大小 × 节点数」。一个 70B 模型约 140GB,十台同时冷启动就是 1.4TB 量级的对象存储出口流量,节点网卡和对象存储侧带宽要扛得住,否则首发延迟被下载拖死。

IAM 凭证收窄到只读。给挂载用的 access key 授权 vllm-models 桶内指定前缀的只读,照官方前缀限权示例的结构写两条语句:s3:ListBucket 那条挂 Condition 的 StringLike,把 s3:prefix 限到 opt-125m/*;对象级操作(s3:GetObject)的 Resource 写成 arn:aws:s3:::vllm-models/opt-125m/*。注意内置的 readonly 策略不含 s3:ListBucket,直接拿它挂载会列不出目录,要按这个结构建自定义策略。千万别拿管理员 key 去挂。

多模型靠前缀版本化。一个桶里每个模型一个前缀,发新版本就换新前缀,回滚就是切回旧前缀,天然带版本能力,不用额外数据库记版本。

试完想拆,按官方给的三步走

保留桶、只拆演示环境:docker rm -f vllm 停掉容器,再 fusermount -u /mnt/vllm-models 卸载 rclone 挂载点,不卸的话它会一直挂在目录上。要连桶内模型一起清,最后 rclone purge rustfs:vllm-models。

排障顺序与决策清单

真到现场,按这个顺序查:

  • 权重到底传进去了没有:rclone copy 之后先 rc object list rustfs/vllm-models/opt-125m 确认对象在桶里。
  • 挂载点有没有文件:起 vLLM 之前 ls /mnt/vllm-models/opt-125m/ 确认 config、tokenizer、safetensors 都在。
  • 报 Unsupported CPU attention configuration: head_dim=...:vLLM 的 CPU 内核只支持有限的 head_dim 集合,hf-internal-testing/tiny-random-* 这类微型测试模型会在请求阶段失败,换成真实的小模型,比如 facebook/opt-125m。
  • 报 Cannot find any model weights with /models/...:挂载目录缓存过期,或权重根本没传,重传一次,并把 --dir-cache-time 调短到 10s。
  • 报 Insufficient space in /dev/shm:容器加 --shm-size=2g 或 --ipc=host。
  • 服务退出提示 CPU 内存不够:默认的 KV cache(推理时缓存的注意力键值)预留占系统内存九成,用 --gpu-memory-utilization 0.15 调低,这个 flag 名字带 GPU,在 CPU 后端同样生效。

把权重收进对象存储之后,扩容和回滚都从一个桶开始,节点本地不再有会漂移的模型副本。RustFS 官方 vLLM 集成指南、S3 兼容性说明和 GitHub 仓库都在官方站点。RustFS 稳定线最新 1.0.4(2026-10-25),Apache 2.0 许可。

相关推荐
Ikalus19881 小时前
Netty 同一个洞,90 天后换了编号又回来 —— 官方公告自己写着「上次修得不完整」
开源
2501_946244781 小时前
开源鸿蒙平台 CMP 三方库「compose-continuous-rounded-corner-shape」适配全流程
华为·开源·harmonyos
wflynn1 小时前
GitHub 日榜趋势速报 | 2026-10-29
开源·github
2501_946244782 小时前
开源鸿蒙平台 CMP 三方库「Waterfall」适配全流程
华为·开源·harmonyos
2401_zq136y032 小时前
开源鸿蒙平台 CMP 三方库「Jewel」适配全流程
华为·开源·harmonyos
fb_123452 小时前
从探针到权限:一篇吃透 Kubernetes 健康检查、RBAC 认证授权与 Dashboard 可视化管理
云原生·容器·kubernetes
mengge.cloud3 小时前
10-28-Kubernetes健康检查认证授权与Dashboard
云原生·容器·kubernetes
2601_949480063 小时前
开源鸿蒙平台 KMP 三方库「AutoLinkText」适配全流程
华为·开源·harmonyos
做运维的阿瑞4 小时前
EKS 可销毁环境:集群创建、应用部署到账单归零
云原生·云计算·terraform