
把一批文件在两个 S3 兼容存储之间搬或者同步,rclone 和 mc 是最常见的两个命令行工具。网上对比文章不少,但多数是抄帮助文档,没真跑过。这篇把两个工具接在同一个 RustFS 上,限速、过滤、增量、断点四组场景逐个实测,数字都是本机跑出来的,复现命令在文末,你可以照着重跑对拍。
先交代环境:RustFS 单机(Windows 版二进制,S3 接口在 127.0.0.1:9000),rclone v1.75.2,mc RELEASE.2025-08-13(这是 minio/mc 仓库的最后一个 release,2026 年 MinIO 归档开源版之后,dl.min.io 的 mc 下载已经返回 410 Gone,GitHub 上的版本停在 2025 年 8 月,选型时这个现实要考虑进去,下文选型一节细说)。测试数据是一棵 303 个文件、约 74 MiB 的目录树,按类型分了五个子目录(日志、CSV、大文件、临时文件、图片),外加三个 20 MiB 的随机文件专门测大文件行为。所有命令在正文里,建议你照着在自己的存储上重跑一遍再下结论。
接 RustFS:两个工具都是零障碍
mc 的接法:
mc alias set rustfs http://127.0.0.1:9000 rfsadmin '你的密码'
mc mb rustfs/rvm-bench
rclone 写一份 config(rclone config 或直接编辑文件):
[rfs]
type = s3
provider = Other
access_key_id = rfsadmin
secret_access_key = 你的密码
endpoint = http://127.0.0.1:9000
都走 path-style,provider = Other 是 rclone 对非主流 S3 的通用档位,RustFS 上传下载全程没报一次错。这一轮两个工具打平,后面开始分高下。
说下为什么选 RustFS 当测试后端:这次横评要的是中立,两个工具一个来自 rclone 社区、一个来自 MinIO,后端再选这两家中的任何一个都难免偏心,RustFS 是第三方 S3 兼容实现,两边都不沾亲带故;顺带它也兼容 MinIO 客户端生态,mc 直接就能接,正好把「mc 脚本能不能无感迁到别的 S3」这个问题一起验了。要提醒的是本机回环没有网络抖动,限速数字测的是工具自身的限速精度,不是链路吞吐;三百文件、几十 MiB 的量级也测不出超大规模下的性能差异,这两点结论里都会注明边界。

