scp 与 rsync:服务器文件传输工具用法与优劣解析
来源:马哥Linux运维 | 发布日期:2026-05-29
在服务器运维中,经常需要在本机和远程服务器之间、或两台服务器之间传输文件。scp 语法简单适合小文件一次性传输,rsync 支持增量同步和断点续传适合大文件迁移和定期备份。本文面向初中级运维工程师,详细讲解两个工具的用法、参数、实战场景和常见问题解决方案。
一、scp 详解
基本原理
scp(Secure Copy)基于 SSH 协议实现文件加密传输。在本地执行命令,通过 SSH 连接到远程主机完成传输后返回结果。
- 优点: 简单易用,一行命令搞定
- 缺点: 每次传输复制全部文件,不支持增量同步
基本语法
# 从本地复制到远程
scp [选项] 源路径 目标路径
# 从远程复制到本地
scp [选项] 远程用户@远程主机:远程路径 本地路径
# 从远程复制到远程(不经过本地中转)
scp [选项] 用户1@主机1:路径1 用户2@主机2:路径2
常用参数
| 参数 | 作用 | 示例 |
|---|---|---|
-r |
递归复制整个目录 | scp -r /dir user@host:/dest/ |
-p |
保留原文件的修改时间、访问时间和权限 | scp -p file user@host:/dest/ |
-q |
静默模式,不显示传输进度 | scp -q file user@host:/dest/ |
-v |
详细/调试模式,显示 SSH 连接过程 | scp -v file user@host:/dest/ |
-C |
启用压缩传输 | scp -C file user@host:/dest/ |
-P port |
指定 SSH 端口(注意是大写 P) | scp -P 2222 file user@host:/dest/ |
-i file |
指定私钥文件 | scp -i ~/.ssh/id_rsa file user@host:/dest/ |
-l limit |
限制带宽(单位 Kbit/s) | scp -l 4000 file user@host:/dest/ |
-o option |
传递 SSH 选项 | scp -o "ConnectTimeout=10" file user@host:/dest/ |
-F file |
指定 SSH 配置文件 | scp -F ~/.ssh/prod_config file user@host:/dest/ |
实战场景
场景一:本地上传到远程
# 上传单个文件
scp /path/to/local/file.txt [email protected]:/remote/path/
# 指定 SSH 端口(非默认 22)
scp -P 2222 /path/to/local/file.txt [email protected]:/remote/path/
# 指定私钥
scp -i ~/.ssh/id_rsa /path/to/local/file.txt [email protected]:/remote/path/
# 保留文件属性
scp -p /path/to/local/file.txt [email protected]:/remote/path/
场景二:远程下载到本地
# 下载单个文件
scp [email protected]:/remote/path/file.txt /local/path/
# 下载整个目录
scp -r [email protected]:/remote/path/directory /local/path/
场景三:两台远程服务器直传
不经过本地中转,直接在两台服务器之间传输:
scp user1@host1:/path/to/file user2@host2:/path/to/destination/
这样传输速度是两台远程服务器之间的直连速度,不受本地带宽影响。
场景四:批量上传多个文件
# 使用通配符
scp /local/path/*.txt [email protected]:/remote/path/
# 空格分隔多个文件
scp file1.txt file2.txt file3.txt [email protected]:/remote/path/
场景五:限制带宽传输
大文件传输时避免占满业务带宽:
# 限制带宽为 500KB/s
scp -l 4000 /largefile.tar.gz [email protected]:/remote/path/
注意: -l 参数的单位是 Kbit/s,不是 KB/s。限制 500KB/s 需要设置 -l 4000(500 × 8 = 4000)。
场景六:压缩传输
压缩可以减少传输数据量,对文本文件效果明显,对已压缩文件(.tar.gz、.zip)效果有限:
scp -C /path/to/largefile.tar.gz [email protected]:/remote/path/
实战技巧
使用 SSH Config 简化连接
在 ~/.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
之后可以直接用:
scp file.txt prod-server:/remote/path/
scp prod-server:/remote/file.txt prod-backup:/backup/
传输后验证
# 对比文件大小
ssh user@host "ls -lh /remote/path/file.txt"
ls -lh /local/path/file.txt
# 对比 MD5
md5sum /local/file.txt
ssh user@host "md5sum /remote/file.txt"
二、rsync 详解
基本原理
rsync 的核心优势是增量同步。通过特殊的校验算法,只传输源文件和目标文件之间不同的部分,大大减少网络传输量和同步时间。
支持三种工作模式:
- 本地同步: 在同一个机器上同步目录
- 远程 Shell 同步: 通过 SSH 通道传输(最常用)
- rsync 守护进程同步: 通过 rsync daemon 服务(适合大规模部署)
基本语法
# 本地同步
rsync [选项] 源路径 目标路径
# 远程同步(通过 SSH,最常用)
rsync [选项] 源路径 用户@主机:目标路径
# 从远程同步到本地
rsync [选项] 用户@主机:源路径 本地目标
# 远程同步(通过 rsync daemon)
rsync [选项] 源路径 用户@主机::模块/目标路径
常用参数
| 参数 | 作用 | 说明 |
|---|---|---|
-a |
归档模式 | 等价于 -rlptgoD,保留权限/时间/属主/属组/符号链接/设备文件,推荐使用 |
-v |
显示传输详情 | 显示传输的文件列表和统计信息 |
-z |
压缩传输 | 传输时压缩,减少网络流量 |
-r |
递归同步 | 但不保留权限和时间戳,建议用 -a 替代 |
-P |
进度 + 断点续传 | 等价于 --partial --progress,大文件推荐 |
--delete |
删除多余文件 | 目标端删除源端不存在的文件,双向完全一致 |
--exclude=PATTERN |
排除匹配文件 | 支持多个 --exclude,也支持 --exclude-from=file |
--bwlimit=RATE |
限制带宽 | 单位 KB/s,和 scp 不同(rsync 用 KB/s,scp 用 Kbit/s) |
-n / --dry-run |
模拟运行 | 显示将要传输的文件,不实际执行 |
--remove-source-files |
传输后删除源文件 | 类似 mv,慎用 |
-u / --update |
仅更新较新文件 | 跳过目标端较新的文件 |
--link-dest=DIR |
硬链接增量备份 | 相同文件做硬链接,极省空间 |
--partial |
保留部分传输文件 | 配合 -P 使用 |
实战场景
场景一:本地目录同步
# 归档模式递归同步
rsync -av /source/dir/ /backup/dir/
关于尾部斜杠的要点:
- 加斜杠(
/source/dir/):同步目录内容到目标 - 不加斜杠(
/source/dir):连目录本身一起同步
# 示例对比
rsync -av /data/app/ /backup/app/ # 结果:/backup/app/ 下面直接是文件
rsync -av /data/app /backup/ # 结果:/backup/app/ 下面才是文件
场景二:远程同步到本地
# 通过 SSH 远程同步到本地
rsync -avz user@host:/remote/dir/ /local/dir/
# 指定 SSH 端口(使用 -e 参数)
rsync -avz -e "ssh -p 2222" user@host:/remote/dir/ /local/dir/
场景三:本地同步到远程并删除多余文件
# 备份场景,确保目标端和源端完全一致
rsync -avz --delete /local/dir/ user@host:/backup/dir/
特别适合: 定期备份、镜像同步、灾备切换。
场景四:排除特定文件和目录
# 排除单个模式
rsync -av --exclude='*.log' /src/ /dest/
# 排除多个模式
rsync -av --exclude='*.log' --exclude='cache/' --exclude='tmp/' /src/ /dest/
# 从文件中读取排除规则
rsync -av --exclude-from=exclude.txt /src/ /dest/
exclude.txt 格式示例:
*.log
*.tmp
cache/
node_modules/
.git/
.env
场景五:模拟运行(先看效果再执行)
# 只显示将要传输的文件,不实际执行
rsync -av --dry-run /src/ /dest/
强烈建议: 重要操作之前先用 -n 预览结果。
场景六:断点续传
# -P 等价于 --partial --progress
rsync -avP /largefile.tar.gz user@host:/dest/
传输中断后,重新执行同样的命令即可继续——rsync 会自动识别已传输的部分。
增量同步演示
# 模拟:第一次全部传输
echo "data1" > /tmp/testdata.ext
rsync -avh /tmp/testdata.ext /tmp/backup/
# 输出:sending incremental file list → testdata.ext(第一次,全量)
# 模拟:追加数据后第二次传输
echo "data2" >> /tmp/testdata.ext
rsync -avh /tmp/testdata.ext /tmp/backup/
# 输出:sending incremental file list → testdata.ext(第二次,只传变化部分)
原理: rsync 使用 rolling checksum 算法,将文件切分为固定大小的块(block),逐块校验对比,只传输发生变化的块。
三、scp vs rsync 详细对比
核心差异
| 对比维度 | scp | rsync |
|---|---|---|
| 传输方式 | 全部传输 | 增量传输(只传变化部分) |
| 断点续传 | ❌ 不支持 | ✅ -P / --partial |
| 第一次速度 | 较快(无校验开销) | 较快(算法开销小) |
| 后续速度 | 慢(每次都全量) | 快很多(增量) |
| 压缩传输 | ✅ -C |
✅ -z |
| 带宽限制 | ✅ -l(Kbit/s) |
✅ --bwlimit(KB/s) |
| 排除文件 | ❌ 不支持 | ✅ --exclude |
| 删除同步 | ❌ 不支持 | ✅ --delete |
| 预览模式 | ❌ 不支持 | ✅ -n / --dry-run |
| 保留文件属性 | ✅ -p |
✅ -a(更全面) |
| 语法复杂度 | ⭐ 简单 | ⭐⭐ 中等 |
| 适用场景 | 小文件、临时传输 | 大文件、定期同步、备份 |
性能对比案例
假设源目录有 1000 个文件,其中只有 10 个发生了变化:
| 场景 | scp | rsync |
|---|---|---|
| 1000 个文件,10 个变化 | 传输全部 1000 个 | 只传 10 个 |
| 10GB 文件,修改了 200MB | 传输整个 10GB | 只传 200MB |
| 日常定时同步 | 每次都全量,浪费带宽 | 增量同步,高效执行 |
选择指南
| 场景 | 推荐工具 | 原因 |
|---|---|---|
| 临时拷贝一两个小文件 | scp | 语法简单,一行命令搞定 |
| 大文件(>500MB)传输 | rsync | 支持断点续传,不怕中断 |
| 定期备份/同步 | rsync | 增量同步,配合 cron 高效执行 |
| 大量小文件 | rsync | 先 tar 打包再同步,避免逐个文件握手开销 |
| 两台远程服务器间传输 | scp | 直接直传,无需本地中转 |
| 需要排除某些文件 | rsync | scp 不支持 exclude |
四、实战案例
案例一:日志迁移
需求: 将历史日志文件从生产服务器迁移到备份服务器,控制带宽占用。
#!/bin/bash
# migrate_logs.sh - 日志迁移脚本
SOURCE_USER=root
SOURCE_HOST=192.168.1.100
SOURCE_DIR="/var/log/myapp/archive/"
TARGET_DIR="/backup/logs/myapp/"
# 第一步:先 rsync 同步大部分数据(白天执行,限制带宽)
rsync -avz --bwlimit=5120 \
$SOURCE_USER@$SOURCE_HOST:$SOURCE_DIR \
$TARGET_DIR
# 第二步:业务低峰期(凌晨)做最终增量同步
# (配合 cron 在凌晨 2 点执行)
# rsync -avz $SOURCE_USER@$SOURCE_HOST:$SOURCE_DIR $TARGET_DIR
# 第三步:迁移完成后验证
echo "=== 文件数量对比 ==="
echo "源端:$(ssh $SOURCE_USER@$SOURCE_HOST "find $SOURCE_DIR -type f | wc -l")"
echo "目标:$(find $TARGET_DIR -type f | wc -l)"
echo "=== MD5 抽样校验 ==="
for f in $(ssh $SOURCE_USER@$SOURCE_HOST "ls $SOURCE_DIR | head -5"); do
echo "源端 $f: $(ssh $SOURCE_USER@$SOURCE_HOST "md5sum $SOURCE_DIR$f" | cut -d' ' -f1)"
echo "目标 $f: $(md5sum $TARGET_DIR$f | cut -d' ' -f1)"
done
案例二:零停机代码部署
需求: 使用 rsync 实现零停机代码部署,先同步到测试目录验证,确认无误后切换。
#!/bin/bash
# deploy.sh - 零停机部署脚本
APP_NAME="myapp"
SOURCE_DIR="/data/build/$APP_NAME/"
TEST_DIR="/data/$APP_NAME-test/"
PROD_DIR="/data/$APP_NAME/"
# 1. 同步到测试目录
echo ">>> 同步到测试目录..."
rsync -avz --delete $SOURCE_DIR $TEST_DIR
# 2. 在测试目录执行验证
echo ">>> 执行部署前验证..."
cd $TEST_DIR
# ./run_checks.sh # 自定义验证脚本
# 3. 确认无误后,同步到正式目录
echo ">>> 切换到正式目录..."
rsync -avz --delete $TEST_DIR $PROD_DIR
# 4. 重启服务(按需)
# systemctl restart $APP_NAME
echo ">>> 部署完成"
五、安全注意事项
# 1. SSH 密钥认证(推荐,替代密码)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
ssh-copy-id user@host
# 2. 使用非默认 SSH 端口(降低被扫描风险)
# 服务端 /etc/ssh/sshd_config: Port 22222
# 客户端连接: scp/rsync -e "ssh -p 22222"
# 3. 限制可执行命令
# 在远程用户 ~/.ssh/authorized_keys 中限制:
# command="/usr/bin/rsync --server ..." ssh-ed25519 AAA...
# 4. 排除敏感文件
# .env、*.key、*.pem 等不要传输到不信任的服务器
# 5. 传输日志记录
rsync -av --log-file=/var/log/rsync.log /src/ user@host:/dest/
六、常见问题
1. Connection refused
# 检查远程 SSH 是否运行
ssh -v user@host
# 检查端口
nc -zv host 22
telnet host 22
2. Permission denied
# 检查目标目录写权限
ssh user@host "ls -ld /target/dir"
# 检查密钥权限
chmod 600 ~/.ssh/id_rsa
chmod 700 ~/.ssh
# 检查 authorized_keys
ssh user@host "cat ~/.ssh/authorized_keys | grep your-key"
3. 传输速度慢
# 确认用了压缩
scp -C file user@host:/dest/
rsync -avz file user@host:/dest/
# 检查带宽限制
# scp -l 值可能设太小
# 网络质量排查
mtr host
ping -c 100 host
# 大量小文件时先打包
tar czf - /data/files/ | ssh user@host "tar xzf - -C /dest/"
4. 断点续传
scp 不支持断点续传。传输中断后需要重新传输整个文件。 rsync 天然支持,传输中断后重新执行即可:
rsync -avP /largefile.tar.gz user@host:/dest/
七、传输前中后检查清单
传输前检查
[ ] 确认源文件路径正确
[ ] 确认目标路径存在或有写权限
[ ] 确认 SSH 连接正常(ssh 连接测试)
[ ] 确认目标服务器磁盘空间充足(df -h)
[ ] 确认网络带宽不会影响业务
[ ] 确认传输时间窗口(业务低峰期首选)
传输后验证
# 对比文件数量
echo "源端:$(ssh user@host "find /remote/dir -type f | wc -l")"
echo "目标:$(find /local/dir -type f | wc -l")"
# 对比文件大小
du -sh /local/dir
ssh user@host "du -sh /remote/dir"
# 抽样校验 MD5
for f in file1 file2 file3; do
echo "源端: $(md5sum /local/dir/$f | cut -d' ' -f1)"
echo "目标: $(ssh user@host "md5sum /remote/dir/$f | cut -d' ' -f1")"
done
自动化巡检脚本
配合 cron 实现定期同步检查:
#!/bin/bash
# /etc/cron.daily/check_sync.sh
LOG_FILE="/var/log/sync_check.log"
SOURCE="user@host:/data/"
TARGET="/backup/data/"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] 开始同步检查..." >> $LOG_FILE
# 用 --dry-run 模拟同步,统计需要传输的文件数
CHANGES=$(rsync -avzn --delete $SOURCE $TARGET | wc -l)
if [ $CHANGES -gt 3 ]; then # 减去输出的统计行
echo "⚠️ 发现 $CHANGES 个文件需要同步,执行增量同步..."
rsync -avz --delete $SOURCE $TARGET >> $LOG_FILE 2>&1
echo "✅ 同步完成" >> $LOG_FILE
else
echo "✅ 两端一致,无需同步" >> $LOG_FILE
fi
八、快速参考
日常场景对照
| 你要做什么 | 命令 |
|---|---|
| 上传文件到远程 | scp file user@host:/dest/ 或 rsync -avz file user@host:/dest/ |
| 从远程下载文件 | scp user@host:/file . 或 rsync -avz user@host:/file . |
| 同步整个目录 | rsync -avz /src/ user@host:/dest/ |
| 增量同步(仅更新变化) | rsync -avz /src/ user@host:/dest/ |
| 排除 log 文件同步 | rsync -avz --exclude='*.log' /src/ user@host:/dest/ |
| 断点续传大文件 | rsync -avP /bigfile user@host:/dest/ |
| 限制带宽传输 | scp -l 4000 file user@host:/dest/ |
| 模拟运行看效果 | rsync -avz --dry-run /src/ user@host:/dest/ |
| 远程服务器间直传 | scp user1@h1:/file user2@h2:/dest/ |
| 压缩传输加速 | scp -C file user@host:/dest/ 或 rsync -avz file user@host:/dest/ |
最佳实践总结
- SSH 密钥认证 — 避免每次输入密码,安全又方便
- 重要操作先 dry-run —
rsync -n预览变更,避免误操作 - 设置带宽限制 — 大文件传输时使用
--bwlimit或-l,不影响业务 - 排除敏感文件 —
.env、*.key、*.pem不传不该传的地方 - 记录传输日志 —
rsync --log-file=便于排查和审计 - 验证传输结果 — 文件数量/大小/MD5 三确认
- 大量小文件先打包 —
tar czf - | ssh tar xzf -避免逐个文件握手开销 - 调度在业务低峰期 — 配合 cron 定时执行
关联页面
| 页面 | 关联点 |
|---|---|
| linux-essential-commands-reference | Linux 常用命令手册 |
| linux-compression-tools-comparison | 压缩解压工具对比(tar/gzip/zip) |
| linux-filesystem-directory-structure-guide | Linux 文件系统目录结构 |
| linux-awk-sed-text-processing | awk 与 sed 批量文本处理实战:字段分析/日志统计/配置批量修改/脚本自动化,8大Nginx日 |
| linux-file-transfer-guide | Linux 大文件传输方案选型:五大方案(rsync/scp/nc+tar/split/aria2) |
| ops-automation-scripts | 运维自动化脚本(文件传输在自动化中的典型位置) |