背景与适用场景
在服务器运维工作中,经常需要在本地机器和远程服务器之间、或者两台服务器之间传输文件。Linux 提供了多种文件传输工具,其中最常用的是 scp 和 rsync。
scp(secure copy)是基于 SSH 协议的文件传输工具,语法简单,使用方便,适合小文件和一次性传输。rsync 则是一个更强大的文件同步工具,支持增量同步、压缩传输、断点续传,适合大文件迁移和定期备份。
选择哪个工具,取决于具体场景:小文件快速传输用 scp,大文件或需要增量同步时用 rsync,目录定期同步时更应该用 rsync。
本文面向初中级运维工程师,详细讲解 scp 和 rsync 的用法、参数、实战场景,以及常见问题的解决方案。
第一部分:scp 详解
基本原理
scp 基于 SSH 协议实现文件加密传输,数据传输过程是加密的。它的工作方式是在本地执行命令,通过 SSH 连接到远程主机,完成文件传输后再返回结果。
scp 的优点是简单易用,缺点是每次传输都会复制全部文件,不支持增量同步。
基本语法
# 从本地复制到远程 scp [选项] 源路径 目标路径 # 从远程复制到本地 scp [选项] 远程用户@远程主机:远程路径 本地路径 # 从远程复制到远程 scp [选项] 用户1@主机1:路径1 用户2@主机2:路径2
常用参数
-r:递归复制整个目录
-p:保留原文件的修改时间、访问时间和权限
-q:静默模式,不显示传输进度
-v:详细模式,显示调试信息
-C:启用压缩传输
-P port:指定 SSH 端口(注意是大写 P)
-i identity_file:指定私钥文件
-l limit:限制带宽(单位 Kbit/s)
-o ssh_option:传递 SSH 选项
-F ssh_config:指定 SSH 配置文件
实战示例
场景一:从本地上传文件到远程服务器
上传单个文件:
scp /path/to/local/file.txt remote_user@192.168.1.100:/remote/path/
上传文件并指定 SSH 端口:
scp -P 2222 /path/to/local/file.txt remote_user@192.168.1.100:/remote/path/
上传文件并指定私钥:
scp -i ~/.ssh/id_rsa /path/to/local/file.txt remote_user@192.168.1.100:/remote/path/
上传文件并保留原属性:
scp -p /path/to/local/file.txt remote_user@192.168.1.100:/remote/path/
场景二:从远程服务器下载文件到本地
下载单个文件:
scp remote_user@192.168.1.100:/remote/path/file.txt /local/path/
下载整个目录:
scp -r remote_user@192.168.1.100:/remote/path/directory /local/path/
场景三:两台远程服务器之间传输文件
不经过本地,直接在两台服务器之间传输:
scp user1@host1:/path/to/file user2@host2:/path/to/destination/
场景四:批量上传多个文件
使用通配符:
scp /local/path/*.txt remote_user@192.168.1.100:/remote/path/
使用空格分隔多个文件:
scp file1.txt file2.txt file3.txt remote_user@192.168.1.100:/remote/path/
场景五:限制带宽传输
限制带宽为 500KB/s(适用于不影响业务带宽的场景):
scp -l 4000 /largefile.tar.gz remote_user@192.168.1.100:/remote/path/
注意:-l 参数的单位是 Kbit/s,不是 KB/s。如果想限制 500KB/s,需要设置 -l 4000。
场景六:使用压缩传输
压缩可以减少传输数据量,加快传输速度(对文本文件效果明显,对已压缩文件效果有限):
scp -C /path/to/largefile.tar.gz remote_user@192.168.1.100:/remote/path/
实战技巧
使用 SSH Config 简化连接
在 ~/.ssh/config 中添加主机配置:
Host prod-server HostName 192.168.1.100 User remote_user Port 22 IdentityFile ~/.ssh/id_rsa Host prod-backup HostName 192.168.1.101 User backup_user Port 2222 IdentityFile ~/.ssh/id_rsa_backup
配置后可以直接使用别名:
# 上传文件 scp file.txt prod-server:/remote/path/ # 下载文件 scp prod-server:/remote/path/file.txt /local/path/
传输进度显示
scp 默认会显示传输进度。如果传输中断想重新开始,直接重新执行 scp 命令即可。
断线重连
scp 不支持断点续传。如果传输中断,需要重新开始。对于大文件,建议使用 rsync。
常见错误与解决
错误一:ssh: connect to host port 22: Connection refused
原因:SSH 端口不是默认的 22,或 SSH 服务未运行。
解决:
# 确认 SSH 端口 ssh -p 2222 remote_user@192.168.1.100 # 在 scp 中指定端口 scp -P 2222 file.txt remote_user@192.168.1.100:/path/
错误二:Permission denied (publickey)
原因:SSH 密钥未配置或权限不正确。
解决:
# 确认私钥权限正确 chmod 600 ~/.ssh/id_rsa # 指定正确的私钥 scp -i ~/.ssh/id_rsa file.txt remote_user@192.168.1.100:/path/
错误三:Not a regular file
原因:尝试上传目录但未加 -r 参数,或者目标路径是目录但未以 / 结尾。
解决:
# 上传目录需要加 -r scp -r /local/directory remote_user@192.168.1.100:/remote/path/ # 确保目标路径以 / 结尾,表示是目录 scp file.txt remote_user@192.168.1.100:/remote/path/
错误四:No such file or directory
原因:远程路径不存在。
解决:
# 先创建目录 ssh remote_user@192.168.1.100 "mkdir -p /remote/path" # 再传输 scp file.txt remote_user@192.168.1.100:/remote/path/
安全注意事项
私钥文件权限:私钥文件权限必须是 600,否则 SSH 会拒绝使用
不要在命令中明文输入密码:使用 SSH 密钥认证
谨慎使用通配符:确保通配符不会匹配到不该传输的文件
检查目标路径:scp 会覆盖已存在的同名文件,且不会提示
大文件传输:scp 不支持断点续传,传输大文件建议用 rsync
第二部分:rsync 详解
基本原理
rsync 是一个快速、多功能的文件同步工具。它通过特殊的算法,只传输源文件和目标文件之间不同的部分(增量传输),大大减少网络传输量和同步时间。
rsync 可以本地使用,也可以通过 SSH 或 rsync daemon 远程使用。
基本语法
# 本地同步 rsync [选项] 源路径 目标路径 # 远程同步(通过 SSH) rsync [选项] 源路径 用户@主机:目标路径 # 远程同步(通过 rsync daemon) rsync [选项] 源路径 用户@主机::模块/目标路径
常用参数
同步控制参数
-r:递归同步(但不保留权限、时间戳等属性)
-a:归档模式,等价于 -rlptgoD(保留权限、时间戳、属主、属组、符号链接、设备文件等)
-z:压缩传输
-P:显示进度并保留部分传输的文件(等同于 --partial --progress)
--delete:删除目标目录中源目录没有的文件(镜像同步)
--exclude=PATTERN:排除匹配模式的文件
--include=PATTERN:包含匹配模式的文件(必须放在 --exclude 前面)
--filter=RULE:添加过滤规则
同步行为参数
-n 或 --dry-run:模拟同步,不实际执行,用于预览
-v:详细输出
-q:静默模式,只显示错误信息
--stats:显示传输统计信息
--itemize-changes:显示每个变更的详细信息
文件属性参数
-t 或 --times:保留时间戳
-p 或 --perms:保留权限
-o 或 --owner:保留所有者(需要 root 权限)
-g 或 --group:保留所属组
--links:保留符号链接
--devices:保留设备文件(需要 root 权限)
--specials:保留特殊文件
传输参数
-e:指定远程 shell(如 ssh)
-l:传输符号链接
-L:传输符号链接指向的源文件
-W:完整传输,不做增量检查(适合跨文件系统)
--bwlimit=RATE:限制带宽(单位 KB/s)
--partial:保留部分传输的文件(断点续传)
--progress:显示传输进度
过滤参数
--exclude=PATTERN:排除匹配的文件
--exclude-from=FILE:从文件读取排除规则
--include=PATTERN:包含匹配的文件
--include-from=FILE:从文件读取包含规则
实战示例
场景一:本地目录同步
基本同步:
rsync -av /source/directory/ /target/directory/
注意:源目录末尾的 / 表示同步目录内容,不包括目录本身。如果不加 /,会把 source 目录本身同步到 target 下。
# 同步目录内容(target/directory/ 下是 source 的内容) rsync -av /source/directory/ /target/directory/ # 同步整个目录(target/directory/ 下是 source 目录) rsync -av /source/directory /target/
场景二:远程同步(通过 SSH)
上传到远程服务器:
rsync -avz -e ssh /local/directory/ remote_user@192.168.1.100:/remote/directory/
从远程服务器下载:
rsync -avz -e ssh remote_user@192.168.1.100:/remote/directory/ /local/directory/
指定 SSH 端口:
rsync -avz -e "ssh -p 2222" /local/directory/ remote_user@192.168.1.100:/remote/directory/
场景三:增量同步(只传输变化的部分)
rsync 的核心优势就是增量传输:
rsync -avz /source/directory/ remote_user@192.168.1.100:/remote/directory/
第一次传输全部内容,后续只传输变化的部分。
场景四:镜像同步(完全一致)
删除目标目录中源目录没有的文件:
rsync -avz --delete /source/directory/ remote_user@192.168.1.100:/remote/directory/
这个操作会把目标目录变成源目录的镜像,危险:目标目录中多余的文件会被删除。使用前务必确认。
场景五:排除特定文件
排除日志文件:
rsync -avz --exclude='*.log' /source/directory/ remote_user@192.168.1.100:/remote/directory/
排除多个模式:
rsync -avz --exclude='*.log' --exclude='*.tmp' --exclude='.cache' /source/directory/ remote_user@192.168.1.100:/remote/directory/
排除特定目录:
rsync -avz --exclude='node_modules' --exclude='.git' /project/ remote_user@192.168.1.100:/remote/project/
场景六:包含特定文件
先包含后排除,rsync 会按顺序处理规则:
rsync -avz --include='*.php' --include='*/' --exclude='*' /source/ remote@:/target/
这个例子表示:只传输 .php 文件,同时传输所有目录(否则无法进入子目录)。
场景七:预览同步结果(不实际执行)
rsync -avzn --delete /source/directory/ remote_user@192.168.1.100:/remote/directory/
-n 参数会模拟执行,只显示会发生什么变化,不实际传输文件。
场景八:限制带宽
限制传输速度为 1MB/s:
rsync -avz --bwlimit=1024 /large/directory/ remote_user@192.168.1.100:/remote/directory/
场景九:断点续传
如果传输中断,使用 --partial 保留已传输的部分:
rsync -avzP --partial /large/directory/ remote_user@192.168.1.100:/remote/directory/
或者简写为:
rsync -avzP /large/directory/ remote_user@192.168.1.100:/remote/directory/
-P 等同于 --partial --progress。
场景十:显示传输统计
rsync -avz --stats /source/directory/ remote_user@192.168.1.100:/remote/directory/
输出示例:
Number of files: 12345 Number of files transferred: 234 Total file size: 1234567890 bytes Total transferred file size: 12345678 bytes Literal data: 12345678 bytes Matched data: 0 bytes File list size: 123456 File list generation time: 0.001 seconds File list transfer time: 0.000 seconds Total bytes sent: 12345678 bytes Total bytes received: 12345 bytes sent 12345678 bytes received 12345 bytes 23456.78 bytes/sec total size is 1234567890 speedup is 99.00
常用场景
场景一:网站代码部署
使用 rsync 同步代码到 Web 服务器:
#!/bin/bash # deploy.sh - 网站部署脚本 # 配置 REMOTE_USER=deploy REMOTE_HOST=192.168.1.100 REMOTE_PATH=/var/www/html LOCAL_PATH=/home/deploy/app # 排除不需要同步的文件 EXCLUDE_FILE="/tmp/rsync_exclude.txt" cat > "$EXCLUDE_FILE" << 'EOF' *.log .env node_modules/ .git/ .cache/ .DS_Store EOF # 同步前检查 echo "开始同步 $LOCAL_PATH 到 $REMOTE_HOST:$REMOTE_PATH" echo "排除文件列表:" cat "$EXCLUDE_FILE" # 执行同步(先预览) echo "预览模式..." rsync -avzn --delete --exclude-from="$EXCLUDE_FILE" -e "ssh -p 22" "$LOCAL_PATH/" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH/" read -p "确认执行同步? (yes/no): " CONFIRM if [ "$CONFIRM" != "yes" ]; then echo "取消部署" exit 0 fi # 正式同步 echo "执行同步..." rsync -avz --delete --exclude-from="$EXCLUDE_FILE" -e "ssh -p 22" "$LOCAL_PATH/" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH/" # 清理 rm -f "$EXCLUDE_FILE" echo "部署完成"
场景二:定时备份
使用 cron 定时同步备份:
# 每天凌晨 3 点同步备份 0 3 * * * rsync -avz --delete -e "ssh -p 22" /data/ remote_user@192.168.1.100:/backup/data/ >> /var/log/rsync_backup.log 2>&1
场景三:多服务器同步
将同一份文件同步到多台服务器:
#!/bin/bash
# multi_sync.sh - 同步到多台服务器
SERVERS=(
"192.168.1.101"
"192.168.1.102"
"192.168.1.103"
)
REMOTE_USER=deploy
REMOTE_PATH=/var/www/html
LOCAL_PATH=/home/deploy/app
for SERVER in "${SERVERS[@]}"; do
echo "=== 同步到 $SERVER ==="
rsync -avz --delete
-e "ssh -p 22"
"$LOCAL_PATH/" "$REMOTE_USER@$SERVER:$REMOTE_PATH/"
echo ""
done
echo "所有服务器同步完成"
场景四:日志目录同步
同步日志到日志收集服务器:
# 排除最新的日志文件(可能正在写入) rsync -avz --exclude='*current.log' remote_user@192.168.1.100:/var/log/myapp/ /backup/logs/myapp/
rsync daemon 模式
rsync 还可以作为守护进程运行,适合内网大流量传输(比 SSH 更快,因为不加密)。
配置 rsync daemon
创建配置文件 /etc/rsync.conf:
uid = nobody gid = nobody use chroot = yes max connections = 4 pid file = /var/run/rsyncd.pid exclude = lost+found/ transfer logging = yes timeout = 900 read only = no list = yes [backup] path = /backup comment = Backup directory hosts allow = 192.168.1.0/24 auth users = backup secrets file = /etc/rsyncd.secrets
创建密码文件 /etc/rsyncd.secrets:
backup:password123
设置权限:
chmod 600 /etc/rsyncd.secrets
启动 rsync daemon:
# 手动启动 rsync --daemon # 设置开机启动(systemd) cat > /etc/systemd/system/rsync.service << 'EOF' [Unit] Description=rsync daemon After=network.target [Service] ExecStart=/usr/bin/rsync --daemon --no-detach Restart=always [Install] WantedBy=multi-user.target EOF systemctl enable rsync systemctl start rsync
使用 rsync daemon 传输
# 上传 rsync -avz /local/path/ backup@192.168.1.100::backup/ # 下载 rsync -avz backup@192.168.1.100::backup/ /local/path/ # 使用密码文件(避免交互输入密码) rsync -avz --password-file=/path/to/rsync.passwd /local/path/ backup@192.168.1.100::backup/
常见错误与解决
错误一:skipping directory
原因:源路径末尾没有 /,导致 rsync 把目录本身同步进去。
解决:
# 加 / 同步目录内容 rsync -av /source/directory/ /target/directory/
错误二:Permission denied (publickey)
原因:SSH 认证失败。
解决:
# 确认 SSH 密钥配置正确 ssh -v remote_user@192.168.1.100 # 确认私钥权限 chmod 600 ~/.ssh/id_rsa # 使用 -e 参数指定 SSH 选项调试 rsync -avz -e "ssh -v" /source/ remote@:/target/
错误三:rsync: connection unexpectedly closed
原因:远程 rsync daemon 未运行,或 SSH 连接被断开。
解决:
# 如果用 daemon 模式,检查服务状态 systemctl status rsync # 如果用 SSH 模式,增加超时时间 rsync -avz --timeout=600 /source/ remote@:/target/
错误四:rsync: safe_read failed
原因:网络不稳定导致读取失败。
解决:
# 增加超时时间 rsync -avz --timeout=600 /source/ remote@:/target/ # 使用断点续传 rsync -avzP /source/ remote@:/target/
安全注意事项
使用 SSH 加密:生产环境优先使用 SSH 模式,而不是 daemon 模式(除非在内网)
设置 SSH 密钥:避免在脚本中明文存储密码
限制 rsync daemon 访问:使用 hosts allow 限制允许连接的 IP
敏感文件排除:同步代码时排除 .env、*.key、*.pem 等敏感文件
--delete 的危险性:使用 --delete 前务必先预览,确认无误后再执行
第三部分:scp 与 rsync 对比
功能对比
| 特性 | scp | rsync |
|---|---|---|
| 传输方式 | 全部传输 | 增量传输 |
| 断点续传 | 不支持 | 支持(--partial) |
| 压缩传输 | 支持(-C) | 支持(-z) |
| 排除文件 | 不支持 | 支持(--exclude) |
| 预览模式 | 不支持 | 支持(-n) |
| 速度(全量) | 较快 | 较快 |
| 速度(增量) | 慢(全部传输) | 快(只传变化部分) |
| 语法复杂度 | 简单 | 较复杂 |
| 适用场景 | 小文件、一次性传输 | 大文件、定期同步 |
选择建议
使用 scp 的场景:
传输小文件(几十 MB 以内)
一次性传输,不需要重复执行
网络稳定,不需要断点续传
只想快速复制文件,不需要复杂选项
使用 rsync 的场景:
传输大文件或大量文件
需要增量同步(只传输变化部分)
需要排除特定文件或目录
需要断点续传
需要定期同步(部署、备份)
需要预览同步结果
性能对比
假设源目录有 1000 个文件,其中只有 10 个文件发生了变化:
scp:传输全部 1000 个文件
rsync:只传输 10 个变化的文件
对于大文件,差异更明显。如果只有一个 10GB 的文件变化,scp 需要传输整个 10GB,rsync 可能只需要传输几百 MB 的差异数据。
传输速度优化
scp 优化:
# 启用压缩 scp -C file.tar.gz remote:/path/ # 多线程传输(需要安装并行工具) # 先压缩再分割传输(复杂场景)
rsync 优化:
# 启用压缩 rsync -avz source/ remote:/target/ # 使用 --whole-file(全量传输,适合局域网) rsync -avzW source/ remote:/target/ # 调整块大小(适合大文件) rsync -avz --block-size=8192 source/ remote:/target/
第四部分:生产环境实战案例
案例一:大型日志文件迁移
场景描述
需要将一台旧服务器上的 500GB 日志文件迁移到新服务器,网络带宽有限(100Mbps),需要分批传输,且不能影响业务。
方案设计
使用 rsync 增量同步,先同步大部分数据
选择业务低峰期(凌晨)完成最后同步
使用 --bwlimit 限制带宽,避免影响业务
操作步骤
#!/bin/bash # migrate_logs.sh - 日志迁移脚本 SOURCE_USER=root SOURCE_HOST=192.168.1.50 SOURCE_PATH=/var/log/myapp TARGET_USER=root TARGET_HOST=192.168.1.100 TARGET_PATH=/var/log/myapp # 带宽限制 10MB/s(约80Mbps) BW_LIMIT=10240 # 排除正在写入的日志 EXCLUDE_FILE="/tmp/rsync_exclude.txt" cat > "$EXCLUDE_FILE" << 'EOF' *.current.log *.tmp EOF echo "=== 开始日志迁移 ===" echo "源: $SOURCE_HOST:$SOURCE_PATH" echo "目标: $TARGET_HOST:$TARGET_PATH" echo "带宽限制: $BW_LIMIT KB/s" echo "" # 第一次同步(完整同步,限速) echo ">>> 第一次同步..." rsync -avzP --bwlimit=$BW_LIMIT --exclude-from="$EXCLUDE_FILE" -e "ssh -p 22" "$SOURCE_USER@$SOURCE_HOST:$SOURCE_PATH/" "$TARGET_USER@$TARGET_HOST:$TARGET_PATH/" # 检查第一次同步结果 if [ $? -eq 0 ]; then echo ">>> 第一次同步完成" else echo ">>> 第一次同步失败,请检查" exit 1 fi # 第二次同步(增量,检查是否有新文件) echo ">>> 第二次同步(增量检查)..." rsync -avzP --bwlimit=$BW_LIMIT --exclude-from="$EXCLUDE_FILE" -e "ssh -p 22" "$SOURCE_USER@$SOURCE_HOST:$SOURCE_PATH/" "$TARGET_USER@$TARGET_HOST:$TARGET_PATH/" echo ">>> 迁移完成" rm -f "$EXCLUDE_FILE"
验证步骤
# 在源服务器执行 find /var/log/myapp -type f | wc -l du -sh /var/log/myapp # 在目标服务器执行 find /var/log/myapp -type f | wc -l du -sh /var/log/myapp # 对比 MD5(可选,对关键文件) md5sum /var/log/myapp/*.log # 在目标服务器对比
案例二:代码部署
场景描述
使用 rsync 实现代码零停机部署,部署前先在测试目录验证,确认无误后切换。
方案设计
同步到测试目录
验证测试目录内容
切换(用 rsync 同步到正式目录)
#!/bin/bash # deploy.sh - 零停机部署脚本 set -e # 配置 APP_USER=deploy APP_HOST=192.168.1.100 APP_PATH=/var/www/myapp TEST_PATH=/var/www/myapp_test SOURCE_PATH=/home/deploy/releases/$(date +%Y%m%d_%H%M%S) # 创建发布目录 mkdir -p "$SOURCE_PATH" # 模拟:复制代码到发布目录 cp -r /home/deploy/app/* "$SOURCE_PATH/" echo "=== 代码部署开始 ===" echo "发布版本: $SOURCE_PATH" echo "" # 步骤1:同步到测试目录 echo ">>> 步骤1:同步到测试目录..." rsync -avz --exclude='.env' --exclude='.git' --exclude='node_modules' -e "ssh -p 22" "$SOURCE_PATH/" "$APP_USER@$APP_HOST:$TEST_PATH/" # 步骤2:验证测试目录 echo ">>> 步骤2:验证测试目录..." ssh -p 22 "$APP_USER@$APP_HOST" "ls -la $TEST_PATH | head -20" # 步骤3:确认部署 read -p "确认切换到正式环境? (yes/no): " CONFIRM if [ "$CONFIRM" != "yes" ]; then echo "取消部署" exit 0 fi # 步骤4:同步到正式目录 echo ">>> 步骤3:同步到正式目录..." rsync -avz --exclude='.env' --exclude='.git' --exclude='node_modules' -e "ssh -p 22" "$SOURCE_PATH/" "$APP_USER@$APP_HOST:$APP_PATH/" # 步骤5:重启应用 echo ">>> 步骤4:重启应用..." ssh -p 22 "$APP_USER@$APP_HOST" "systemctl restart myapp" # 步骤6:验证 echo ">>> 步骤5:验证应用..." sleep 3 ssh -p 22 "$APP_USER@$APP_HOST" "curl -s http://localhost/health" echo "" echo "=== 部署完成 ==="
案例三:数据库备份同步
场景描述
需要将数据库备份文件同步到异地备份服务器,备份文件每天生成一次,需要定期同步。
方案设计
本地备份数据库
压缩备份文件
使用 rsync 同步到备份服务器
清理本地过期备份
#!/bin/bash
# backup_db.sh - 数据库备份与同步
set -e
# 配置
DB_HOST=localhost
DB_USER=backup
DB_PASS='password123'
DB_NAME=myapp
BACKUP_DIR=/backup/db
REMOTE_USER=backup
REMOTE_HOST=192.168.1.200
REMOTE_PATH=/backup/myapp
RETENTION_DAYS=30
# 创建备份目录
mkdir -p "$BACKUP_DIR"
# 备份文件名(带时间戳)
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_$(date +%Y%m%d_%H%M%S).sql"
echo "=== 数据库备份开始 ==="
echo "时间: $(date)"
echo "备份文件: $BACKUP_FILE"
# 备份数据库
mysqldump -h"$DB_HOST" -u"$DB_USER" -p"$DB_PASS"
--single-transaction
--routines
--triggers
--events
"$DB_NAME" > "$BACKUP_FILE"
if [ $? -eq 0 ]; then
echo "备份成功"
else
echo "备份失败"
exit 1
fi
# 压缩备份文件
gzip "$BACKUP_FILE"
BACKUP_FILE="${BACKUP_FILE}.gz"
echo "备份文件: $BACKUP_FILE"
# 同步到远程备份服务器
echo ">>> 同步到远程备份服务器..."
rsync -avzP
--bwlimit=5120
-e "ssh -p 22"
"$BACKUP_FILE"
"$REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH/"
if [ $? -eq 0 ]; then
echo "同步成功"
else
echo "同步失败"
exit 1
fi
# 清理本地过期备份(保留 30 天)
echo ">>> 清理本地过期备份..."
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
# 显示备份统计
echo ""
echo "=== 备份统计 ==="
echo "本地备份数量: $(find "$BACKUP_DIR" -name '*.sql.gz' | wc -l)"
echo "本地备份总大小: $(du -sh "$BACKUP_DIR" | cut -f1)"
echo "完成时间: $(date)"
总结
scp 常用命令速查
# 上传文件 scp file.txt user@host:/path/ # 下载文件 scp user@host:/path/file.txt /local/path/ # 上传目录 scp -r /local/dir user@host:/remote/path/ # 指定端口 scp -P 2222 file.txt user@host:/path/ # 限速 1MB/s scp -l 8000 file.txt user@host:/path/ # 压缩传输 scp -C file.txt user@host:/path/
rsync 常用命令速查
# 本地同步 rsync -av /source/ /target/ # 远程同步 rsync -avz /source/ user@host:/target/ # 增量同步(只传变化) rsync -avzP /source/ user@host:/target/ # 预览(不执行) rsync -avzn /source/ user@host:/target/ # 排除文件 rsync -avz --exclude='*.log' /source/ user@host:/target/ # 镜像同步(删除目标多余文件) rsync -avz --delete /source/ user@host:/target/ # 断点续传 rsync -avzP /source/ user@host:/target/ # 限速 rsync -avz --bwlimit=1024 /source/ user@host:/target/
选型建议
一次性小文件传输:用 scp,简单直接
大文件或定期同步:用 rsync,效率高
需要预览结果:用 rsync -n
网络不稳定:用 rsync --partial
排除特定文件:用 rsync --exclude
内网大流量:考虑 rsync daemon 模式
最佳实践
使用 SSH 密钥认证:避免每次传输输入密码
先用 -n 预览:重要操作前先 dry-run
设置带宽限制:避免影响业务网络
排除敏感文件:.env、*.key、*.pem 等
记录传输日志:便于排查问题和审计
验证传输结果:对比文件数量、校验和
常见问题自检清单
传输前检查清单:
[ ] 确认源文件路径正确 [ ] 确认目标路径存在或有写权限 [ ] 确认 SSH 连接正常(ssh 连接测试) [ ] 确认磁盘空间充足(目标服务器 df -h) [ ] 确认网络带宽不会影响业务 [ ] 确认传输文件不包含敏感信息
传输后验证清单:
[ ] 对比文件数量(find | wc -l) [ ] 对比文件大小(du -sh) [ ] 抽样校验 MD5(md5sum) [ ] 检查日志文件完整性 [ ] 确认应用能正常读取文件
自动化巡检脚本
配合 cron 实现定期巡检:
# /etc/cron.daily/check_sync.sh LOG_FILE="/var/log/sync_check.log" REMOTE_USER=deploy REMOTE_HOST=192.168.1.100 SOURCE_PATH=/data REMOTE_PATH=/backup/data echo "=== 同步巡检 $(date) ===" >> "$LOG_FILE" # 检查远程目录是否存在 if ssh $REMOTE_USER@$REMOTE_HOST "test -d $REMOTE_PATH"; then echo "[OK] 远程目录存在" >> "$LOG_FILE" else echo "[FAIL] 远程目录不存在" >> "$LOG_FILE" fi # 检查源目录大小 SOURCE_SIZE=$(du -sh "$SOURCE_PATH" 2>/dev/null | cut -f1) echo "源目录大小: $SOURCE_SIZE" >> "$LOG_FILE" # 检查远程目录大小 REMOTE_SIZE=$(ssh $REMOTE_USER@$REMOTE_HOST "du -sh $REMOTE_PATH 2>/dev/null" | cut -f1) echo "远程目录大小: $REMOTE_SIZE" >> "$LOG_FILE" # 检查同步状态 if [ "$SOURCE_SIZE" = "$REMOTE_SIZE" ]; then echo "[OK] 同步完成" >> "$LOG_FILE" else echo "[WARN] 大小不一致,可能需要重新同步" >> "$LOG_FILE" fi echo "" >> "$LOG_FILE"
全部0条评论
快来发表一下你的评论吧 !