1. 为什么你需要rsync来接力中断的文件传输我猜你肯定遇到过这种情况辛辛苦苦用scp或者sftp传一个大文件传了80%、90%突然网络一抖或者终端不小心关了整个传输直接中断一切从头再来。那种感觉就像你跑了42公里的马拉松最后100米摔了一跤裁判让你回到起点重跑。血压瞬间就上来了对吧我之前就经常被这个问题折磨。比如从家里的NAS往云服务器备份一个几十GB的虚拟机镜像或者从远程开发机拉取一个庞大的数据集。scp命令简单直接但它有个“致命”的缺点不支持断点续传。一旦中断之前传的那些数据就白费了既浪费了时间也浪费了网络带宽。更别提有时候服务器为了安全把默认的SSH端口22给改了换成了像2022、2222这样的自定义端口这时候很多命令的用法都得跟着变。这时候就该rsync这个“瑞士军刀”闪亮登场了。它不仅仅是一个文件同步工具更是一个智能的、支持增量备份和断点续传的数据传输利器。它的核心工作原理是“差异同步”先比较源文件和目标文件的差异通过校验和算法然后只传输发生变化的部分。对于中断的文件传输它配合--partial这个选项能保留已经传输成功的部分文件块下次同步时直接从断点开始“接着传”而不是“重新传”。所以当你面对一个因为网络波动、手动中断或者端口非标准而导致传输失败的任务时把scp换成rsync绝对是提升效率和保住头发的最佳选择。下面我就手把手带你用最接地气的方式搞定通过自定义SSH端口来恢复中断文件同步这件事。2. 从你的scp命令到rsync命令无缝转换让我们直接对照你给出的例子来操作这样最直观。你原本被打断的命令是scp -r -P 2022 xdhome.elvisiky.com:/data/xiedong/fooocus_tensorRT/TensorRT/demo/Diffusion/ ./这条命令的意思是递归地 (-r) 从远程服务器home.elvisiky.com上用户xd的指定目录通过端口2022(-P 2022) 复制到本地的当前目录 (./)。现在我们要把它“翻译”成具备断点续传能力的rsync命令。最核心的转换版本如下rsync -av --partial --progress -e ssh -p 2022 xdhome.elvisiky.com:/data/xiedong/fooocus_tensorRT/TensorRT/demo/Diffusion/ ./Diffusion/看起来参数多了几个别慌我们一个一个拆解保证你理解得明明白白。首先rsync命令的基本结构是rsync [选项] 源路径 目标路径。在这个例子里源路径xdhome.elvisiky.com:/data/xiedong/.../Diffusion/。注意这里路径末尾的/非常关键它告诉rsync“我要同步的是这个目录里面的内容”而不是这个目录本身。如果你省略了/rsync会在本地创建一个名为Diffusion的目录然后把远程的Diffusion目录整个放进去结果就会变成./Diffusion/Diffusion/这通常不是我们想要的。目标路径./Diffusion/。这是我们本地准备存放文件的目录。现在来看那一串选项-av --partial --progress -e ssh -p 2022-a(archive)这是“归档模式”是rsync的精华之一。它不是一个单独的选项而是一个组合包相当于同时开启了-rlptgoD。简单来说它能确保同步时保留文件的几乎所有属性包括权限、所有者、时间戳、符号链接等等并且是递归操作的。用它来备份或镜像目录非常省心。-v(verbose)输出详细信息让你能看到正在同步的文件列表。虽然有点“啰嗦”但在排查问题时非常有用。--partial(核心)这就是实现“断点续传”的魔法开关。默认情况下如果rsync传输一个文件到一半中断了它会删除这个不完整的部分文件。而加上--partial后它会保留这部分已传输的数据。下次再运行同样的命令时rsync会发现这个不完整的文件然后只传输剩余的部分。你还可以用更强大的--partial-dirDIR来指定一个目录专门存放这些部分文件避免弄乱目标目录。--progress在传输过程中显示进度条和百分比。对于大文件看着进度条一点点往前走心里会踏实很多。-e ssh -p 2022(关键)这是指定使用自定义SSH端口的方式。-e选项用来指定远程shell程序我们在这里通过它来传递SSH的端口参数。ssh -p 2022作为一个整体字符串传给-e意思就是“请使用SSH进行连接并且连接时使用-p 2022这个参数”。这是处理非22端口的标准做法。所以整条命令连起来读就是以归档模式、显示详情和进度通过SSH端口2022连接到远程服务器在同步时保留部分文件以实现断点续传将远程Diffusion目录下的所有内容同步到本地的./Diffusion/目录下。3. 深入理解rsync断点续传的机制与自定义端口知道了命令怎么写我们再来深入一层看看rsync到底是怎么做到“接着传”的以及为什么指定端口要那么写。理解了原理以后遇到任何变种情况你都能自己搞定。3.1--partial选项背后的故事你可以把文件传输想象成用卡车搬运一堆箱子。scp就像是一辆一次性的卡车必须把所有箱子一趟运完中途翻车了箱子全撒了下次得重新装车。而rsync配合--partial则像是一个智能物流系统它先给每个箱子文件块贴上唯一的条形码校验和。搬运时每成功送达一个箱子就在清单上打个勾。如果中途网络断了卡车抛锚已经送到仓库的箱子会原封不动地放在那里--partial的作用。下次重新启动任务时系统会扫描仓库里已有的箱子和清单发现有些箱子已经在了于是只调度卡车去运送那些缺失的箱子。技术上讲rsync在传输大文件时可能会将其分成多个数据块进行校验和比较。当启用--partial时一个文件即使没有完全传输成功其已接收的部分也会以类似filename.part的临时形式保存在目标位置。下次同步时rsync会识别这个.part文件并尝试从断点处追加数据完成后再重命名为正确的文件名。一个进阶技巧使用--partial-dir如果你同步的目录里文件很多或者你不想让那些.part临时文件出现在目标目录里可以使用--partial-dir选项。rsync -av --partial --partial-dir.rsync-partial --progress -e ssh -p 2022 source/ dest/这个命令会把部分传输的文件统一存放到目标目录下的.rsync-partial隐藏文件夹里这样你的dest/目录看起来就干净多了。完成后rsync会自动将它们移出来并合并。3.2 自定义SSH端口的几种指定方法为什么-e ssh -p 2022是标准答案因为rsync使用SSH作为传输隧道时本质上是在远程机器上启动了一个rsync守护进程来通信。-e选项就是用来设置这个远程shell命令的。除了直接在命令里写死还有更灵活的方法方法一使用SSH配置文件最推荐对于需要经常连接的服务器每次都敲端口号太麻烦。你可以在本地的~/.ssh/config文件里为这台服务器创建一个配置项Host home-server # 给你服务器起个别名 HostName home.elvisiky.com # 真实地址 User xd # 用户名 Port 2022 # 自定义端口 IdentityFile ~/.ssh/id_rsa # 可指定私钥路径保存之后你的rsync命令就可以简化成rsync -av --partial --progress home-server:/data/path/ ./rsync会自动读取SSH配置使用你设置的别名、用户和端口。这种方式既安全又便捷是管理多台服务器的首选。方法二环境变量法你也可以通过设置RSYNC_RSH环境变量来指定默认的远程shellexport RSYNC_RSHssh -p 2022 # 然后就可以省略 -e 参数了 rsync -av --partial --progress xdhome.elvisiky.com:/data/path/ ./这种方法适合在脚本中临时设置但不如SSH配置文件通用。方法三直接修改SSH命令格式-e参数后面的字符串其实就是完整的SSH命令所以你可以根据需要添加任何SSH支持的参数比如指定密钥、关闭密码认证等rsync -av -e ssh -p 2022 -i ~/.ssh/my_key -o PasswordAuthenticationno source/ dest/4. 实战演练处理复杂场景与性能调优掌握了基础命令和原理我们来看看在实际工作中可能会遇到哪些更复杂的情况以及如何让rsync跑得更快更稳。4.1 场景一同步数百万个小文件如果你要同步的是一个包含海量小文件的目录比如代码库、日志目录直接使用-av可能会比较慢因为rsync需要为每个文件计算校验和。这时可以尝试使用-W(whole file) 选项这个选项告诉rsync不要计算差异直接传输整个文件。对于大量经常变动的小文件有时直接全传比计算差异更快。但注意这会丧失增量同步的优势只适合第一次全量备份或文件几乎全变的情况。rsync -avW --partial --progress -e ssh -p 2022 source/ dest/使用--inplace选项默认情况下rsync会先传输到一个临时文件完成后替换原文件。--inplace让它直接修改目标文件。这可以节省磁盘I/O和空间但风险是如果传输中断目标文件可能处于损坏状态。结合--partial使用需谨慎。调整--bwlimit如果你不想让rsync占满所有带宽影响其他网络应用可以用这个选项限制速度单位是KB/s。rsync -av --bwlimit1000 --progress -e ssh -p 2022 source/ dest/ # 限制到约1MB/s4.2 场景二排除或只包含特定文件rsync强大的过滤功能可以让你精确定位需要同步的内容。排除文件/目录使用--exclude参数。支持通配符。# 排除所有 .log 文件和 tmp 目录 rsync -av --exclude*.log --excludetmp/ --progress -e ssh -p 2022 source/ dest/ # 也可以把排除规则写在一个文件里用 --exclude-from rsync -av --exclude-fromexclude-list.txt --progress -e ssh -p 2022 source/ dest/只包含特定文件这需要结合--include和--exclude并且顺序很重要。规则是先定义包含模式最后用--exclude*排除其他所有。# 只同步 .py 和 .sh 文件 rsync -av --include*.py --include*.sh --exclude* --progress -e ssh -p 2022 source/ dest/4.3 场景三干跑测试与恢复验证在真正执行一个可能改变大量数据的同步命令前强烈建议先进行干跑Dry Run。使用-n或--dry-run选项rsync会模拟执行整个同步过程告诉你它会做什么创建、删除、更新哪些文件但不会实际传输任何数据。rsync -avn --partial --progress -e ssh -p 2022 source/ dest/仔细查看干跑的输出确认符合你的预期后再去掉-n选项执行真正的同步。同步完成后如何验证文件是否一致对于重要数据可以在两端使用md5sum或sha256sum对文件或目录树生成校验和进行对比。虽然rsync本身的校验机制已经很可靠但多一层手动验证对于关键数据来说是值得的。5. 避坑指南我踩过的那些雷用了这么多年rsync我也没少掉进坑里。这里分享几个最常见的“坑点”希望能帮你省点时间。坑一路径末尾的斜杠/这是新手最容易困惑的地方。再强调一次rsync source/ dest/同步source目录内部的所有内容到dest目录下。rsync source dest/将整个source目录包括其本身同步到dest目录下结果会是dest/source/...。 在写命令前花一秒想清楚你想要的结果是哪一种。坑二权限问题Permission Denied如果你同步时遇到权限错误可能是以下几个原因SSH密钥问题确保你的公钥已经添加到远程服务器的~/.ssh/authorized_keys文件中。对于非22端口在ssh-copy-id时也要指定端口ssh-copy-id -p 2022 xdhome.elvisiky.com。目标目录权限确保你本地执行命令的用户对目标目录如./Diffusion/有写入权限。远程目录权限确保你使用的远程用户如xd对源目录有读取权限。坑三--delete选项的恐怖威力--delete选项会让目标目录变得和源目录一模一样源目录里没有的文件在目标目录里会被删除。这是一个危险操作如果你不小心把源路径和目标路径写反了可能会清空你的源目录。所以使用--delete前务必先进行干跑测试 (-n)并且最好结合--backup或--backup-dir选项使用给被删除的文件留个备份。坑四网络不稳定导致重复中断如果网络极其不稳定即使有--partial连接也可能频繁断开导致同步难以完成。这时可以考虑使用--timeoutSECONDS设置一个更长的超时时间。将命令写进脚本用while循环包装直到同步成功退出。#!/bin/bash until rsync -av --partial --progress -e ssh -p 2022 source/ dest/; do echo 传输中断10秒后重试... sleep 10 done对于极端情况可以考虑使用更专业的工具如lftp的mirror命令或者rclone它们在某些网络环境下的重试机制可能更健壮。最后再给一个我个人的小习惯对于非常重要的同步任务我通常会同时打开两个终端。一个运行着rsync命令另一个用tail -f实时监控目标目录下某个关键文件的增长情况或者用df -h观察磁盘空间变化。这样既能实时掌握进度也能在磁盘快满时及时干预。数据传输是个耐心活用好工具摸清它的脾气就能让它成为你得力的助手而不是烦恼的来源。