Rsync同步操作看这篇就够了

# Rsync同步操作看这篇就够了 数据同步和备份是我们日常工作中绕不开的话题。无论是服务器之间的文件同步、定期备份,还是代码部署,都离不开一个神器级的工具——rsync。 说起rsync,可能很多新手朋友会觉得它很复杂,参数一大堆,看着就头疼。但实际上,掌握了rsync的核心原理和常用操作后,你会发现它简直是运维工作的得力助手。 什么是Rsync? Rsync(Remote Sync)是一个开源的快速备份工具,可以在不同主机之间镜像整个目录树。它的最大特点就是使用"rsync算法"进行增量传输,只传输文件的差异部分,大大提高了传输效率。 简单来说,rsync就像是一个聪明的搬运工,它不会傻乎乎地把所有文件都重新搬一遍,而是会比较源文件和目标文件的差异,只搬运有变化的部分。这样既节省了时间,又减少了网络带宽的消耗。 Rsync的核心优势 增量传输:只传输变化的部分,效率极高 保持文件属性:可以保持文件的权限、时间戳、软硬链接等 压缩传输:支持传输过程中的数据压缩 断点续传:网络中断后可以从断点继续传输 跨平台:支持Linux、Unix、Windows等多种操作系统 Rsync的工作模式 Rsync有三种主要的工作模式,理解这些模式对于正确使用rsync至关重要。 1. 本地模式 这种模式就是在同一台机器上进行文件同步,类似于cp命令,但功能更强大。 基本语法 rsync [选项] 源路径 目标路径 ​ 示例:同步本地目录 rsync -av /home/user/documents/ /backup/documents/ 2. 远程Shell模式 通过SSH等远程shell协议进行同步,这是最常用的模式。 推送到远程主机 rsync -av /local/path/ user@remote-host:/remote/path/ ​ 从远程主机拉取 rsync -av user@remote-host:/remote/path/ /local/path/ 3. 守护进程模式 rsync以守护进程方式运行,提供rsync服务。 连接rsync守护进程 rsync -av /local/path/ rsync://user@remote-host/module-name/ Rsync常用参数详解 rsync的参数很多,但常用的就那么几个,掌握这些就够日常使用了。 基础参数 -a (archive):归档模式,相当于-rlptgoD的组合 -v (verbose):详细输出 -r (recursive):递归处理子目录 -l (links):保持软链接 -p (perms):保持权限 -t (times):保持时间戳 -g (group):保持组信息 -o (owner):保持所有者信息 -D:保持设备文件和特殊文件 实用参数 -z (compress):传输时压缩数据 -P:等同于partial progress,显示进度并支持断点续传 delete:删除目标目录中源目录没有的文件 exclude:排除指定文件或目录 include:包含指定文件或目录 -n (dry-run):试运行,不实际执行操作 bwlimit:限制传输带宽 安全相关参数 -e:指定远程shell程序 rsync-path:指定远程rsync程序的路径 实战案例分析 理论说得再多,不如实际操作来得直接。我们通过几个真实的运维场景来看下rsync的具体应用。 案例1:网站文件同步 我们需要将本地开发的网站文件同步到生产服务器。(这招也可以用在云计算磁盘需要缩容的过程中,毕竟云硬盘,多开1G都是要花钱的,利用率最大化才是省钱王道) 基本同步命令 rsync -avz delete /var/www/html/ root@192.168.1.100:/var/www/html/ ​ 排除不需要同步的文件 rsync -avz delete \ exclude='*.log' \ exclude='cache/' \ exclude='.git/' \ /var/www/html/ root@192.168.1.100:/var/www/html/ 这个命令会: 递归同步整个网站目录 保持文件属性和时间戳 压缩传输数据 删除目标目录中多余的文件 排除日志文件、缓存目录和Git仓库 案例2:数据库备份同步 对于数据库备份文件的异地同步,我们通常需要更谨慎的处理。 #!/bin/bash 数据库备份同步脚本 ​ BACKUP_DIR="/backup/mysql" REMOTE_HOST="backup-server.company.com" REMOTE_DIR="/data/mysql-backup" LOG_FILE="/var/log/backup-sync.log" ​ 执行同步 rsync -avz progress \ log-file=$LOG_FILE \ timeout=300 \ bwlimit=10000 \ $BACKUP_DIR/ root@$REMOTE_HOST:$REMOTE_DIR/ ​ 检查同步结果 if [ $? -eq 0 ]; then echo "$(date): 备份同步成功" >> $LOG_FILE else echo "$(date): 备份同步失败" >> $LOG_FILE 发送告警邮件 echo "备份同步失败,请检查" | mail -s "备份告警" admin@company.com fi 案例3:配置文件分发 在集群环境中,经常需要将配置文件分发到多台服务器。 #!/bin/bash 配置文件分发脚本 ​ CONFIG_DIR="/etc/app-config" SERVERS=("web01" "web02" "web03" "web04") ​ for server in "${SERVERS[@]}"; do echo "正在同步配置到 $server..." rsync -avz dry-run \ exclude='*.bak' \ $CONFIG_DIR/ root@$server:$CONFIG_DIR/ 确认无误后执行实际同步 read -p "确认同步到 $server 吗?(y/n): " confirm if [ "$confirm" = "y" ]; then rsync -avz \ exclude='*.bak' \ $CONFIG_DIR/ root@$server:$CONFIG_DIR/ echo "$server 同步完成" fi done 高级技巧和最佳实践 1. 使用过滤规则文件 当排除规则很复杂时,可以使用过滤规则文件。 创建过滤规则文件 exclude-list.txt cat > exclude-list.txt << EOF *.log *.tmp cache/ .git/ node_modules/ *.pyc __pycache__/ EOF ​ 使用过滤规则文件 rsync -avz exclude-from=exclude-list.txt /source/ /destination/ 2. 限速传输 在生产环境中,为了不影响正常业务,通常需要限制rsync的传输速度。 限制传输速度为1MB/s rsync -avz bwlimit=1000 /source/ user@remote:/destination/ ​ 在脚本中动态调整限速 if [ $(date +%H) -ge 9 ] && [ $(date +%H) -le 18 ]; then 工作时间限速更严格 BWLIMIT="500" else 非工作时间可以跑满带宽 BWLIMIT="0" fi ​ rsync -avz bwlimit=$BWLIMIT /source/ user@remote:/destination/ 3. 使用SSH密钥认证 为了安全和自动化,建议使用SSH密钥认证而不是密码认证。 生成SSH密钥对 ssh-keygen -t rsa -b 2048 -f ~/.ssh/rsync_key 将公钥复制到目标服务器 ssh-copy-id -i ~/.ssh/rsync_key.pub user@remote-host 在rsync中指定密钥文件 rsync -avz -e "ssh -i ~/.ssh/rsync_key" /source/ user@remote:/destination/ 4. 监控同步状态 编写监控脚本来跟踪rsync的执行状态。 #!/bin/bash rsync监控脚本 SYNC_LOG="/var/log/rsync-monitor.log" LOCK_FILE="/var/run/rsync-sync.lock" 检查是否已有rsync进程在运行 if [ -f "$LOCK_FILE" ]; then echo "$(date): rsync进程已在运行" >> $SYNC_LOG exit 1 fi 创建锁文件 echo $$ > $LOCK_FILE 执行同步并记录时间 START_TIME=$(date +%s) echo "$(date): 开始同步" >> $SYNC_LOG rsync -avz stats /source/ user@remote:/destination/ 2>&1 | tee -a $SYNC_LOG END_TIME=$(date +%s) DURATION=$((END_TIME - START_TIME)) echo "$(date): 同步完成,耗时 ${DURATION} 秒" >> $SYNC_LOG 清理锁文件 rm -f $LOCK_FILE 5.配合inotify实现实时同步 说到实时同步,我想起之前在一个项目中遇到的需求,客户要求文件一有变化就立即同步到备份服务器,不能等定时任务。这时候单纯用rsync就不够了,需要配合inotify来监控文件变化。 inotify是Linux内核提供的文件系统事件监控机制,可以监控文件的创建、修改、删除等操作。配合rsync使用,就能实现准实时的文件同步。 最简单的方法是使用inotify-tools这个工具包,先安装一下: CentOS/RHEL yum install inotify-tools Ubuntu/Debian apt-get install inotify-tools 然后写个简单的监控脚本: #!/bin/bash SRC_DIR="/var/www/html" DEST="user@remote_host:/var/www/html/" inotifywait -mr timefmt '%Y-%m-%d %H:%M:%S' format '%T %w %f %e' \ -e modify,create,delete,move $SRC_DIR | while read TIME DIR FILE EVENT do echo "$TIME: $DIR$FILE was $EVENT" rsync -av delete $SRC_DIR/ $DEST done 不过这个脚本有个问题,就是每次有文件变化都会触发一次完整的rsync,如果文件变化很频繁,会造成很大的系统负担。 我后来改进了一下,加了个延迟机制,在一定时间内的多次变化只触发一次同步: #!/bin/bash SRC_DIR="/var/www/html" DEST="user@remote_host:/var/www/html/" DELAY=5 SYNC_LOCK="/tmp/rsync.lock" inotifywait -mr format '%w %f %e' -e modify,create,delete,move $SRC_DIR | while read DIR FILE EVENT do echo "检测到文件变化: $DIR$FILE ($EVENT)" 如果已经有同步任务在等待,就跳过 if [ -f $SYNC_LOCK ]; then continue fi 创建锁文件 touch $SYNC_LOCK 延迟执行同步 ( sleep $DELAY echo "开始同步..." rsync -av delete $SRC_DIR/ $DEST rm -f $SYNC_LOCK echo "同步完成" ) & done 这样就避免了频繁同步的问题,实际使用效果还不错。不过要注意,inotify监控的文件数量是有限制的,可以通过调整内核参数来增加: echo 8192 > /proc/sys/fs/inotify/max_user_watches 常见问题和解决方案 1. 权限问题 问题:同步后文件权限不正确或无法访问某些文件。 解决方案: 确保源文件有读权限 chmod -R +r /source/ 使用sudo执行rsync sudo rsync -avz /source/ user@remote:/destination/ 或者在远程端使用sudo rsync -avz rsync-path="sudo rsync" /source/ user@remote:/destination/ 2. 网络中断导致传输失败 问题:在传输大文件时网络不稳定导致中断。 解决方案: 使用-P参数支持断点续传和显示进度 rsync -avzP /source/ user@remote:/destination/ 设置超时和重试 rsync -avz timeout=60 contimeout=60 /source/ user@remote:/destination/ 编写重试脚本 #!/bin/bash MAX_RETRIES=3 RETRY_COUNT=0 while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do rsync -avzP /source/ user@remote:/destination/ if [ $? -eq 0 ]; then echo "同步成功" break else RETRY_COUNT=$((RETRY_COUNT + 1)) echo "第 $RETRY_COUNT 次重试..." sleep 30 fi done 3. 磁盘空间不足 问题:目标磁盘空间不够导致同步失败。 解决方案: 先进行试运行检查空间需求 rsync -avzn /source/ /destination/ | grep "total size" 使用max-size限制单个文件大小 rsync -avz max-size=100M /source/ /destination/ 分批同步,先同步小文件 rsync -avz max-size=10M /source/ /destination/ rsync -avz min-size=10M max-size=100M /source/ /destination/ 4. 软链接处理问题 问题:软链接没有正确处理或指向错误位置。 解决方案: 保持软链接(默认行为) rsync -avz /source/ /destination/ 复制软链接指向的实际文件内容 rsync -avzL /source/ /destination/ 转换绝对路径软链接为相对路径 rsync -avz copy-unsafe-links /source/ /destination/ 性能优化技巧 1. 并发同步 对于多个独立的同步任务,可以使用并发处理来提高效率。 #!/bin/bash 并发同步脚本 sync_task() { local src=$1 local dst=$2 local name=$3 echo "开始同步 $name..." rsync -avz "$src/" "$dst/" > "/tmp/sync_${name}.log" 2>&1 if [ $? -eq 0 ]; then echo "$name 同步成功" else echo "$name 同步失败,查看日志: /tmp/sync_${name}.log" fi } 后台并发执行多个同步任务 sync_task "/data/web1" "user@server1:/backup/web1" "web1" & sync_task "/data/web2" "user@server2:/backup/web2" "web2" & sync_task "/data/db" "user@server3:/backup/db" "database" & 等待所有后台任务完成 wait echo "所有同步任务完成" 2. 优化SSH连接 通过SSH连接复用来减少连接建立的开销。 在 ~/.ssh/config 中配置连接复用 cat >> ~/.ssh/config << EOF Host backup-server HostName 192.168.1.100 User root Port 22 ControlMaster auto ControlPath ~/.ssh/master-%r@%h:%p ControlPersist 10m Compression yes EOF 这样多次rsync操作会复用同一个SSH连接 rsync -avz /data1/ backup-server:/backup/data1/ rsync -avz /data2/ backup-server:/backup/data2/ 3. 调整传输参数 根据网络环境调整rsync的传输参数。 高带宽低延迟网络 rsync -avz compress-level=1 /source/ user@remote:/destination/ 低带宽高延迟网络 rsync -avz compress-level=9 whole-file /source/ user@remote:/destination/ 局域网内可以关闭压缩 rsync -av no-compress /source/ user@remote:/destination/ 自动化部署实践 定时备份脚本 #!/bin/bash 完整的定时备份脚本 /usr/local/bin/auto-backup.sh 配置参数 SOURCE_DIRS=("/var/www" "/etc" "/home") BACKUP_SERVER="backup.company.com" BACKUP_BASE="/backup/$(hostname)" LOG_DIR="/var/log/backup" RETENTION_DAYS=7 创建日志目录 mkdir -p $LOG_DIR 获取当前时间 DATE=$(date +%Y%m%d_%H%M%S) LOG_FILE="$LOG_DIR/backup_$DATE.log" 记录开始时间 echo "=== 备份开始: $(date) ===" > $LOG_FILE 检查网络连通性 if ! ping -c 3 $BACKUP_SERVER > /dev/null 2>&1; then echo "错误: 无法连接到备份服务器 $BACKUP_SERVER" >> $LOG_FILE exit 1 fi 备份每个目录 for dir in "${SOURCE_DIRS[@]}"; do if [ -d "$dir" ]; then echo "正在备份 $dir..." >> $LOG_FILE 创建远程目录 ssh root@$BACKUP_SERVER "mkdir -p $BACKUP_BASE$(dirname $dir)" 执行同步 rsync -avz delete \ exclude='*.tmp' \ exclude='*.log' \ exclude='cache/' \ timeout=3600 \ log-file=$LOG_FILE \ $dir/ root@$BACKUP_SERVER:$BACKUP_BASE$dir/ if [ $? -eq 0 ]; then echo "$dir 备份成功" >> $LOG_FILE else echo "$dir 备份失败" >> $LOG_FILE 发送告警 echo "目录 $dir 备份失败" | mail -s "备份失败告警" admin@company.com fi else echo "警告: 目录 $dir 不存在" >> $LOG_FILE fi done 清理旧日志 find $LOG_DIR -name "backup_*.log" -mtime +$RETENTION_DAYS -delete echo "=== 备份结束: $(date) ===" >> $LOG_FILE 设置定时任务 crontab -e 0 2 * * * /usr/local/bin/auto-backup.sh 代码部署脚本 #!/bin/bash 代码部署脚本 PROJECT_NAME="myapp" LOCAL_PATH="/var/jenkins/workspace/$PROJECT_NAME" SERVERS=("web01.company.com" "web02.company.com") REMOTE_PATH="/var/www/$PROJECT_NAME" BACKUP_PATH="/var/www/backup/$PROJECT_NAME" echo "开始部署 $PROJECT_NAME..." 检查本地代码是否存在 if [ ! -d "$LOCAL_PATH" ]; then echo "错误: 本地代码路径不存在" exit 1 fi 部署到每台服务器 for server in "${SERVERS[@]}"; do echo "正在部署到 $server..." 创建备份 ssh root@$server " mkdir -p $BACKUP_PATH if [ -d $REMOTE_PATH ]; then cp -r $REMOTE_PATH $BACKUP_PATH/$(date +%Y%m%d_%H%M%S) fi " 同步代码 rsync -avz delete \ exclude='.git/' \ exclude='node_modules/' \ exclude='*.log' \ $LOCAL_PATH/ root@$server:$REMOTE_PATH/ if [ $? -eq 0 ]; then echo "$server 部署成功" 重启服务 ssh root@$server "systemctl restart $PROJECT_NAME" 健康检查 sleep 5 if curl -f http://$server/health > /dev/null 2>&1; then echo "$server 服务启动正常" else echo "$server 服务启动异常,正在回滚..." 回滚操作 LATEST_BACKUP=$(ssh root@$server "ls -t $BACKUP_PATH | head -1") ssh root@$server " rm -rf $REMOTE_PATH cp -r $BACKUP_PATH/$LATEST_BACKUP $REMOTE_PATH systemctl restart $PROJECT_NAME " fi else echo "$server 部署失败" fi done echo "部署完成" 监控和告警 同步状态监控 #!/bin/bash rsync状态监控脚本 MONITOR_LOG="/var/log/rsync-monitor.log" ALERT_EMAIL="admin@company.com" check_rsync_status() { local log_file=$1 local max_age_hours=2 if [ ! -f "$log_file" ]; then echo "告警: 同步日志文件不存在" return 1 fi 检查日志文件是否太旧 if [ $(find "$log_file" -mmin +$((max_age_hours * 60)) | wc -l) -gt 0 ]; then echo "告警: 同步日志超过 $max_age_hours 小时未更新" return 1 fi 检查是否有错误 if grep -q "rsync error\|failed\|No such file" "$log_file"; then echo "告警: 同步过程中发现错误" return 1 fi return 0 } 检查各个同步任务 SYNC_LOGS=("/var/log/web-sync.log" "/var/log/db-sync.log" "/var/log/config-sync.log") for log in "${SYNC_LOGS[@]}"; do if ! check_rsync_status "$log"; then echo "$(date): $log 检查失败" >> $MONITOR_LOG 发送告警邮件 tail -50 "$log" | mail -s "Rsync同步告警: $(basename $log)" $ALERT_EMAIL fi done rsync作为运维工程师的必备工具,其强大的功能和灵活的配置能够满足各种数据同步需求。无论是日常的文件备份,还是复杂的多服务器部署,rsync都能提供可靠的解决方案。 在实际工作中,建议大家根据具体业务场景选择合适的同步策略,并结合其他工具(如cron、监控系统、配置管理工具等)构建完整的自动化运维体系。 记住,工具的价值在于解决实际问题。理解业务需求,选择合适的技术方案,才能真正发挥rsync的威力,提高运维工作的效率和可靠性。