一、为什么需要批量同步?

想象一下,你管理着10台服务器,每次更新网站内容都要手动挨个上传文件,是不是头皮发麻?这就是批量同步要解决的问题。rsync这个老牌工具就像个智能快递员,它能精准识别哪些文件需要更新,只传输变化的部分,大大节省时间和带宽。

举个实际例子:公司官网改版后,需要把新版的HTML/CSS文件同步到5台前端服务器。手动操作不仅容易出错,还特别耗时。这时候,一个自动化的同步脚本就能让你准时下班。

二、准备工作要做好

在写脚本之前,我们需要做些基础工作:

  1. 确保所有服务器都安装了rsync(Linux系统通常自带)
  2. 主控机需要配置到所有从机的SSH免密登录
  3. 统一规划好文件存放路径

配置SSH免密登录的示例(技术栈:Linux Shell):

# 在主控机生成密钥对
ssh-keygen -t rsa -b 4096  # 按回车保持默认设置

# 将公钥拷贝到从机1(重复此步骤配置其他从机)
ssh-copy-id -i ~/.ssh/id_rsa.pub user@slave1_ip

三、脚本编写实战

下面这个脚本实现了核心同步功能,我们逐段分析:

#!/bin/bash
# 技术栈:Linux Shell

# 配置区域:根据实际情况修改
MASTER_DIR="/var/www/project"  # 主控机源目录
SLAVES=("192.168.1.101" "192.168.1.102" "192.168.1.103")  # 从机IP数组
REMOTE_USER="webadmin"  # 远程登录用户名
REMOTE_DIR="/var/www/project"  # 从机目标目录

# 日志函数:记录操作过程和错误
log() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" >> /var/log/rsync_batch.log
}

# 主同步函数
sync_to_slave() {
    local slave_ip=$1
    log "开始同步到 $slave_ip"
    
    rsync -avz --delete \
        -e "ssh -o StrictHostKeyChecking=no" \
        $MASTER_DIR/ $REMOTE_USER@$slave_ip:$REMOTE_DIR
    
    if [ $? -eq 0 ]; then
        log "$slave_ip 同步成功"
    else
        log "$slave_ip 同步失败!错误码:$?"
    fi
}

# 主程序入口
log "========== 开始批量同步 =========="
for slave in "${SLAVES[@]}"; do
    sync_to_slave $slave
done
log "========== 同步任务完成 =========="

这个脚本有几个亮点:

  1. 使用数组存储从机IP,方便扩展
  2. 详细的日志记录功能
  3. --delete参数保持两端完全一致
  4. 错误处理机制

四、进阶功能增强

基础版本能用,但我们可以做得更专业:

  1. 增加邮件报警功能
  2. 实现增量备份
  3. 添加同步前检查

改进后的报警功能示例:

# 在同步函数中添加邮件通知
send_alert() {
    local subject=$1
    local content=$2
    echo "$content" | mail -s "$subject" admin@example.com
}

sync_to_slave() {
    # ...原有代码...
    if [ $? -ne 0 ]; then
        send_alert "同步报警" "主机 $slave_ip 同步失败!"
    fi
}

五、实际应用中的技巧

经过多个项目的实践,我总结出这些经验:

  1. 带宽限制:大文件同步时加上--bwlimit=5000(单位KB/s)
  2. 网络抖动:添加--timeout=30参数
  3. 权限问题:建议统一使用--chmod=755参数
  4. 部分同步:可以指定子目录,如$MASTER_DIR/uploads/

六、常见问题排雷

新手常会遇到这些问题:

  1. 权限不足错误:

    rsync: mkstemp "/var/www/.index.html.XXXXXX" failed: Permission denied (13)
    

    解决方法:确保远程用户对目标目录有写权限

  2. 连接超时:

    ssh: connect to host 192.168.1.101 port 22: Connection timed out
    

    检查:网络连通性、防火墙设置、SSH服务状态

  3. 文件校验不一致: 使用-c参数启用校验模式,但会显著降低速度

七、性能优化建议

当服务器数量多时,这些优化很关键:

  1. 并行同步:使用parallel命令或&后台执行

    for slave in "${SLAVES[@]}"; do
        sync_to_slave $slave &
    done
    wait
    
  2. 差分同步:结合find命令找出24小时内修改的文件

    find $MASTER_DIR -type f -mtime -1 > filelist.txt
    rsync --files-from=filelist.txt ...
    
  3. 压缩传输:对于文本文件,-z参数能减少30%-70%传输量

八、安全注意事项

自动化同步虽方便,但安全不能忽视:

  1. 使用专用账号:不要用root直接同步
  2. 限制IP访问:配置从机的SSH只允许主控机IP连接
  3. 敏感文件过滤:通过--exclude参数排除配置文件
    rsync --exclude="*.env" --exclude="config/" ...
    
  4. 日志审计:定期检查同步日志,发现异常操作

九、完整方案示例

结合所有优化点,这是最终版的脚本:

#!/bin/bash
# 增强版批量同步脚本

# 配置区
MASTER_DIR="/data/website"
SLAVES=("201.120.10.1" "201.120.10.2" "201.120.10.3")
REMOTE_USER="syncuser"
REMOTE_DIR="/data/website"
MAX_THREADS=3  # 最大并发数

# 初始化日志
LOG_FILE="/var/log/sync_$(date +%Y%m%d).log"
exec 3>&1 4>&2
trap 'exec 2>&4 1>&3' 0 1 2 3
exec 1>>$LOG_FILE 2>&1

# 线程控制函数
thread_ctrl() {
    while [ $(jobs -r | wc -l) -ge $MAX_THREADS ]; do
        sleep 1
    done
}

# 带重试机制的同步
sync_with_retry() {
    local ip=$1
    for i in {1..3}; do
        rsync -avz --partial --delete --timeout=30 \
            -e "ssh -o ConnectTimeout=10" \
            $MASTER_DIR/ $REMOTE_USER@$ip:$REMOTE_DIR
        [ $? -eq 0 ] && return 0
        sleep $((i*5))
    done
    return 1
}

# 主流程
echo "==== 启动同步 $(date) ===="
for ip in "${SLAVES[@]}"; do
    thread_ctrl
    (
        if sync_with_retry "$ip"; then
            echo "[成功] $ip"
        else
            echo "[失败] $ip"
            # 这里可以添加报警逻辑
        fi
    ) &
done
wait
echo "==== 同步结束 $(date) ===="

十、总结与展望

通过这个方案,我们实现了:

  • 一键式多服务器同步
  • 完善的错误处理和日志
  • 灵活的并发控制
  • 自动重试机制

未来还可以考虑:

  1. 集成到CI/CD流程中
  2. 增加Web控制界面
  3. 结合inotify实现实时同步

记住,自动化运维的核心是"懒" - 但不是真的偷懒,而是把时间花在更有价值的事情上。这个脚本可能只需要你半天时间开发,但能节省未来无数个加班的夜晚。