楚狐在线 - 资讯杂烩
资讯杂烩   在线工具   益智游戏   影音娱乐   网站导航

使用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

  若你在使用过程中有任何问题,也可以通过页面底部的反馈留言与我联系。

返回首页    发布日期:2025年12月06日

Copyright © 2026  楚狐在线  All Rights ReservedLA反馈留言  友情赞助