Skip to content

使用 rsync 传输数据到开发机

在向智算云平台的主机传输数据时,scp / sftp 是常用的命令行工具。但是如果对断点续传有比较高的要求,rsync 可能是更好的选择。

一个典型场景是文件夹包含大量小文件和几个大文件,并且网络带宽有限,那么 rsync 的增量传输和断点续传功能能够有效地减少带宽使用和传输时间。

Windows、macOS 和 Linux 对 rsync 的支持

  • Linux 通常可以通过系统软件源安装 rsync,但预装情况和版本取决于发行版与镜像。
  • macOS 可能预装 rsync 或兼容实现,但系统程序可能只兼容旧版 rsync 2.6.x。命令存在不代表它支持本文使用的所有选项。
  • Windows 默认不支持 rsync,需要使用 WSLCygwin
  • 如果开发机使用的镜像中未提供 rsync,也需要使用 Linux 包管理器自行安装。
新手提示

Windows 端操作难度较高,如果不熟悉 Windows 开发,建议选择其他数据传输方式。

准备工作

本地安装 rsync

首先,检查本地实际调用的 rsync 程序和软件版本:

language-bash
command -v rsync
rsync --version

本文的命令使用 --inc-recursive--info=progress2--inc-recursive 只有在两端均为 rsync 3.0.0 或更高版本时才能使用增量递归算法,--info=progress2 要求发起传输的一端为 rsync 3.1.0 或更高版本。为获得一致行为,本文要求本地和远程主机都使用 rsync 3.1.0 或更高版本。3.1.0 是兼容性最低要求,应优先使用系统软件源提供的当前维护版本。

macOS 用户可以通过 Homebrew 安装新版,并单独确认 Homebrew 程序的版本:

language-bash
brew install rsync
"$(brew --prefix)/bin/rsync" --version
command -v rsync
rsync --version

重要

安装完成后,当前 Shell 仍可能调用 /usr/bin/rsync。如果 command -v rsync 没有显示 Homebrew 路径,请按照 Homebrew 提示调整 PATH,或在传输命令中使用 "$(brew --prefix)/bin/rsync"。查看完整版本输出中的 rsync 软件版本,不要只根据 protocol version 判断兼容性。

确认远程主机上的 rsync

本文使用 rsync 传输数据到开发机,因此远程主机指开发机。

请在开发机上执行以下命令,检查实际程序和版本:

language-bash
command -v rsync
rsync --version

如果没有,可以使用以下命令安装和更新(以 Ubuntu 为例):

language-bash
sudo apt-get update
sudo apt-get install rsync

两端版本号不必完全相同,但都应满足 rsync 3.1.0 或更高版本的最低要求。

了解 zsh、bash 和文件系统差异

本文的命令使用 zsh 和 bash 均支持的 POSIX 风格引号与换行语法。从 macOS zsh 向 Linux bash 环境传输时,不需要仅因为 Shell 不同而改写命令;rsync 按字节传输文件,不会转换文件内容或换行符。需要注意以下差异:

  • 路径包含空格、方括号或通配符时,应引用完整参数。尤其不要在 zsh 中使用未引用且无法匹配的通配符,因为 zsh 和 bash 的默认处理不同。
  • -a 会请求保留权限、时间、符号链接、所有者和组,最终结果取决于两端账户和权限。如果不需要保留 macOS 的所有者和组,可在 -a 后添加 --no-owner --no-group,并在传输后检查 Linux 目标权限。
  • -a 不包含 ACL 和扩展属性。只有两端文件系统均支持且业务依赖这些元数据时,才添加 -A-X 并先做小范围验证。
  • macOS 文件系统通常不区分文件名大小写,并可能使用与 Linux 不同的 Unicode 文件名规范化方式。包含仅大小写或规范化形式不同的文件名时,应先验证代表性目录。
  • -a 保留符号链接本身。指向 /Users/... 等 macOS 绝对路径的链接在 Linux 中通常不可用。

生成示例数据文件

我们可以使用 dd 命令生成一个用于测试 rsync 数据传输的大文件:

language-bash
dd if=/dev/urandom of=dummyfile bs=1M count=150

这会创建一个 150MB 的随机数据文件,用于演示 rsync 的功能。

获取开发机 SSH 连接信息

请登录智算云平台,查看开发机的 SSH 连接命令。

SSH 连接命令示例:-p 38526 root@8.140.242.203

其中包含当前开发机的 SSH 端口号、用户名、SSH 主机 IP,下一步中将会使用。root 为默认 SSH 登录用户名(部分旧版实例展示为非 root 普通用户名,请重启)。

使用 rsync 传输数据

继续操作前,请完成准备工作中的本地和远程版本检查,确认两端均使用 rsync 3.1.0 或更高版本。

包含 SSH 端口号的 rsync 命令

智算云平台的开发机使用非默认 SSH 端口,我们需要在 rsync 命令中指定端口。

使用 -e 选项来设置 SSH 参数后,rsync 命令结构变为如下格式:

language-bash
rsync -e "ssh -p PORT" [其他选项] 源目录 用户名@远程主机:目标目录

传输单个文件

要传输单个文件到远程主机,使用以下命令:

language-bash
rsync -a \
  --partial \
  --partial-dir=.rsync-partial \
  --info=progress2 \
  --human-readable \
  -e "ssh -T -o Compression=no -p PORT" \
  /path/to/local/file \
  username@remote_host:/path/to/destination/
  • -a: 归档模式,保留文件属性
  • --partial: 保留未完成文件
  • --info=progress2: 显示总体进度
  • --partial-dir=.rsync-partial: 将部分传输的文件保存在指定目录
  • Compression=no: 避免对模型、压缩包和图片等通常已压缩的数据重复压缩

