
分布式存储跑几年,总有一批机器要退役:过保的节点、容量更小的旧盘、要合并的机房。难点不在"关掉它",在于关掉之前那一池数据得有人搬到别处去。RustFS 的存储池退役(pool decommission)就是干这件专门活的:把选定池里的对象迁到剩余活跃池,腾空之后再把它从集群拓扑里摘掉,全程不用你手写迁移脚本。注意退役以池为单位:想换一块小盘、退一台机器,只能把包含它的池整体退役,不能只摘单块盘。它和"删数据"完全不同:退役是先搬后删,保证搬完才下线,不会出现数据半路消失;搬迁阶段在线做,收尾摘池之后需要按官方流程重启剩余节点才生效。
再均衡解决不了"要搬走一整池"这件事
很多人第一反应是上再均衡(rebalance)。但 rebalance 的假设是所有池都继续留着,它只是把数据在活跃池之间重新铺匀,不会减少集群的池数量,帮不了缩容、下线的诉求。退役要的是反方向:把一个池彻底抽干然后下线。RustFS 把这两件事分得很清,而且它们不能同时跑,再均衡进行中不能起退役,退役也没法中途插一个再均衡。要搬走一整池,认准 decommission。有些团队图省事直接加新池把旧池晾着,结果旧池成了没人管的孤儿盘,既占电又是个没人巡检的故障域。
退役前先算清三件事
动手前有三道硬门槛。其一,退役之后至少得留一个活跃池,不能把集群搬空。其二,剩余池的空闲空间要能吞下被搬出的已用字节,外加 30% 的开销余量,RustFS 硬性要求剩余空间覆盖"搬出量 + 30%",空间不够直接不让跑。其三,所有节点和磁盘都得健康,且没有正在跑的再均衡。另外建议先备份关键数据,挑低峰期做,并把要退役的池 ID 和卷表达式原样记下来,免得摘错。备份这步别跳过:退役是集群级的拓扑变更,动拓扑前留一份备份是稳妥做法。挑低峰期做,也是给搬迁留足吞吐、少打扰在线业务。这 30% 的空闲余量,可以理解为给搬迁途中再出状况留的余地:万一某块盘在搬移时坏了,剩余池还得有地方把那份数据重新复制出来。
Console 与 rc 两条操作路径
控制台路径最直观:用有退役管理权限的账号登进 RustFS Console,打开 Pool Decommission,核对目标池的 ID、卷表达式、已用容量和状态,点 Start Decommission,用 Sync 刷新池状态和移动计数器直到完成,最后从各节点的 RUSTFS_VOLUMES 里摘掉这池表达式并重启。命令行走 rc,先建别名再列池:
bash
rc alias set rustfs http://rustfs-node1:9000
rc admin pool list rustfs
rc admin decommission start rustfs 0 --by-id
rc admin decommission status rustfs 0 --by-id
池的编号是零基的,--by-id 后跟的就是这个序号;不想用序号,也可以直接传完整的卷表达式,比如 'http://rustfs-node1:9000/data/rustfs{1...4}/mnmd',这是最容易写错的地方,建议从 rc admin pool list 的输出里原样复制。status 能看到进度,中途反悔用 cancel,失败或取消后想重试先 clear 清掉元数据。注意取消不是回滚:官方文档明确 cancel 不会撤回已完成的搬迁,已经搬过去的对象就留在目标池里;想重跑,先 clear 再重新 start。搬迁的具体机制官方没有细说,从结果看是搬空之后才停用。
进度别凭感觉:status 和控制台的移动计数器是官方给的观测手段,想对单个池看得更细,用 rc admin pool status rustfs 0 --by-id 逐池详查。算不算搬完,只认 Completed 状态加失败计数归零,两个条件都满足再去摘池。

退役收尾:从拓扑里摘掉这池
这一步最容易被漏掉,也最容易出事。退役状态变成 Completed 之后,必须去每一个剩余节点的 RUSTFS_VOLUMES 里删掉那行被抽干池的表达式,然后用"和原来同样顺序的拓扑"重启 RustFS。顺序很关键:RustFS 的池拓扑按声明顺序解析,乱序或漏改会造成拓扑不一致。走 Helm 的话,顺序是先在集群里把池退役完,再去 pools.list 里删条目,永远不要去动或重排一个还在线的池条目。
校验退役真的做干净了
退役完别急着走。先在 Console 或 rc admin decommission status 确认目标池是 Completed,失败对象数和失败字节数都是零;从拓扑里摘掉池并重启后,再确认几件事:退役池不再出现在活跃池列表里、剩余节点磁盘全在线、剩余池显示出了搬迁过来的数据且空闲充足、原先在那池上的对象还能列能读、新写对象走的是 S3 端点。都过了,这批硬件才算真正安全下线。
如果诉求反过来是扩而不是缩:往 RUSTFS_VOLUMES 追加一个新池表达式并重启,RustFS 会把它纳进拓扑,后续写入自然铺到新池,已有数据不会自动搬过去,除非你主动再均衡。但扩容不算轻活,官方同样要求备份关键数据、挑维护窗口执行、全节点重启。还有个容易踩的坑:rc admin expand start/status/stop 听起来像扩容命令,其实是扩容后再均衡的别名,只重新分布现有数据,不会往 RUSTFS_VOLUMES 追加池。退役是先搬后删的减法,扩容是纳管加搬迁两步的加法,别在想下线硬件时误用了扩容动作。

官方运维文档把退役的每一步、rc 子命令和 Helm 注意事项都列全了(存储池退役)。实现与变更记录见 github.com/rustfs/rustfs。