适用场景:AI 训练/推理集群、数十 TB 级数据集迁移、多套对象存储对接、单容器聚合多数据源
核心工具:rclone(通用)、juicesync(对象存储专用)、find + diff 对账
核心纪律:迁移前先对账,迁移后必校验------丢了哪个目录,比慢一天更致命
一、背景:数据搬运为什么是 AI 集群交付的高风险环节
AI 集群里,数据搬运的坑比 GPU 调度还多:
- 几十 TB 的数据从文件存储迁到对象存储,跑了一夜,不知道到底迁全了没有
- 两个对象存储 bucket 之间迁移,网络抖动导致部分文件传输中断,没重试就当完了
- 容器里同时挂了多个数据源,路径混乱,研发写脚本时写错目录,把训练数据写到了备份盘
- 挂载参数不对,单流读只有几十 MB/s,训练 I/O 直接成瓶颈
所以这一块要讲清两件事:怎么高效搬 (工具参数)和怎么确认搬对了(对账)。
二、rclone 大规模迁移:几十 TB 级的姿势
rclone 是通用的存储搬运工具,支持对象存储、文件存储、本地目录等多种后端,一条命令打通。
2.1 基础用法
复制(保留源端,源端不动)
bash
rclone copy --transfers 32 <src> <dst> --progress
移动(搬完从源端删除,用于"迁移+清理"场景)
bash
rclone move \
--transfers 32 \
--s3-upload-concurrency 4 \
--checkers 16 \
--timeout 5m \
--retries 5 \
--retries-sleep 30s \
-L \
<src> <dst>
2.2 参数怎么选
| 参数 | 含义 | 经验值 |
|---|---|---|
--transfers N |
并发传输的文件数 | 大文件 16~32,海量小文件 64+ |
--checkers N |
并发做校验的协程数 | 一般等于 transfers |
--s3-upload-concurrency N |
单文件的分片并发数 | 4~8,太大反而被限流 |
--timeout 5m |
单请求超时 | 大文件调大,默认 5m 常不够 |
--retries 5 |
失败重试次数 | 跨地域建议 5~10 |
--retries-sleep 30s |
重试间隔 | 被限流时加这个,避免雪崩 |
-L / --copy-links |
跟随软链接 | 迁文件存储时经常需要 |
--fast-list |
用更少 API 调用列举目录 | 海量小文件时显著提速 |
--progress |
实时显示进度 | 长任务必备 |
2.3 迁移前必须做 dry-run
和批量运维一个道理,rclone 也支持先模拟:
只列出会做什么,不真传
bash
rclone copy --dry-run --transfers 32 <src> <dst>
加 --max-depth 2 先看目录结构对不对
bash
rclone copy --dry-run --max-depth 2 <src> <dst>
2.4 常见坑
| 现象 | 原因 | 解决 |
|---|---|---|
| 跑得慢 | transfers 太小 / 单连接被限速 | 调到 32,加 --fast-list |
| 报限流错误 | 请求太密 | 降 transfers,加 --retries-sleep |
| 软链接没跟着走 | 没加 -L |
加 --copy-links |
| 小文件海量时列举极慢 | 没用 --fast-list |
加上 |
| 迁完发现缺文件 | 没做对账 | 用第四章的目录树比对 |
三、对象存储专用搬运:juicesync
如果两端都是对象存储(如不同 bucket 之间、对象存储到本地),可以用 juicesync,走对象存储原生 API,效率比通用工具更高。
基础用法(线程数按机器规格调)
bash
juicesync --threads=110 <src> <dst>
内网/专线环境关闭 HTTPS 提速
bash
juicesync --no-https --threads=80 <src> <dst>
参数选择:
| 参数 | 含义 | 经验值 |
|---|---|---|
--threads |
并发线程数 | 100~200,看机器核数和带宽 |
--no-https |
走 HTTP 而非 HTTPS | 仅限可信内网/专线,省掉 TLS 开销 |
--update |
跳过目标端已存在的更新文件 | 增量迁移时用 |
--delete-src |
迁完删源端 | 等价于 rclone move |
⚠️
--no-https只在内网可信通道用,公网务必走 HTTPS。另外多套凭证(AK/SK)对应不同的 endpoint,配置文件里要写成多个 remote,别配串了。
四、多套对象存储对接:AK/SK 与 endpoint 的规范写法
生产环境一般不会只对接一套对象存储,可能有:业务数据桶、备份桶、跨区域同步桶等。配置时记住三条:
4.1 endpoint 用占位符,不写死具体地域
rclone 配置示例(脱敏写法):
bash
[s3-prod]
type = s3
provider = <你的对象存储厂商>
env_auth = false
access_key_id = <YOUR_ACCESS_KEY>
secret_access_key = <YOUR_SECRET_KEY>
endpoint = <your-object-storage-endpoint>
region = <your-region>
bash
[s3-backup]
type = s3
provider = <你的对象存储厂商>
access_key_id = <YOUR_ACCESS_KEY_2>
secret_access_key = <YOUR_SECRET_KEY_2>
endpoint = <your-backup-endpoint>
region = <your-region>
4.2 AK/SK 管理规范
- 不同业务用不同 AK/SK,别一套密钥打通所有桶
- 权限最小化:迁移账号只给源端读、目标端写,不给删桶权限
- 别写进剧本明文 :用
rclone config存到独立配置文件,或走环境变量注入 - 泄漏即轮换:AK/SK 一旦提交到 git,立刻在控制台禁用并生成新的
4.3 多 endpoint 场景的调用方式
从业务桶迁到备份桶
bash
rclone copy s3-prod:bucket-dataset s3-backup:bucket-dataset --progress
跨端点到本地
bash
rclone copy s3-prod:bucket-dataset /data/dataset --transfers 32
五、迁移前对账:目录树比对(这条最值钱)
搬了几十 TB,怎么确认目录一个没少,文件一个没漏?
5.1 源端和目标端各出一份目录树清单
源端
bash
cd /data/dataset && find ./ -type d | sort > src_dirs.txt
目标端
bash
cd /mnt/dataset && find ./ -type d | sort > dst_dirs.txt
5.2 diff 找差异
源端有、目标端没有的目录(漏迁的)
bash
comm -23 src_dirs.txt dst_dirs.txt > missing_in_dst.txt
目标端有、源端没有的(多出来的)
bash
comm -13 src_dirs.txt dst_dirs.txt > extra_in_dst.txt
直接看差异
bash
diff src_dirs.txt dst_dirs.txt
5.3 为什么用目录树而不是全量文件清单
几十 TB 的数据往往有千万级小文件 ,find -type f 全量出清单可能要跑很久。目录树清单通常只有几 MB,秒级 diff,用来做"有没有漏迁某个子目录"的粗校验非常划算。
💡 对账三层递进:① 目录树 diff(秒级,查漏) → ② 文件大小+mtime 比对(分钟级,查错) → ③ 抽样哈希校验(小时级,查损坏)
六、容器挂载多数据源:一个容器挂多个目录
训练容器经常需要同时访问多种存储,常见组合:
| 挂载点 | 存储类型 | 用途 |
|---|---|---|
/mnt/fs-hot |
并行文件系统 | 高速共享训练数据 |
/mnt/nas-common |
文件存储/NFS | 通用数据 |
/mnt/nas-archive |
文件存储/NFS | 归档/备份数据 |
/mnt/obj-backup |
对象存储挂载 | 备份盘 |
/mnt/local-data |
本地盘/PVC | 热数据/缓存 |
/mnt/fs-project |
另一种并行文件系统 | 项目专用数据 |
6.1 注意事项
- 路径不要重叠 :别出现
/mnt/data和/mnt/data/sub同时挂载后者会被前者覆盖住 - 挂载顺序有讲究:父目录先挂,子目录后挂
- 写权限要分清:备份盘挂成只读,避免训练脚本误写
- 故障隔离 一个挂载点挂起(hung)时时,用
soft+timeo避免拖垮整个容器
6.2 示例:只读挂备份盘,读写挂数据盘
备份盘只读:读
bash
mount -t nfs -o nfsvers=3,soft,noresvport,ro <storage-server>:/backup /mnt/obj-backup
数据盘读写:写
bash
mount -t nfs -o vers=4.1,rsize=1048576,wsize=1048576,hard,noresvport <storage-server>:/data /mnt/local-data
6.3 Kubernetes 里多 PVC / 多挂载点
伪配置示意(实际写在 pod spec 的 volumes + volumeMounts 里)
volumes:
• name: fs-hot
persistentVolumeClaim:
claimName: pvc-fs-hot
• name: obj-backup
nfs:
server: <storage-server>
path: /backup
containers:
• name: trainer
volumeMounts:
◦ name: fs-hot
mountPath: /mnt/fs-hot
◦ name: obj-backup
mountPath: /mnt/obj-backup
readOnly: true
七、踩坑清单
| 现象 | 排查点 |
|---|---|
| 迁完发现缺目录 | 没做目录树对账,comm -23 找出漏迁的 |
| 对象存储报鉴权失败 | AK/SK 和 endpoint 不匹配,或权限策略没开 |
| 容器里挂载点看不到内容 | 挂载顺序问题,子目录被父目录盖住 |
| 训练脚本把数据写到了备份盘 | 备份盘没挂只读,用 ro 选项挂载 |
| 迁移中途断网,重跑又重传一遍 | 没加 --update 或 --retries |
| 对象存储限流报错 | transfers/threads 太高,降并发 + 加重试间隔 |
| 多套 endpoint 串桶 | remote 名写混了,先 rclone lsd <remote>: 验证再迁 |
八、小结
数据搬运与存储对接的三条主线:
- 高效搬 rclone 通用(
--transfers 32 --fast-list)、JuiceSync 专攻对象存储(--threads)、先 dry-run 再全量量 - 确认搬对 :迁移前源端目标端各出目录树清单 →
comm比对 → 文件级抽样哈希校验 - 多源挂载规范 :不同存储挂不同路径、不重叠、备份盘挂只读、容器里用
readOnly: true兜底
一句话:数据迁移不怕慢,怕的是搬完了不知道搬全了没有。对账流程必须和搬运流程一起上线。
有问题的在评论区贴你的 rclone 命令和 comm 比对结果,我看到会回。