例如,要将生成的测试文件传输到远程主机的 /root/ 目录:

language-bash
rsync -a --partial --partial-dir=.rsync-partial --info=progress2 --human-readable \
  -e "ssh -T -o Compression=no -p 33260" \
  dummyfile root@8.140.242.203:/root/

如果目标位置已有该文件,rsync 会比较文件差异,只传输不同部分。

传输整个目录

要传输整个目录及其内容,使用以下命令:

language-bash
rsync -a \
  --inc-recursive \
  --partial \
  --partial-dir=.rsync-partial \
  --info=progress2 \
  --human-readable \
  -e "ssh -T -o Compression=no -p PORT" \
  /path/to/local/directory \
  username@remote_host:/path/to/destination/

注意源目录路径末尾没有斜杠 /。如果加上 /,表示要传输目录的内容而不是目录本身。

例如,要将 ~/Desktop/very-important-folder 同步到远程主机的 /root/very-important-folder,可以使用以下命令:

language-bash
rsync -a --inc-recursive --partial --partial-dir=.rsync-partial --info=progress2 --human-readable \
  -e "ssh -T -o Compression=no -p 33260" \
  ~/Desktop/very-important-folder root@8.140.242.203:/root/very-important-folder/

传输完成后远端的文件结构:

language-bash
(base) root@is-c7wqsja2wznj73pe-devmachine-0:~$ tree -L 2
.
└── very-important-folder
    ├── ssh.jpeg
    ├── ssh-port-forwarding-copilot.png
    ├── ssh-port-forwarding-http.jpeg
    └── ssh-port-forwarding-via-aicoder.png

1 directory, 4 files

使用 --exclude 选项排除特定文件或目录

如果想排除某些文件或目录,可以使用 --exclude 选项:

language-bash
rsync -a --inc-recursive --partial --partial-dir=.rsync-partial \
  --info=progress2 --human-readable --exclude='*.txt' \
  -e "ssh -T -o Compression=no -p PORT" \
  /path/to/local/directory/ username@remote_host:/path/to/destination/

这个命令会排除所有 .txt 文件。

使用 --delete 选项同步目录

如果想让目标目录与源目录完全一致(删除目标目录中源目录没有的文件),可以使用 --delete 选项:

language-bash
rsync -a --inc-recursive --partial --partial-dir=.rsync-partial \
  --info=progress2 --human-readable --delete --dry-run \
  -e "ssh -T -o Compression=no -p PORT" \
  /path/to/local/directory/ username@remote_host:/path/to/destination/

请谨慎使用此选项,因为移除 --dry-run 后,它会删除目标目录中的文件。先检查演练输出并确认方向和路径无误,再执行实际删除。

模型、压缩包和图片通常已经压缩,默认不要添加 -z。只有源数据以可压缩文本为主且带宽确实成为瓶颈时,才在小范围测试压缩效果。

传输大量数据时先只运行一个 rsync 进程。单个文件可以大于客户端或服务端内存;内存压力主要来自文件条目数量、并发进程和需要全局跟踪文件关系的选项。包含数百万个文件时,按一级子目录分批串行传输,并避免使用 -H

总结

以上就是使用 rsync 从本地传输数据到远程 Linux 主机的基本步骤。rsync 是一个强大的工具,有很多高级选项可以根据具体需求进行调整。在使用 --delete 等可能造成数据丢失的选项时,建议先使用 --dry-run 选项进行测试,以确保操作的正确性。

常见问题解答

如何进行断点续传?

rsync 可以复用保留的未完成文件。要让中断后的传输具备可恢复性,请在首次传输时使用以下选项,并在中断后重新运行同一条命令:

  • --partial:保留未完成文件,而不是在中断后删除。
  • --partial-dir=.rsync-partial:将未完成文件保存在目标目录下的指定子目录中。
  • --info=progress2:显示总体传输进度,不为每个文件生成详细日志。

使用这些选项的命令示例:

language-bash
rsync -a --inc-recursive --partial --partial-dir=.rsync-partial \
  --info=progress2 --human-readable \
  -e "ssh -T -o Compression=no -p PORT" \
  /path/to/local/directory/ username@remote_host:/path/to/destination/

如果传输中断,只需再次运行此命令,rsync 会从中断处继续传输。

注意

即使启用了以上选项,rsync 在部分文件缺失、源文件已变化或两端版本不兼容时仍可能重新传输。两端版本号不必完全相同,但都应满足本文的最低版本要求,并且在整个传输过程中不要改动源文件。

scp 是否也具有断点续传的功能?

不,scp(Secure Copy)并不具有与 rsync 相同的断点续传功能。如果使用 scp 传输文件时连接中断,再次运行相同的命令不会从中断处继续传输,而是会重新开始整个文件的传输。

scp 的主要优点是简单易用,但在处理大文件或不稳定网络环境时,rsync 通常是更好的选择。rsync 不仅支持断点续传,还能够只传输文件的变化部分,这使得它在同步和备份任务中特别有效。

如果你经常需要处理大文件传输或在不稳定的网络环境中工作,建议使用 rsync 而不是 scp。但对于简单的、小型的文件传输任务,scp 仍然是一个有用且直观的工具。