限速:都有效,rclone 更精确
限速是备份任务最实际的需求:别让夜间同步把业务带宽挤掉。两边各限 2 MiB/s 传 60 MiB:
| 工具 | 命令 | 实测吞吐 |
|---|---|---|
| rclone | rclone copy big rfs:lim --bwlimit 2M |
稳定在 2.004--2.048 MiB/s,60 MiB 用时约 30 s |
| mc | mc mirror --limit-upload 2MiB big rustfs/lim |
进度条收敛到 2.07 MiB/s,60 MiB 用时 29 s |
两个都能把速度精确压在设定值上,这点都合格。差别在三个细节。第一,rclone 的 --bwlimit 支持时间表(比如 --bwlimit "08:00,10M 23:00,off",白天限 10 MiB/s 半夜不限),做定时备份不用再配 crontab 改参数;mc 只吃单值,或者用 MC_LIMIT_UPLOAD 环境变量。第二,mc mirror 帮助里没有 --limit-upload,它是全局旗标,要挂在 mirror 子命令后面才生效,挂错了位置不报错也不限速,这个坑实测踩过一次才发现。rclone 的限速是每个传输命令的正规旗标,位置放哪都行。第三,限速值两边都认 M 和 MiB,但含义不同:rclone 的 M 按十进制算,mc 的 MiB 按二进制算,写脚本时别混,差 5% 的账不好查。
过滤规则:语义完全不同,mc 在 Windows 上有坑
同一个需求:只要 .log 和 data/ 目录,排除 .tmp。两边各跑一遍,对端结果直接见分晓。
rclone 用 --include "*.log" --include "data/**" --exclude "temp/**",上传了 200 个 log 和 50 个 csv,temp 目录没进去。但注意 rclone 自己会打一条 ERROR:include 和 exclude 混用时解析顺序不确定,官方推荐改用 --filter 写规则文件。另外 rclone 的模式语义是:不含斜杠的 pattern 匹配所有层级,所以 *.log 连子目录里的都命中,这和很多人的直觉(只匹配根目录)相反。规则一多就该上 filter 文件,一行一条规则,顺序执行、先到先得,行为可预期:
mc 用 --exclude "*.tmp" --exclude "photos/*",结果 .tmp 确实被排除了,但 photos/* 完全没生效,photos 下 30 个文件全传了上去。换成 photos/** 再试,还是没排除。原因是 mc 的模式匹配在 Windows 上受路径分隔符影响,目录型 pattern 匹配不到 photos\img-1.jpg 这种反斜杠路径;*.tmp 这种纯文件名尾段模式不受影响。Linux 上跑 mc 这类目录 pattern 通常正常,但你在 Windows 上做备份脚本,这就是实打实的坑。
这一项 rclone 赢,而且赢得比较干净:过滤体系完整(include/exclude/filter/rules 文件、按时间 old-than/newer-than 都有),mc 只有 --exclude 加 --older-than/--newer-than,复杂一点的筛选需求就顶不住了。
增量与覆盖:mc mirror 的默认行为要先想清楚
这是整篇实测里差异最大、也最容易出事故的一项。往源目录改两个文件、加一个新文件,然后重跑同步:
rclone copy 重跑,只传了 300 KiB(两个改动的加一个新增的),其余全部跳过。基于 size + modtime 的增量判断,行为符合预期。
mc mirror 重跑,直接报错:
<ERROR> Failed to perform mirroring, with error condition (size)
Overwrite not allowed for `.../data/metrics-1.csv`. Use `--overwrite` to override this behavior.
mc mirror 默认不覆盖对端已存在但内容变了的对象,而且遇到这种不一致是中止而不是跳过,加 --overwrite 才继续。也就是说 mc mirror 的默认语义接近「只补缺失的,改过的不动」,对备份场景来说,源端更新过的文件会一直不同步,直到你发现并加上旗标。删除行为同理:对端多出来的对象,默认不删,要 --remove;rclone 这边 copy 不删、sync 默认删。两个工具的默认值刚好错开,整理成一张表:
| 行为 | rclone copy | rclone sync | mc mirror |
|---|---|---|---|
| 补对端缺失 | 会 | 会 | 会 |
| 覆盖对端已变的 | 会(size/modtime 变了就传) | 会 | 默认拒绝,要 --overwrite |
| 删对端多余的 | 不删 | 默认删 | 默认不删,要 --remove |
没有谁对谁错,但你脚本里用的是哪个默认值,决定了「同步」到底是镜像还是只增不减。写进 cron 之前想清楚,最好先 --dry-run 一遍。
断点续传:都是文件级,别指望分片续传
做法:限速 2 MiB/s 传三个 20 MiB 文件,跑到 25 秒强杀进程,重跑看行为。重跑时,两边对对端已经完整存在的对象都直接跳过:mc 侧实测 0.09 秒就结束了,一个字节没重传;rclone 侧同样跳过已完整的对象,尚未传完的文件则整个重传。
两个工具的续传粒度都只到文件级,没有更细的分片续传。20 MiB 文件在两个工具里都走单次 PUT(rclone 切 multipart 的门槛由 --s3-upload-cutoff 控制,默认 200 MiB,mc 也类似),进程一死,传了一半的那个文件对端不会有任何残留,重传也从零开始。真正的单文件分片续传,两个工具都不支持。大于 200 MiB 的文件走 multipart,中断后 S3 上会留下未完成的分片占空间,rclone 可以用 rclone backend cleanup 清理,mc 靠服务端的分片过期策略回收。mc 文档里常被提的 session 断点机制,实测对 Ctrl+C(SIGINT)有效,进程被 kill -9 强杀时 session 文件没有落盘,脚本里用信号量杀进程的话别指望它。
失败重试也值得单独看一眼,定时同步脚本最怕网络抖动。rclone 有两层重试:HTTP 层 --low-level-retries(默认 10 次)扛单次请求失败,操作层 --retries(默认 3 次)扛整个任务失败,抖动基本能自愈。mc mirror 也有 --retry,要显式开启,粒度是按对象重试:出错的对象逐个重试,但重试次数不可调,也没有分层。遇到整批性的失败(鉴权过期、网络中断这种),cron 脚本里还是得自己包一层兜底。
顺带说校验。rclone 默认按 size + modtime 判断要不要传,加 -c 会比对 MD5;S3 上单段 PUT 的 ETag 就是数据的 MD5,可以直接比,但 multipart 上传的 ETag 不是 MD5,rclone 会把真实 MD5 存在对象元数据里绕过这个限制。mc 的 --checksum 旗标要服务端支持 trailing headers 才能用,help 里写明要求 AWS、MinIO 这类实现,其他 S3 兼容存储上不一定可用,写进跨后端脚本前先在目标存储上验一遍。数据完整性要求高的备份,rclone 的校验链路更省心,rclone check 一条命令做全量对账,mc 对应的是 mc diff。
所以「断点续传」这项,两者打平,都只到文件粒度。谁也没有黑科技。
并发与规模:量大之后才显山露水
这次测试量级小,并发参数的差异没机会暴露,但生产迁移它是第一个要调的旋钮。rclone 的并发分两层:--transfers 控制同时在传的文件数(默认 4),--checkers 控制比对扫描的并发数(默认 8);mc mirror 对应的是 --max-workers(默认自动探测)。并发调大迁移确实快,但对端收到的请求量是线性涨的,RustFS 这类部署在单机或小集群上的存储,QPS 承受力有限,大规模迁移前先想清楚业务桶还剩多少余量,别把线上的桶打挂。
数据规模本身也是变量。三百个文件的目录,两个工具的扫描开销都可以忽略;真到百万级小文件,列举、比对的速度和客户端内存占用就会拉开差距,这部分这次没测。上量之前,拿真实规模的数据在目标存储上试跑一轮,比看任何评测都准。
从 MinIO 迁到 RustFS,脚本怎么换
很多团队的现实处境是:手里有一批写在 MinIO 上的 mirror 脚本,存储要迁到 RustFS,脚本跟着改还是换工具。实测下来两条路都通,改动量都不大。
沿用 mc 最省事。mc 对 RustFS 的兼容性这次是全流程验证过的:alias 指到 RustFS 的地址,建桶、mirror、限速、--remove 全部正常,一行命令都不用改。要过的关只有两个:一是上文说的默认语义检查,把脚本里的 mirror 逐个确认是想要「只补缺」还是「完整镜像」,缺 --overwrite 和 --remove 的补上;二是 mc 本身的版本来源,MinIO 归档后官方下载通道已经关了,新机器上要么用 GitHub 上 2025-08 的最后一个 release,要么趁迁移一起换成 rclone。不管走哪条,建议顺手把 mc 二进制收进内部制品库统一托管,别让新机器的部署依赖外网 GitHub 的可达性。
换 rclone 的改动也不大。把 config 里的 endpoint 从 MinIO 指到 RustFS,provider 保持 Other,然后重点核对三个行为差异:mc mirror 对应 rclone sync(但 sync 默认删多余,mc mirror 默认不删,行为反而变严了);mc mirror --watch 对应 rclone 的 bisync 或者干脆上 cron 轮询;脚本里如果用了 --exclude,按上文说的语义重新对一遍,别原样照搬。
--watch 值得多说两句,它听起来省心,实际是有代价的。S3 协议没有文件系统那种变更推送,--watch 依赖后端的事件通知能力,后端不支持时就只能靠周期性的扫描比对兜底。对象多的桶持续开着 watch,等于让客户端没完没了地发 List 请求,这部分 QPS 压力会一直压在存储端,生产大桶不建议把它当默认方案。rclone 那边的 bisync 是双向同步,官方标注 beta,复杂度高,双向语义下出错后的对账成本远超单向同步,大目录慎用。多数定时备份场景,cron + 单向同步反而是最省事的稳态。
不管换不换工具,迁移完成后的第一次全量对账别省:rclone 用 rclone check src rfs:bucket,mc 用 mc diff,两边数量和校验和都对上再下线旧存储。数据搬迁这种事,传输快慢是小事,对账严谨才是底线。
选型建议
给结论前先把适用边界说清:本次实测是 Windows 单机、localhost 回环、几十 MB 量级,测的是功能语义和限速精度,不是极限吞吐;RustFS 是 Windows 版二进制。你要复现,命令都在下面,环境不同数字会不同,但行为差异(覆盖语义、过滤语义、文件级断点)是工具代码决定的,跟环境无关。
选 rclone,如果你要的是:定时备份(bwlimit 时间表 + 现成的 cron 参数)、复杂过滤(filter 规则文件)、明确的增量语义(copy/sync 边界清晰)、Windows 环境下的目录过滤。选 mc,如果你已经在 MinIO 生态里有一堆 mirror 脚本要迁到 RustFS、只需要「补缺失 + --overwrite/--remove」这种简单语义、或者要 --watch 持续同步。两个工具在 RustFS 上功能全部正常,一个错误都没报过,这点可以放心。
完整复现命令:
mc alias set rustfs http://127.0.0.1:9000 rfsadmin '你的密码'
rclone config # 按 [rfs] 段配 s3 provider=Other
rclone copy big rfs:lim --bwlimit 2M
mc mirror --limit-upload 2MiB big rustfs/lim
rclone copy src rfs:f1 --include "*.log" --include "data/**" --exclude "temp/**"
mc mirror --exclude "*.tmp" src rustfs/f2
rclone sync src rfs:f1 # 默认删多余
mc mirror --overwrite --remove src rustfs/f2
rclone sync --dry-run src rfs:f1
mc mirror --dry-run --overwrite --remove src rustfs/f2
rclone 的文档在 rclone.org/docs(过滤规则细节见 rclone.org/filtering),mc 源码与最后一批 release 在 github.com/minio/mc。RustFS 的 S3 接入见 docs.rustfs.com,仓库在 github.com/rustfs/rustfs。