使用LFTP实现跨服务器的数据同步
LFTP是一款功能强大的命令行文件传输客户端程序,支持多种文件传输协议,包括FTP、FTPS、HTTP、HTTPS、SFTP(SSH文件传输)、HFTP和FISH。其设计灵感来源于Shell环境,提供了命令补全、历史记录、多后台任务执行、书签、排队、镜像、断点续传、多线程下载等高级功能。与传统的FTP客户端相比,LFTP在自动化、批处理和高速传输方面表现卓越,尤其适用于服务器管理、批量文件同步和大型数据传输场景。 LFTP核心特性如下 多协议支持:无需切换工具即可访问各类文件服务器。 高性能传输:支持多线程并行传输(pget, mirror --parallel)和断点续传,极大提升传输速度与可靠性。 类Shell操作:支持Tab键命令/参数补全、历史记录、管道操作和后台任务管理,用户体验流畅。 强大的脚本能力:可通过-c、-f选项执行命令脚本,实现全自动化的文件传输流程。 目录镜像同步:mirror命令可高效同步本地与远程目录,是备份和网站部署的利器。 丰富的配置体系:支持系统级和用户级配置文件,可持久化连接参数、编码、线程数等设置。 安装LFTP,大多数Linux发行版的官方仓库都包含LFTP。
# Debian/Ubuntu:
sudo apt update && sudo apt install lftp
# RHEL/CentOS/Fedora:
# 需要先启用EPEL仓库(CentOS/RHEL)
sudo yum install epel-release
sudo yum install lftp
# macOS:可通过Homebrew安装:brew install lftp。
常用选项
-u:指定用户名和密码
-e:打开连接后执行命令
-f:使用脚本文件执行命令
-c:启动 LFTP 并直接运行命令(无需进入交互模式)
--parallel:启用多个并行连接以提高下载/上传速度
-p:为 FTP 或 SFTP 服务器设置自定义端口
常用子命令
open:打开与服务器的连接
ls:列出远程服务器上的文件和目录
cd:更改远程服务器上的目录
get:从远程服务器下载文件
put:将文件上传到远程服务器
mget:下载多个文件
mput:上传多个文件
mirror:镜像(同步)目录
exit:退出 LFTP 会话
set:设置各种 LFTP 选项(例如速度限制)
-u username,password:指定用户名和密码
-e "command":连接后执行单个命令
今天我们主要讲通过mirror来实现数据的同步功能,mirror的参数主要如下
将源文件夹镜像到目标文件夹。如果目标文件夹以/结尾,原文件夹名称会被附加到目标文件夹名称之后。源和目标都可以是指向文件夹的URL,命令格式如下:
mirror [OPTS] [source [target]]
其中mirror命令的参数如下:
-a 与--allow-chown –allow-suid –no-umask相同
-c, --continue 续传上次的任务
-e, --delete 删除远程目录上不存在的文件
--delete-first 在传输新文件之前删除旧的文件
--depth-first 进入下一层目录优先于文件传输
-s, --allow-suid 根据远程站点设置suid/sgid比特位
--allow-chown 尝试将自己设置为文件所有者和所有组
--ascii 使用ascii方式传输(隐含了–ignore-size)
--ignore-time 决定是否下载时忽略时间因素
--ignore-size 决定是否下载时忽略文件大小因素
--only-missing 只下载缺少的文件
--only-existing 只下载已经存在于目标文件夹中的文件
-n, --only-newer 只下载新文件(-c参数无法工作)
--no-empty-dirs 不创建空文件夹(隐含了–depth-first)
-r, --no-recursion 不进入子文件夹
--no-symlinks 不创建符号链接
-p, --no-perms 不设置文件权限
--no-umask 不使用文件预设权限
-R, --reverse 反向镜像(上传文件)
-L, --dereference 将符号链接作为 文件下载
-N, --newer-than=SPEC 只下载比指定时间晚的文件
--on-change=CMD 只要有文件或文件夹存在差异就执行命令CMD
--older-than=SPEC 只下载比指定时间早的文件
--size-range=RANGE 只下载大小在指定区间上的文件
-P, --parallel[=N] 并行下载N个文件
--use-pget[-n=N] 使用pget传输每个文件
--loop 循环知道找不到差异
-i RX, --include RX 包括相匹配的文件
-x RX, --exclude RX 不包括相匹配的文件
-I GP, --include-glob GP 包括相匹配的文件
-X GP, --exclude-glob GP 不包括相匹配的文件
-v, --verbose[=level] 冗长操作, 显示详细过程
--log=FILE 将执行的lftp命令写入文件FILE
--script=FILE 将lftp命令写入文件FILE,但不执行
--just-print, –dry-run 与–script=-相同
--use-cache 使用缓存目录列表
--Remove-source-files 传输完成后删除源文件
下面是一个示例,通过SFTP登录到sync.example.com服务器,将/opt/html目录下的内容和本地的/opt/html进行同步,排除admin目录下所有文件,显示详细过程,删除远程目录上不存在的本地文件,只下载新文件,具体命令如下:
lftp -u "root","mypassword" sftp://sync.example.com:22 -e "
set sftp:auto-confirm yes
lcd /opt/html
mirror -x ^admin/$ --verbose --delete --only-newer /opt/html /opt/html;
bye
可以将该命令放置在一个shell脚本中,然后通过crontab定时任务调度实现定时执行该脚本。
首先,建立一个/opt/sync_data.sh的脚本内容如下:
#!/bin/bash
# 网站同步备份脚本
# 使用lftp通过SFTP同步远程服务器文件
# 服务器配置
HOST="sync.example.com"
USER="root"
PASS='mypassword'
PORT="22"
# 目录配置
RCD="/opt/html"
LCD="/opt/html"
LOG_FILE="/opt/sync.log"
# 临时文件用于捕获错误信息
TEMP_ERROR_FILE="/tmp/lftp_error_$$.log"
# 日志记录函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# 检查重要命令 lftp 是否安装,未安装则安装
if ! command -v lftp &> /dev/null; then
log "必需的命令 lftp 未安装,开始安装lftp……"
sudo apt-get install -y lftp >>/dev/null 2>&1
log "lftp 安装完成"
fi
# 检查ssh-keygen是否可用
if ! command -v ssh-keygen &> /dev/null; then
log "警告: ssh-keygen 命令不可用,如果遇到主机密钥问题将无法自动处理"
fi
# 清理已知主机密钥函数
clean_known_hosts() {
local host="$1"
local port="$2"
log "检测到服务器主机密钥变化,清理旧的known_hosts记录..."
ssh-keygen -f "/root/.ssh/known_hosts" -R "[$host]:$port" >/dev/null 2>&1
ssh-keygen -f "/root/.ssh/known_hosts" -R "$host:$port" >/dev/null 2>&1
ssh-keygen -f "/root/.ssh/known_hosts" -R "$host" >/dev/null 2>&1
# 等待一下确保清理完成
sleep 1
}
# 禁用严格主机密钥检查(备选方案)
disable_strict_host_check() {
if [ ! -f ~/.ssh/config ]; then
mkdir -p ~/.ssh
touch ~/.ssh/config
chmod 600 ~/.ssh/config
fi
# 为特定主机禁用严格主机密钥检查
if ! grep -q "Host *$HOST*" ~/.ssh/config; then
echo "Host $HOST" >> ~/.ssh/config
echo " StrictHostKeyChecking no" >> ~/.ssh/config
echo " UserKnownHostsFile /dev/null" >> ~/.ssh/config
echo " LogLevel ERROR" >> ~/.ssh/config
log "已为 $HOST 禁用严格主机密钥检查"
fi
}
# 执行同步函数
# -x ^admin/$ 用于排除admin目录。
perform_sync() {
# 使用临时文件捕获错误输出 --log=$LOG_FILE
{
lftp -u "$USER","$PASS" sftp://$HOST:$PORT -e "
set sftp:auto-confirm yes
lcd $LCD
mirror -x ^admin/$ --verbose --delete --only-newer $RCD $LCD;
bye
"
} >> "$LOG_FILE" 2>&1
return $?
}
log "开始启动全站同步,主服务器$HOST ……"
# 尝试执行同步,如果失败则处理主机密钥问题
max_retries=2
retry_count=0
success=0
while [ $retry_count -le $max_retries ] && [ $success -eq 0 ]; do
log "尝试同步 ($((retry_count + 1))/$((max_retries + 1)))..."
# 执行同步并捕获输出
sync_output=$(perform_sync 2>&1)
sync_exit_code=$?
# 记录输出到日志
echo "$sync_output" >> "$LOG_FILE"
if [ $sync_exit_code -eq 0 ]; then
log "全站同步已完成。"
success=1
else
log "同步过程出现错误 (退出码: $sync_exit_code)"
# 检查错误信息中是否包含主机密钥相关的关键词
if echo "$sync_output" | grep -q -E "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED|Host key verification failed|Host key for.*has changed"; then
log "检测到主机密钥验证失败错误"
if command -v ssh-keygen &> /dev/null; then
log "清理known_hosts并重试..."
clean_known_hosts "$HOST" "$PORT"
retry_count=$((retry_count + 1))
sleep 2
continue
else
log "ssh-keygen不可用,无法自动清理known_hosts"
break
fi
elif [ $retry_count -eq 0 ]; then
# 第一次遇到其他错误,尝试禁用严格主机密钥检查
log "尝试禁用严格主机密钥检查..."
disable_strict_host_check
retry_count=$((retry_count + 1))
sleep 2
continue
else
# 其他类型的错误
log "同步失败,错误信息:"
echo "$sync_output" | tail -5 | while read line; do log " $line"; done
break
fi
fi
done
# 清理临时文件
rm -f "$TEMP_ERROR_FILE"
if [ $success -eq 1 ]; then
log "同步成功完成。"
exit 0
else
log "同步失败,已达到最大重试次数。"
log "建议手动执行以下命令清理known_hosts记录:"
log "ssh-keygen -f \"/root/.ssh/known_hosts\" -R \"[$HOST]:$PORT\""
log "或者检查服务器连接和认证信息。"
exit 1
fi
其次,使用crontab命令编辑当前用户的定时任务表,设置为每10分钟运行一次同步脚本。
#输入
crontab -e
#最最下面增加下面的这一行
*/10 * * * * /opt/sync_data.sh >> /opt/sync.log 2>&1
若你在使用过程中有任何问题,也可以通过页面底部的反馈留言与我联系。 |