1. 项目概述:为什么Rsync依然是远程同步的“定海神针”
在运维和开发的日常里,数据同步是个绕不开的活儿。无论是代码部署、日志备份,还是跨服务器迁移海量文件,一个可靠、高效的工具能省下无数个加班的夜晚。你可能用过scp,它简单直接,但每次都是全量拷贝,面对几个G的增量更新,那种等待的煎熬实在难受。你也可能听过rsync,知道它很强大,但面对它那一长串的参数,是不是有点望而却步,最后又用回了老方法?今天,我就结合自己十多年在真实生产环境里摸爬滚打的经验,来彻底拆解rsync这个“老将”。它绝不是一个简单的拷贝命令,而是一套完整的增量同步策略。通过10个由浅入深的实例,我会带你从“会用”到“精通”,理解它背后的核心逻辑,掌握那些能真正提升效率、保障数据安全的“骚操作”和“避坑指南”。无论你是刚接触Linux的新手,还是想优化现有工作流的老兵,这篇文章都能让你对rsync有一个全新的认识。
2. Rsync核心机制深度解析:增量传输的智慧
在直接敲命令之前,我们必须先搞懂rsync是怎么工作的。把它想象成一个拥有“记忆”和“策略”的智能快递员,而不是一个只会蛮干的搬运工。
2.1 “快速检查”算法:同步效率的基石
rsync的核心魔力在于其“快速检查”算法。它并非盲目地比较两个文件的每一个字节,那在大文件面前将是灾难。其工作流程可以拆解为以下几步:
- 分块与签名:对于源文件,
rsync会将其逻辑分割成若干固定大小的块(默认大小约700字节),并为每一块计算两个校验和:一个32位的滚动校验和一个128位的MD4强校验和。这个“滚动校验和”的设计非常巧妙,它允许高效地计算文件中滑动窗口的校验和。 - 校验和传输:
rsync客户端将这些块的校验和列表发送给服务器端。 - 差异查找:服务器端拿着这个校验和列表,在自己的目标文件上滑动窗口,计算每个位置的滚动校验和进行快速比对。一旦滚动校验和匹配,再计算强校验和进行二次确认。通过这种方式,它能快速定位到哪些数据块是目标端已经拥有的。
- 增量传输:最后,客户端只需要传输那些目标端缺失的数据块,以及如何重组这些块以构成完整文件的指令。如果文件是全新的,则传输整个文件;如果只有一小部分变动,则只传输变动的部分。
这个过程意味着,同步一个只修改了几行的1GB日志文件,可能只需要传输几KB的数据,而不是整个1GB。这种效率是scp或cp无法比拟的。
2.2 核心工作模式解析
rsync有三种主要的工作模式,对应不同的使用场景:
本地模式:
rsync [OPTION...] SRC... [DEST]类似于增强版的cp命令,在单机内部进行文件同步。虽然听起来简单,但在配合--link-dest做硬链接备份时,它能发挥出惊人的空间效率。通过远程Shell访问模式:
rsync [OPTION...] SRC... [USER@]HOST:DEST这是我们最常用的模式之一。它默认使用SSH作为传输通道,因此继承了SSH的安全性(加密传输)和便利性(免密登录)。你几乎不需要额外配置服务端。守护进程模式:
rsync [OPTION...] SRC... [USER@]HOST::DEST或rsync [OPTION...] rsync://[USER@]HOST[:PORT]/DEST在这种模式下,需要在服务器端运行rsyncd守护进程,并配置/etc/rsyncd.conf文件。它适合需要频繁、自动化同步的场景,可以定义模块、设置访问权限、限制带宽等,功能更强大,但配置也稍复杂。
注意:很多初学者容易混淆后两种模式中的路径分隔符。远程Shell模式使用单个冒号
:,而守护进程模式使用双冒号::或rsync://协议URL。用错了会导致连接失败。
理解这些底层机制和模式,能帮助我们在实际使用时做出正确的选择,并理解命令执行背后的状态,当出现问题时也能更快地定位。
3. 十大实战场景与命令实例详解
下面我们进入实战环节。我将按照从基础到进阶的顺序,通过10个实例来展示rsync的强大功能。每个实例都会解释清楚“为什么这么用”以及“需要注意什么”。
3.1 实例1:最基础的本地与远程同步
这是你迈出的第一步,掌握它就能解决80%的简单同步需求。
场景:将本地的/home/user/project目录同步到远程服务器192.168.1.100的/backup/目录下。
# 本地同步 (类似 cp -r) rsync -av /home/user/project/ /backup/project/ # 远程同步(通过SSH) rsync -av /home/user/project/ user@192.168.1.100:/backup/project/-a(archive):这是最重要的选项之一,它是“归档模式”,相当于-rlptgoD的组合。它保留符号链接、权限、时间戳、属主和组信息,并递归同步目录。对于备份,几乎总是需要它。-v(verbose):输出详细过程,让你知道正在同步什么文件。- 路径末尾的斜杠
/:这是新手最容易踩的坑!rsync -av source/ dest/:同步source目录内部的内容到dest目录下。如果dest不存在会自动创建。rsync -av source dest/:将整个source目录(包括其自身)同步到dest目录下,结果会是dest/source/...。 根据你的意图谨慎使用斜杠。
实操心得:在第一次执行重要同步前,强烈建议加上-n(干跑模式)和-v选项先预览一下。命令rsync -avn source/ dest/会列出所有将要发生的变更,而不会实际执行任何操作,确认无误后再移除-n执行。
3.2 实例2:实现“镜像”同步与文件删除
有时我们需要的不是合并,而是让目标端成为源端的精确副本,即删除目标端存在而源端没有的文件。
场景:将本地Web站点的html目录完全镜像到远程服务器,并删除远程服务器上多余的文件。
rsync -av --delete /var/www/html/ user@server:/var/www/html/--delete:这个选项让rsync删除目标目录中存在而源目录中不存在的文件。使用此选项务必极其小心!一旦源目录为空或路径错误,它可能会清空你的目标目录。永远先使用-n --delete进行预演。
避坑指南:我经历过一次惨痛的教训。在脚本中同步一个动态生成的临时目录路径,因为变量为空,导致命令变成了rsync -av --delete ./ user@server:/important-data/,差点酿成大祸。所以,对于--delete,我的铁律是:三思而后行,预览不可少。
3.3 实例3:排除特定文件与目录
我们很少需要同步目录里的所有东西,比如日志、缓存、版本控制目录等。
场景:同步项目目录,但排除所有的.log日志文件、.tmp临时文件以及.git目录。
rsync -av --exclude='*.log' --exclude='*.tmp' --exclude='.git' /project/ user@server:/backup/project/更复杂的情况,可以使用--exclude-from选项从一个文件中读取排除规则列表。
# 假设有一个 exclude-list.txt 文件,内容如下: # *.log # *.tmp # .git/ # node_modules/ # *.swp rsync -av --exclude-from='exclude-list.txt' /project/ user@server:/backup/project/注意事项:排除模式是相对于源路径进行匹配的。如果你想排除绝对路径,可以使用--exclude='/path/to/file'。另外,rsync的排除规则是有顺序的,先定义的规则优先。
3.4 实例4:带宽限制与传输压缩
在跨公网或带宽受限的环境下同步,我们需要做“好邻居”,避免占满带宽影响其他服务。
场景:在白天业务时段,将备份数据同步到异地机房,但需要将带宽限制在1MB/s以内。
rsync -avz --bwlimit=1024 /data/backup/ user@remote-server:/offsite-backup/--bwlimit=KBPS:将传输带宽限制在每秒多少KB。这里1024代表1024KB/s,即1MB/s。这对于避免网络拥塞至关重要。-z(compress):在传输过程中进行压缩。这对于文本、代码、日志等可压缩率高的文件效果显著,能减少传输数据量,但会稍微增加CPU开销。对于已经是压缩格式的文件(如jpg, zip, avi),效果不大甚至可能变大。
经验之谈:--bwlimit的单位是KB/s,不是网络带宽中常见的Mbps。1MB/s = 1024 KB/s ≈ 8 Mbps。在编写自动化脚本时,根据网络状况和时间段动态调整这个值是个好习惯,比如夜间可以放开限制。
3.5 实例5:增量备份与硬链接魔法(--link-dest)
这是rsync最经典、最省空间的备份方案,常用于实现类似“时光机”的备份效果。
场景:每天凌晨对/home目录进行增量备份,每次备份看起来都是完整的,但未修改的文件不占用额外空间。
#!/bin/bash # 假设备份到 /backup/daily BACKUP_ROOT="/backup/daily" SOURCE="/home" # 今天的备份目录,以日期命名 TODAY=$(date +%Y%m%d) TODAY_BACKUP="$BACKUP_ROOT/$TODAY" # 昨天的备份目录 YESTERDAY=$(date -d "yesterday" +%Y%m%d) YESTERDAY_BACKUP="$BACKUP_ROOT/$YESTERDAY" # 如果存在昨天的备份,则使用--link-dest if [ -d "$YESTERDAY_BACKUP" ]; then rsync -a --link-dest="$YESTERDAY_BACKUP" "$SOURCE/" "$TODAY_BACKUP/" else # 第一次备份,全量 rsync -a "$SOURCE/" "$TODAY_BACKUP/" fi--link-dest=DIR:这是实现“魔法”的关键。rsync会在创建新备份TODAY_BACKUP时,先去参考目录YESTERDAY_BACKUP里查找。如果某个文件在两个备份间没有变化,rsync不会复制数据,而是在新备份中创建一个指向旧备份中同一文件的硬链接。- 硬链接:硬链接是同一个文件数据的多个目录入口。删除其中一个链接不会影响其他链接和数据本身,只有当所有链接都被删除,文件数据才会被释放。
执行后,/backup/daily目录下会有20231001,20231002,20231003...等多个完整的/home目录视图。但物理上,只有每天变化的文件才占用新空间,未变的文件在所有备份中共享同一份数据。
核心优势:
- 节省空间:极端情况下,如果文件一个月都没变,那么30个备份中它只占一份空间。
- 恢复方便:每个备份目录都是独立的、完整的,你可以直接进入
20231001目录找到那天的文件状态,无需复杂的增量还原流程。
3.6 实例6:远程Shell端口与密钥认证
默认rsync使用SSH的22端口,并使用你当前的系统用户。但在生产环境中,SSH端口常常被修改,并且我们会使用密钥对进行免密登录。
场景:远程服务器SSH端口为2222,并使用密钥认证进行同步。
rsync -av -e 'ssh -p 2222 -i /path/to/private_key' /local/data/ user@server:/remote/data/-e(rsh):此选项用于指定远程Shell程序。我们通过它来传递SSH的额外参数。ssh -p 2222 -i /path/to/private_key:这是传递给SSH的命令,指定端口和私钥路径。
为了让操作更简便,通常我们会将SSH配置放在~/.ssh/config文件中:
# ~/.ssh/config Host mybackupserver HostName server.example.com Port 2222 User backupuser IdentityFile ~/.ssh/id_rsa_backup配置好后,同步命令就可以简化为:
rsync -av /local/data/ mybackupserver:/remote/data/安全提示:确保私钥文件权限为600(chmod 600 ~/.ssh/id_rsa),并且考虑使用ssh-agent来管理密钥,避免在脚本中硬编码密钥路径或密码。
3.7 实例7:守护进程模式实战
对于需要高频、自动化、多用户访问的同步任务,守护进程模式是更专业的选择。
服务端配置(/etc/rsyncd.conf):
# /etc/rsyncd.conf uid = nobody gid = nobody use chroot = yes max connections = 10 pid file = /var/run/rsyncd.pid log file = /var/log/rsyncd.log [web_backup] # 模块名 path = /data/backup/web # 服务器上对应的真实路径 comment = Web Directory Backup read only = no # 允许上传 list = yes auth users = backupuser # 认证用户(非系统用户) secrets file = /etc/rsyncd.secrets # 密码文件创建密码文件 (/etc/rsyncd.secrets):
# 格式:username:password backupuser:YourSecurePassword123 # 设置严格权限 chmod 600 /etc/rsyncd.secrets启动rsync守护进程(通常通过systemd或xinetd):
systemctl start rsyncd systemctl enable rsyncd客户端同步命令:
# 拉取(下载)文件 rsync -av rsync://backupuser@server_ip/web_backup/ /local/backup/ # 推送(上传)文件 rsync -av /local/web/ rsync://backupuser@server_ip/web_backup/ # 需要密码,可以设置环境变量 RSYNC_PASSWORD 或使用 --password-file RSYNC_PASSWORD=YourSecurePassword123 rsync -av /local/web/ rsync://backupuser@server_ip/web_backup/模式对比:
| 特性 | 远程Shell模式 (SSH) | 守护进程模式 (Rsyncd) |
|---|---|---|
| 安全性 | 高 (SSH加密) | 中 (可配置SSL隧道,默认明文) |
| 认证 | 系统用户/SSH密钥 | 独立用户/密码文件 |
| 配置复杂度 | 低 (依赖现有SSH) | 中 (需单独配置) |
| 功能 | 基础同步 | 丰富 (模块、带宽限制、IP过滤等) |
| 适用场景 | 临时、个人、需加密的同步 | 定期、自动化、多用户共享的备份 |
3.8 实例8:部分传输与断点续传
同步大文件时,网络中断是噩梦。rsync的--partial和--progress选项可以缓解这个问题。
场景:同步一个巨大的虚拟机镜像文件,并希望中断后能续传。
rsync -avP /path/to/large.vmdk user@server:/backup/-P:这是两个常用选项的组合:--progress:显示每个文件的传输进度条,让你对进度心中有数。--partial:保留部分传输的文件。默认情况下,如果传输中断,rsync会删除未完成的目标文件。使用--partial则会保留它,下次同步时可以从中断处继续。
--append:与--partial类似,但更智能。它会检查已传输的部分数据是否正确,然后从文件末尾追加数据。对于只增不减的日志类文件特别有用。
注意事项:--partial保留的文件会以隐藏文件形式存在(如.large.vmdk.XXXXXX),直到传输完成才重命名为正式文件。确保目标磁盘有足够空间存放这些临时文件。
3.9 实例9:实时同步的桥梁——与inotify/tail结合
rsync本身不是实时的,它需要被触发。结合Linux内核的inotify机制,可以实现近实时的文件同步。
一个简单的方案是使用inotifywait命令(属于inotify-tools包)监控目录变化,然后触发rsync。
#!/bin/bash # 简单示例:监控本地目录,有变化则同步到远程 SRC="/data/to/watch/" DEST="user@server:/backup/watch/" inotifywait -mrq --timefmt '%d/%m/%y %H:%M' --format '%T %w %f %e' \ -e modify,create,delete,attrib,move "$SRC" | while read date time dir file event do # 触发rsync同步 rsync -av --delete "$SRC" "$DEST" # 记录日志 echo "$date $time: 事件 $event 发生于 $dir$file, 已触发同步。" >> /var/log/rsync_watch.log done更优的工具:对于生产环境,更推荐使用专门封装好的工具,如lsyncd。它底层使用inotify或fsevents,并内置了rsync作为同步动作,配置更简单,可靠性更高,还能防抖动(避免短时间内大量变化触发多次同步)。
3.10 实例10:高级过滤与权限映射
在复杂的跨系统同步中,你可能会遇到UID/GID不一致,或者需要更精细地控制同步内容。
场景1:保持权限,但忽略某些特殊权限位
rsync -av --no-perms --no-owner --no-group source/ dest/--no-perms:不同步权限。--no-owner:不同步属主信息。--no-group:不同步属组信息。 这在向不具备相同用户的环境同步时很有用。
场景2:包含/排除过滤规则的复杂应用rsync的过滤规则比简单的--exclude更强大,它支持“包含”和“排除”的组合,规则按顺序应用。
# 只同步 .php 和 .html 文件,但排除 tmp 目录下的所有文件 rsync -av --include='*.php' --include='*.html' --include='*/' --exclude='*' --exclude='tmp/*' source/ dest/这个命令的逻辑是:
- 包含所有
.php文件。 - 包含所有
.html文件。 - 包含所有目录(
*/),这是为了能让rsync进入子目录去匹配.php和.html文件。 - 排除所有其他文件(
*)。 - 排除
tmp/目录下的所有内容(覆盖前面的包含规则)。
场景3:使用--files-from从列表同步如果你有一个精确的需要同步的文件列表,可以使用这个选项。
# filelist.txt 包含需要同步的文件路径,每行一个,路径相对于源目录 rsync -av --files-from=filelist.txt /source/ /dest/4. 性能调优与高级参数解析
当同步的数据量达到TB级别,或者文件数量极多(如百万个小文件)时,默认参数可能不够用,需要进行调优。
4.1 应对海量小文件同步
同步数百万个小文件(比如代码仓库、日志碎片)的主要瓶颈在于rsync需要在两端进行大量的文件统计和对比。
-W或--whole-file:关闭增量检查,直接传输整个文件。在高速局域网内,这通常比增量计算更快,因为它跳过了昂贵的校验和计算与对比阶段。rsync -avW source/ dest/调整块大小 (
-B, --block-size):rsync的快速检查算法使用块大小。对于平均文件大小很小的场景,适当增大块大小可以减少需要计算和传输的校验和数量。但设置过大可能会降低增量检测的精度。这是一个需要根据实际情况测试的参数。rsync -av -B 16384 source/ dest/ # 设置块大小为16KB使用
--inplace的权衡:默认rsync会先传输到一个临时文件,完成后替换原文件,保证数据一致性。--inplace选项会直接写入目标文件,节省磁盘IO和空间,但如果在传输中断,目标文件将处于损坏状态。仅在对一致性要求不高、且需要极致速度的场景下谨慎使用。
4.2 网络与IO优化
--compress-level=LEVEL:-z选项默认的压缩级别是6。你可以降低级别(如3)以减少CPU消耗,或者提高级别(如9)以在带宽极其紧张时获得更好的压缩率,但会显著增加CPU负担。rsync -avz --compress-level=3 source/ dest/ # 快速压缩--max-size和--min-size:限制传输文件的大小范围。例如,不同步超过100MB的大文件,或者只同步大于1KB的文件。rsync -av --max-size=100M source/ dest/ rsync -av --min-size=1K source/ dest/--temp-dir:指定临时文件目录。如果目标文件系统空间不足,但另一个挂载点有空间,可以使用此选项。rsync -av --temp-dir=/bigdisk/tmp source/ /smalldisk/dest/
5. 生产环境常见问题与排查实录
即使命令正确,在实际操作中也会遇到各种问题。这里记录几个我踩过的坑和解决方法。
5.1 问题:权限被拒绝 (Permission Denied)
这是最常见的问题。
SSH模式:
- 检查目标目录权限:确保远程用户对目标目录有写权限 (
ls -ld /path/to/dest)。 - 检查SSH密钥:确认密钥认证已正确设置,且私钥权限为
600。 - 使用
sudo:如果需要在远程执行sudo,rsync本身不能直接传递sudo密码。一种方法是让rsync以root用户SSH登录(不安全),更好的方法是在远程通过sudo设置目标目录的权限,让普通用户可写。
- 检查目标目录权限:确保远程用户对目标目录有写权限 (
守护进程模式:
- 检查
rsyncd.conf中的uid/gid:确保守护进程运行的用户有权限访问path指定的目录。 - 检查密码文件:确保
secrets file路径和权限正确(600),且用户名密码匹配。 - 检查防火墙:确保服务器端的
873端口(或自定义端口)已开放。
- 检查
5.2 问题:同步缓慢,CPU或IO占用高
- 原因1:海量小文件。解决方案见上一节“性能调优”。
- 原因2:
-z压缩不必要的文件。对已压缩文件(jpg, zip, avi等)启用压缩,会浪费CPU。可以使用--skip-compress指定哪些后缀的文件不压缩。rsync -avz --skip-compress=gz/zip/z/rpm/deb/iso/bz2/tgz/tbz2/7z/mp[34]/mov/avi/ogg/jpg/jpeg/png/gif source/ dest/ - 原因3:源或目标磁盘IO瓶颈。使用
iostat、iotop命令监控磁盘状况。考虑在业务低峰期执行同步。
5.3 问题:--delete误删文件后的恢复
这是最可怕的情况。预防永远大于治疗。
- 立即停止所有写入操作:防止数据被覆盖。
- 检查是否有备份:这是最直接的恢复方式。
- 检查是否使用了
--link-dest:如果使用了硬链接备份,文件数据可能在其他备份目录中还存在,只是链接数减少了。你可以从之前的备份目录中找回文件。 - 文件系统恢复工具:如
extundelete(用于ext3/ext4),但这需要专业操作,且不能保证100%成功,成功率取决于文件被删除后磁盘的写入情况。
最重要的教训:在执行任何带有--delete的命令前,必须使用-n(干跑模式)进行预览。将预览结果重定向到文件并仔细审查。
5.4 问题:字符编码与特殊文件名
同步包含中文、空格或特殊字符(如*,?,[,])的文件名时可能出错。
- 使用
--iconv转换编码(如果两端系统编码不同,如GBK和UTF-8):rsync -av --iconv=UTF-8,GBK source/ dest/ # 假设源是UTF-8,目标是GBK - 正确处理特殊字符:确保你的Shell正确转义了参数,或者在脚本中使用引号包裹变量。
rsync本身会处理传输过程中的特殊字符。
5.5 一个实用的调试技巧
当你遇到奇怪的问题,不确定rsync到底在做什么时,使用-vvv(三个v)选项可以输出最详细的调试信息。
rsync -avvv --dry-run source/ dest/ 2>&1 | tee debug.log查看debug.log,你可以看到rsync是如何比较文件、计算校验和、做出传输决策的每一个步骤,这对于排查复杂问题非常有帮助。
6. 编写健壮的Rsync自动化脚本
最后,分享一个我在生产环境中使用的、相对健壮的增量备份脚本框架。它包含了错误处理、日志记录、锁机制和邮件通知。
#!/bin/bash # 文件名:robust_rsync_backup.sh # 描述:带错误处理和通知的Rsync增量备份脚本 set -euo pipefail # 启用严格错误处理 # ========== 配置区 ========== SOURCE_DIR="/data/app" BACKUP_ROOT="/backup/app_daily" REMOTE_USER="backup" REMOTE_HOST="backup.server.com" REMOTE_PORT="22" REMOTE_DIR="/mnt/backup/app" LOG_FILE="/var/log/rsync_backup.log" LOCK_FILE="/tmp/rsync_backup.lock" EMAIL_ADMIN="admin@example.com" # ============================ # 函数:记录日志 log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" } # 函数:发送邮件通知 send_alert() { local subject="[ALERT] Rsync Backup Failed - $(hostname)" local body="Error occurred at $(date). Check log file: $LOG_FILE for details. Error: $1" # 这里可以使用 mail, sendmail, 或调用其他邮件API echo "$body" | mail -s "$subject" "$EMAIL_ADMIN" 2>/dev/null || log "Failed to send email." } # 1. 检查锁文件,防止重复运行 if [ -f "$LOCK_FILE" ]; then log "Another backup process is running or previous one failed uncleanly. Exiting." send_alert "Backup lock file exists." exit 1 fi trap 'rm -f $LOCK_FILE; log "Lock released."' EXIT INT TERM touch "$LOCK_FILE" log "Backup started." # 2. 定义备份目录(按日期) TODAY=$(date +%Y%m%d) YESTERDAY=$(date -d "yesterday" +%Y%m%d 2>/dev/null || echo "") LOCAL_BACKUP_TODAY="$BACKUP_ROOT/$TODAY" REMOTE_BACKUP_TODAY="$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/$TODAY" REMOTE_BACKUP_YESTERDAY="$REMOTE_DIR/$YESTERDAY" # 3. 执行远程Rsync备份(使用硬链接增量) RSYNC_CMD="rsync -a --stats --delete --link-dest=\"$REMOTE_BACKUP_YESTERDAY\" \ -e \"ssh -p $REMOTE_PORT -o ConnectTimeout=30 -o BatchMode=yes\" \ \"$SOURCE_DIR/\" \"$REMOTE_BACKUP_TODAY/\"" log "Executing: $RSYNC_CMD" # 执行命令并捕获输出和错误 if output=$(eval "$RSYNC_CMD" 2>&1); then log "Backup completed successfully." log "Rsync output summary:\n$output" else error_msg="Rsync command failed with exit code $?. Output: $output" log "ERROR: $error_msg" send_alert "$error_msg" exit 1 fi # 4. (可选)本地也保留一份快照(使用硬链接) if [ -d "$BACKUP_ROOT/$YESTERDAY" ]; then cp -al "$BACKUP_ROOT/$YESTERDAY" "$LOCAL_BACKUP_TODAY" 2>/dev/null && \ rsync -a --delete "$SOURCE_DIR/" "$LOCAL_BACKUP_TODAY/" && \ log "Local snapshot updated." else mkdir -p "$LOCAL_BACKUP_TODAY" rsync -a "$SOURCE_DIR/" "$LOCAL_BACKUP_TODAY/" && \ log "First local backup created." fi log "Backup finished successfully." # 脚本结束,trap会清理锁文件这个脚本包含了几个关键点:
set -euo pipefail:让脚本在遇到任何错误时立即退出,避免错误累积。- 锁机制:防止脚本被意外重复执行,导致数据混乱。
- 详细的日志:所有操作都记录到日志文件,便于事后审计和排查。
- 错误处理与通知:如果
rsync失败,会记录错误并发送邮件告警。 - 使用
--stats:在日志中输出传输统计信息(文件数、数据量等),便于监控。 - SSH超时设置:
-o ConnectTimeout=30避免网络问题导致脚本长时间挂起。
你可以根据实际环境调整这个脚本,比如添加备份保留策略(删除N天前的备份)、更复杂的健康检查等。将它放入cron中,就可以实现无人值守的自动化增量备份了。