搞运维这些年,rsync用得比cp多得多。
增量同步、断点续传、压缩传输,这些特性让它在文件传输场景下几乎无可替代。
为什么用rsync
先看个场景:要把100G的日志目录从A服务器同步到B服务器。
用scp:
bash
scp -r /data/logs/ user@B:/data/logs/
# 每次都是全量传输
# 中断了要从头来
# 100G传几个小时
用rsync:
bash
rsync -avz /data/logs/ user@B:/data/logs/
# 只传有变化的文件
# 中断了从断点继续
# 传输时压缩,省带宽
第一次可能都是100G,但后续同步可能只要传几百M变化的文件。这就是增量同步的威力。
基础用法
本地同步
bash
# 基本格式
rsync [选项] 源目录 目标目录
# 同步目录
rsync -av /data/source/ /data/dest/
# 注意:源目录末尾的斜杠很重要!
rsync -av /data/source/ /data/dest/ # 同步source下的内容到dest
rsync -av /data/source /data/dest/ # 同步整个source目录到dest下
斜杠的区别:
bash
# 有斜杠:同步目录内容
rsync -av /data/logs/ /backup/logs/
# 结果:/backup/logs/下直接是文件
# 没斜杠:同步整个目录
rsync -av /data/logs /backup/
# 结果:/backup/logs/logs/下才是文件(多了一层)
这个坑我见无数人踩过,记住:通常用有斜杠的写法。
远程同步
bash
# 推送:本地到远程
rsync -avz /data/logs/ user@remote:/data/logs/
# 拉取:远程到本地
rsync -avz user@remote:/data/logs/ /data/logs/
# 指定端口
rsync -avz -e "ssh -p 2222" /data/ user@remote:/data/
常用选项
bash
-a, --archive # 归档模式,等于 -rlptgoD,保持权限、时间等
-v, --verbose # 详细输出
-z, --compress # 传输时压缩
-P # 等于 --progress --partial,显示进度+支持断点续传
-n, --dry-run # 模拟运行,不实际执行
--delete # 删除目标中源没有的文件
--exclude # 排除文件
--include # 包含文件
--bwlimit # 限制带宽
推荐组合
bash
# 日常同步
rsync -avzP /source/ /dest/
# 镜像同步(目标完全等于源)
rsync -avz --delete /source/ /dest/
# 首次大量传输(显示进度,支持断点)
rsync -avzP --progress /source/ user@remote:/dest/
排除和包含
排除文件
bash
# 排除单个目录
rsync -avz --exclude='logs' /data/ /backup/
# 排除多个
rsync -avz --exclude='logs' --exclude='tmp' --exclude='*.log' /data/ /backup/
# 用排除文件
rsync -avz --exclude-from='exclude.txt' /data/ /backup/
# exclude.txt 内容:
logs/
tmp/
*.log
*.tmp
.git/
node_modules/
包含和排除组合
bash
# 只同步特定类型文件
rsync -avz --include='*.conf' --exclude='*' /data/ /backup/
# 同步目录结构+特定文件
rsync -avz --include='*/' --include='*.log' --exclude='*' /data/ /backup/
规则是按顺序匹配的,第一个匹配的规则生效。
删除选项
bash
# --delete: 删除目标中多余的文件
rsync -avz --delete /source/ /dest/
# 如果源中删了文件,目标也会被删
# --delete-before: 先删除再传输(默认)
# --delete-during: 边传边删
# --delete-after: 传完再删
# 小心使用!建议先 --dry-run 看看会删什么
rsync -avzn --delete /source/ /dest/
实战场景
1. 定时备份
bash
#!/bin/bash
# backup.sh
DATE=$(date +%Y%m%d)
SRC="/data/app/"
DEST="/backup/app/"
LOG="/var/log/backup.log"
echo "=== Backup started at $(date) ===" >> $LOG
rsync -avz --delete \
--exclude='logs/' \
--exclude='tmp/' \
--exclude='*.pid' \
"$SRC" "$DEST" >> $LOG 2>&1
if [ $? -eq 0 ]; then
echo "Backup completed successfully" >> $LOG
else
echo "Backup failed!" >> $LOG
# 发告警
fi
echo "=== Backup finished at $(date) ===" >> $LOG
加入crontab:
bash
# 每天凌晨2点备份
0 2 * * * /opt/scripts/backup.sh
2. 跨服务器迁移
bash
# 大量数据迁移,限速避免影响业务
rsync -avzP --bwlimit=50000 /data/ user@newserver:/data/
# --bwlimit=50000 表示限速50MB/s
# 迁移完验证
rsync -avzn /data/ user@newserver:/data/
# 如果输出为空,说明完全一致
3. 增量备份到多版本
bash
#!/bin/bash
# 保留7天备份
DATE=$(date +%Y%m%d)
SRC="/data/app/"
DEST_BASE="/backup/app"
LATEST="$DEST_BASE/latest"
BACKUP="$DEST_BASE/$DATE"
# 硬链接方式增量备份
rsync -avz --delete --link-dest="$LATEST" "$SRC" "$BACKUP"
# 更新latest链接
rm -f "$LATEST"
ln -s "$BACKUP" "$LATEST"
# 删除7天前的备份
find "$DEST_BASE" -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;
--link-dest 是个神器:如果文件没变化,直接硬链接到上一版本,不占空间。这样保留7天备份,实际占用空间只比一份稍多一点。
4. 双向同步(慎用)
bash
# 先A到B
rsync -avz --update /data/shared/ user@B:/data/shared/
# 再B到A
rsync -avz --update user@B:/data/shared/ /data/shared/
# --update 只同步更新的文件,避免覆盖
双向同步容易出问题,生产环境建议用专门的同步工具(如Syncthing)或者确定好主从关系。
5. 断点续传大文件
bash
# 传输大文件,中途断了可以继续
rsync -avzP --partial largefile.tar.gz user@remote:/data/
# --partial 保留传了一半的文件,不删除
# -P 等于 --partial --progress
rsync daemon模式
除了SSH,rsync还可以以守护进程方式运行,适合内网大量机器同步。
服务端配置
bash
# /etc/rsyncd.conf
uid = nobody
gid = nobody
use chroot = no
max connections = 10
log file = /var/log/rsyncd.log
pid file = /var/run/rsyncd.pid
[data]
path = /data
comment = Data directory
read only = no
list = yes
auth users = syncuser
secrets file = /etc/rsyncd.secrets
[backup]
path = /backup
comment = Backup directory
read only = yes
bash
# /etc/rsyncd.secrets
syncuser:yourpassword
bash
# 权限要设对
chmod 600 /etc/rsyncd.secrets
# 启动
rsync --daemon
# 或者用systemd
systemctl start rsyncd
客户端连接
bash
# 格式:rsync://user@host/模块名/路径
rsync -avz syncuser@192.168.1.100::data/ /local/data/
# 或者
rsync -avz rsync://syncuser@192.168.1.100/data/ /local/data/
# 密码可以写文件或环境变量
export RSYNC_PASSWORD="yourpassword"
rsync -avz syncuser@192.168.1.100::data/ /local/data/
daemon模式的好处是不走SSH,配置灵活,适合内网批量同步场景。
性能优化
压缩策略
bash
# 已压缩的文件不要再压缩
rsync -avz --compress-level=9 /data/ /backup/ # 压缩级别0-9
# 跳过已压缩格式
rsync -avz --skip-compress=gz/jpg/mp4/zip/rar /data/ /backup/
大量小文件
bash
# 大量小文件时,可以先打包
tar czf - /data/logs/ | ssh user@remote "tar xzf - -C /backup/"
# 或者用rsync的 --whole-file 选项
rsync -avz --whole-file /data/ /backup/
# 小文件用whole-file直接传比增量计算快
限制资源
bash
# 限制带宽(KB/s)
rsync -avz --bwlimit=10000 /data/ user@remote:/data/
# 限制IO优先级
ionice -c2 -n7 rsync -avz /data/ /backup/
常见问题
1. 权限问题
bash
# 保持原权限
rsync -avz /data/ /backup/
# 不保持权限(用目标系统默认)
rsync -rltz /data/ /backup/
# 改变属主
rsync -avz --chown=www:www /data/ /backup/
2. 符号链接
bash
# 默认 -a 会复制软链接本身
rsync -avz /data/ /backup/
# 复制软链接指向的文件
rsync -avzL /data/ /backup/
# 跳过软链接
rsync -avz --no-links /data/ /backup/
3. 校验数据完整性
bash
# 用校验和对比,更准确但更慢
rsync -avzc /data/ /backup/
# -c 使用checksum而不是时间+大小
# 验证同步结果
rsync -avzn --checksum /data/ user@remote:/data/
4. 空目录
bash
# rsync默认不创建空目录(没文件可同步)
# 加 -d 选项
rsync -avzd --include='*/' --exclude='*' /data/ /backup/
与其他工具对比
| 场景 | 推荐工具 |
|---|---|
| 单次传文件 | scp |
| 增量同步 | rsync |
| 实时同步 | lsyncd (rsync+inotify) |