服务器文件传输scp和rsync的用法

描述

背景与适用场景

在服务器运维工作中,经常需要在本地机器和远程服务器之间、或者两台服务器之间传输文件。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"

 

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分