ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

lftp实战:断点续传与镜像同步,搞定服务器间文件迁移

lftp实战:断点续传与镜像同步,搞定服务器间文件迁移 做服务器间的文件传输很多人第一反应就是用scp或者干脆套用rsync。我见过不少同事把scp当成万能工具传大文件传一半断线了就得从头再来传海量小文件更是慢到让人怀疑硬盘是不是坏了。今天想认真聊聊lftp这个老牌工具——它看起来其貌不扬但真正解决了我大量服务器间文件同步、迁移和备份的痛点。这篇文章会从为什么选它、基础命令怎么用、镜像同步实战到自动化脚本和问题排查完整分享我在这套方案里的操作习惯。适合搞运维、做部署、搭备份的同学直接对照实践。1. 服务器间传输为什么我最后选了lftp1.1 日常服务器间传文件的几个老大难先说场景。搞过生产环境的都知道服务器和服务器之间传文件从来不只是“把文件拷过去”那么简单。我这边最常见的三类问题第一文件大、链路不稳。数据库备份、日志压缩包、媒体资源动辄几十 GB。网络一抖scp直接断掉没有续传能力又得重传一遍。短时间还好几十 GB 的文件重传一次就是几十分钟甚至几小时。第二目录结构复杂需要增量同步。站点目录里可能有几十万个文件有静态资源、动态脚本、临时缓存。每次都全量传递服务器I/O和带宽根本吃不消。这时候需要的是“只把新增和变更的文件传过去”。第三环境受限没法装额外软件。两台服务器之间可能只有传统的 FTP 服务或者只能走 SSH/SFTP 通道其中一台还是精简系统rsync都没装。你要么装半天依赖要么就得找一种“只装客户端就能干活”的工具。这些痛点堆在一起scp应付不了rsync倒是能解决一部分但受限于“两端都得有 rsync”、以及遇到非 SSH 协议时的尴尬。最后我把方案定在lftp上是因为它把这些情况都覆盖了。1.2 lftp在传输方案里的定位和取舍lftp是一个类 Unix 系统下的文件传输程序支持 FTP、SFTP、HTTP、HTTPS、FTPS 等一堆协议。它最出名的是三件事断点续传、并发传输、镜像同步。断点续传传大文件中断了用-c参数接着传不用重新开始。并发传输一个文件可以用多个连接分段下载一堆小文件也可以并行传。镜像同步内置mirror命令能递归比对远端和本地的目录差异然后增量同步行为类似rsync。它更讨喜的地方在于绝大部分场景下只需要在本地安装lftp一个客户端对端只要有对应的服务协议FTP 服务或者系统自带 SSH/SFTP 服务就能工作不需要对端额外装任何插件。对比一下更直观方案断点续传增量同步多协议支持对端依赖scp不支持不支持基本只有 SSH需要 SSH 服务rsync部分支持支持通常走 SSH也支持rsync daemon两端都要有 rsynclftp支持支持FTP/SFTP/HTTP/FTPS只要目标服务能连上ftp命令不支持不支持只有 FTP需要 FTP 服务打个比方scp像一次性把所有箱子搬上车途中掉一个就得全部卸下来重来rsync像带着一个盘点表去仓库只拿走缺的货但它要求两边仓库管理员都认识你而lftp像是自带麻绳和清单的老手不管对面是什么仓库只要能开门它就能断点续搬、多线程搬、增量搬。所以我的结论是如果两台服务器都能装rsyncrsync在纯增量同步和本地文件校验上确实更强但如果你要传超大文件、目标端只有 FTP、或者不想在对端做任何安装操作lftp就是更省心的选择。甚至后来很多批次发布任务我也直接用它来做因为一条mirror命令就可以完成全量/增量切换避免维护两套脚本。2. lftp基础操作与关键配置2.1 安装和.lftprc初始化安装lftp很简单。我在 CentOS/RHEL 上习惯用yum install -y lftpUbuntu/Debian 上apt-get install -y lftpmacOS 有 Homebrew 的话也可以brew install lftp。装完先别急着连建议先写一个.lftprc配置文件放在家目录下把常用的网络参数固化下来避免每次敲一堆set命令。我常用的.lftprc示例set net:timeout 15 set net:max-retries 3 set net:reconnect-interval-base 5 set ftp:passive-mode on set ssl:verify-certificate no set mirror:parallel-transfer-count 4 set mirror:use-pget-n 1逐条说下我的理解net:timeout 15控制每次连接或操作的最长等待时间。网络质量差时如果不设这个lftp 可能一直卡着日志看起来像死掉了一样。net:max-retries 3操作失败后的重试次数。我一般设 3 次配合断点续传已经很稳。net:reconnect-interval-base 5重连的基础等待时间如果连续失败会按倍数退避避免短时间内反复重试打爆服务端。ftp:passive-mode on主动/被动模式的开关。绝大多数外网环境的 FTP 服务都要求被动模式默认开启它省去很多“连得上但列不出目录”的烦恼。ssl:verify-certificate no关闭证书强校验。我知道很多人会担心安全问题但在内网环境自签证书的场景太普遍了开着校验反而连不上。如果有条件做正规证书建议保留校验。mirror:parallel-transfer-count 4mirror 命令并行传输的默认连接数。mirror:use-pget-n 1mirror 时每个文件默认使用多少个连接分段下载。设 1 表示每个文件单连接避免对小文件也启动多连接反而拖慢速度。配置文件写好后可以用lftp -e set ...临时覆盖也可以直接改.lftprc永久生效。建议对批量服务器做同步任务时公共参数统一放.lftprc任务相关的参数在脚本里显式指定这样既灵活又清晰。2.2 最常用的连接与上传下载命令连接服务器我习惯用lftp sftp://user10.0.0.5 -p 22回车后它会提示输入密码。如果需要自动化可以在连接命令里带密码lftp -u user,password sftp://10.0.0.5:22但说实话这种把密码直接写在命令行的方式在history里会留痕生产环境不建议这么做。我一般更推荐两种方案一种是把登录信息写到~/.netrcmachine 10.0.0.5 login user password yourpassword然后 lftp 连接时会自动读取不用每次输入。另一种是走 SSH 密钥也是我目前主要用的方式后面自动化章节会详细讲。进入 lftp 交互环境后常用的命令和本地 shell 很像而且支持Tab补全命令作用ls/cd查看/切换远端目录lcd切换本地目录get下载单个文件put上传单个文件mget批量下载mput批量上传pget多线程分段下载!执行本地 shell 命令单文件断点续传是我最常用的功能比如get -c /backup/appdb_full_20250601.sql.gz加了-c后如果网络断了再执行一次它会从断点处继续下载。put -c同理上传大文件时很管用。pget是多线程下载适合那种特别大的单个文件pget -n 8 -c /backup/large_archive.tar.gz-n 8表示开 8 个连接分段下载同一个文件。注意pget的多线程能力依赖远端 FTP 服务支持多连接读取如果服务端做了单 IP 并发限制分段太多反而容易被限流。批量上传时我常用mputmput /data/logs/*.log这个命令会把匹配的文件传到当前远端目录。批量下载则用mget。还有一个容易被忽略的!命令可以在不退出 lftp 的情况下执行本地操作比如先本地建目录lcd /data/backups !mkdir -p /data/backups说实话这些命令单独看都不复杂难的是组合。实战里真正让我觉得 lftp 不可替代的还是它的mirror镜像同步能力下一章展开聊。3. 核心实战用mirror实现服务器间目录镜像同步3.1 mirror命令的两种方向与参数拆解mirror命令是 lftp 做服务器间文件同步的核心。它的基本逻辑是递归对比远端和本地目录的差异然后按参数决定是下载新增、上传变更还是删除多余文件。我最常用的两种方向# 下载方向把远端目录同步到本地 lftp -u user,pass sftp://10.0.0.5 EOF mirror /data/publish /data/replica quit EOF# 上传方向把本地目录同步到远端 lftp -u user,pass sftp://10.0.0.5 EOF mirror -R /data/replica /data/publish quit EOF注意-R参数表示 Reverse上传方向。没有-R就是下载方向。这个搞反了后果很严重尤其是带--delete的时候会把目标端的文件删掉。mirror的常用参数我整理成了一张表参数作用常用场景--parallelN同时传 N 个文件大量小文件分发--only-newer只同步比目标端新的文件增量同步--delete删除目标端多余文件完整镜像两端一致--exclude排除匹配的文件/目录跳过缓存目录、日志--verbose打印每个文件处理结果调试和审计--logFILE输出详细日志到文件日常任务留痕--use-pget-nN每个文件用 N 个连接少数大文件场景--continue/-c失败后继续上次传输不稳定网络增量同步我一般用--only-newer它会比较文件修改时间只传输远端比本地新或本地比远端新的文件。前提是两个服务器时间尽量一致否则时间戳判断会出错。我吃过这个亏一台机器时区没同步同步回来的文件全是“新文件”跑了整整一夜。后来我把所有服务器都统一走 NTP 时间同步问题才消停。全量镜像则用--delete比如发布目录需要和代码仓库目录完全一致本地已经删掉的旧文件远端也要删。不过这个参数我建议永远配合--dry-run先用一遍确认没问题再真的跑。--dry-run会模拟一遍同步过程告诉你哪些文件会被上传、下载、删除但不会真正操作文件。3.2 一个真实的双机备份同步案例举个例子我之前管过一批应用服务器生产节点有一台内网机房有一台备份机。每天晚上需要把生产节点上的发布目录/opt/app/webroot增量同步到备份机的/data/backup/webroot。当时生产节点连的是 SFTP 服务我写了一个这样的 lftp 命令lftp -u appbackup,xxxxxx sftp://10.0.2.20 EOF set net:timeout 20 set net:max-retries 3 cd /data/backup mirror --parallel4 --only-newer --verbose --log/var/log/lftp_webroot.log /opt/app/webroot /data/backup/webroot quit EOF注意这里我用了cd /data/backup是为了确保远端工作目录正确。mirror后面的源路径是远端路径目标路径是本地路径。因为这是下载方向所以远端在左边本地在右边。如果是上传方向源路径写到-R后面本地在左、远端在右顺序别搞反。第一次执行我建议先跑一遍全量镜像mirror --parallel4 --verbose /opt/app/webroot /data/backup/webroot让目标目录结构完全建立起来。从第二次开始加上--only-newer做增量速度非常快基本上几秒到几十秒就结束。因为增量阶段只需要比对文件时间和大小。这里还有一个小细节--only-newer其实还会判断文件大小只有当时间或者大小有变化时才会重新传输。我测试过如果时间变了但大小没变它也会重新传但如果时间没变大小变了是否会传取决于具体版本实现。为了保险涉及关键配置文件的同步我通常会在目标端额外跑一次校验脚本对关键文件比对 md5。整个过程中最怕的是断网。lftp 呢好在有--continue即使同步到一半断了重新跑同一条命令它会自动跳过已经完成的文件继续剩下的。配合net:max-retries和net:reconnect-interval-base我见过一条同步任务在连续断线三次后自己恢复最后完整跑完。3.3 排除目录和文件的高级用法生产目录里总有不需要同步的东西。比如runtime/cache这类临时缓存目录*.log日志文件.git目录如果每次都把这几类数据同步过去增量同步的优势会被拖垮。这时候用--excludemirror --only-newer --exclude runtime/cache --exclude *.log --exclude .git/ /opt/app /data/backup/app注意写法规则的匹配基准是相对于同步根目录的路径--exclude可以重复使用一次排除一个模式。这里有个容易踩的坑排除日志文件时如果写--exclude *.log它只匹配文件名后缀为.log的文件但不会排除logs/整个目录。如果日志目录里全是.log文件这个规则倒也能达到效果但如果里面还有.txt之类的文件就得再补一条--exclude logs/。我一般习惯把目录排除写得更明确比如--exclude /logs/两端都带斜杠避免误排除同名路径。还有一个实用技巧--exclude-glob和--exclude-from。--exclude-from可以指定一个文件列表每行一个排除规则适合规则特别多的场景。比如我在一个项目里整理了二十多条排除规则没有堆在命令行里而是放在/etc/lftp_exclude.list中命令写成mirror --exclude-from/etc/lftp_exclude.list /opt/app /data/backup/app这样维护起来清晰得多而且可以放到版本控制里团队协作也方便。4. 把同步脚本化免密登录、定时调度与日志4.1 SSH密钥免密登录与安全实践自动化之前必须先解决免密问题。如果脚本里直接写明文密码或者靠交互输入定时任务根本跑不起来。我主要用 SSH 密钥方式。在调度机也就是执行同步脚本的这台上ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_lftp -N 把公钥拷到目标服务器上ssh-copy-id -i ~/.ssh/id_rsa_lftp.pub user10.0.2.20如果目标服务器没有ssh-copy-id也可以手动把公钥追加到目标机器的~/.ssh/authorized_keys文件里。然后测试ssh -i ~/.ssh/id_rsa_lftp user10.0.2.20能免密登录说明密钥配置成功。lftp 走 SFTP 协议时底层调用的就是本机ssh命令。所以只要 SSH 本身能免密lftp 也就能免密。但有些环境的默认 SSH 参数会触发 host key 交互确认脚本里就卡住了。我在 .lftprc 里用一行配置解决set sftp:connect-program ssh -a -x -o StrictHostKeyCheckingno -i /root/.ssh/id_rsa_lftp意思是不用代理、不转发 X11、不交互验证 host key、指定密钥文件。如果你有多个目标服务器更优雅的做法是在~/.ssh/config里按 Host 配置好密钥和参数然后 lftp 连接时直接用别名比如lftp sftp://backup-server这里的backup-server就是~/.ssh/config里配置的 Host 别名。这种方式最干净脚本里连 IP、用户名、密钥都不用写所有连接细节都收敛在 SSH 配置里。4.2 一键同步脚本示例与定时任务配置自动化脚本我一般写成这样放在/opt/scripts/lftp_sync_webroot.sh#!/bin/bash LOCK_FILE/tmp/lftp_sync_webroot.lock LOG_DIR/var/log/lftp_sync LOG_FILE${LOG_DIR}/webroot_$(date %Y%m%d_%H%M%S).log SRC_USERappbackup SRC_HOST10.0.2.20 SRC_DIR/opt/app/webroot DST_DIR/data/backup/webroot mkdir -p ${LOG_DIR} # 防止任务重复执行 if [ -f ${LOCK_FILE} ]; then echo $(date %F %T) 另一个同步任务还在运行跳过本次执行 ${LOG_FILE} exit 1 fi touch ${LOCK_FILE} trap rm -f ${LOCK_FILE} EXIT # 连接参数放在 .lftprc 里命令参数在这里显式控制 lftp -u ${SRC_USER} sftp://${SRC_HOST} EOF ${LOG_FILE} set net:timeout 20 set net:max-retries 3 mirror --parallel4 --only-newer --delete --exclude-from/etc/lftp_exclude.list --verbose ${SRC_DIR} ${DST_DIR} quit EOF # 清理超过 30 天的日志 find ${LOG_DIR} -name *.log -mtime 30 -exec rm -f {} \;几个关键点加了锁文件避免 crontab 执行周期重叠。如果上一个任务还没跑完新任务直接退出防止多个 lftp 进程同时访问同一个目录造成混乱。trap保证脚本无论正常退出还是异常退出锁文件都会被清理。我一开始没加这行结果一次同步卡死锁文件残留后续任务全被拒之门外排查了半天。每次执行生成独立日志按日期命名方便回溯。日志只保留 30 天避免服务器磁盘被日志占满。别小看这个lftp 的--verbose日志在几十万小文件同步时一天能写几百 MB。然后配置 crontab0 2 * * * /opt/scripts/lftp_sync_webroot.sh /dev/null 21凌晨 2 点执行避开业务高峰期的带宽占用。如果同步量大可以再加一个错峰参数让不同任务间隔半小时跑。4.3 同步脚本的执行结果判断与告警脚本跑完怎么知道成没成我习惯在 lftp 命令执行后直接判断退出码if [ $? -eq 0 ]; then echo $(date %F %T) 同步完成 ${LOG_FILE} else echo $(date %F %T) 同步失败请检查 ${LOG_FILE} fi但这里注意lftp 的退出码并不总是可靠的。有时候连接断了但镜像命令局部失败进程退出码依然可能为 0。所以更稳的做法是检查日志里是否有错误关键字比如Failure、Error、Fatalif grep -iE fatal|error|failure ${LOG_FILE} /dev/null 21; then echo 同步异常 ${LOG_FILE} fi我甚至会解析mirror生成的统计信息。mirror --verbose结束时lftp 会打印类似“文件传输完成”的统计行。把它抓到后可以确认本次传输了多少文件、多少字节再决定要不要后续校验。告警这块最朴素的做法是发邮件。脚本里加一行mail -s lftp同步失败: webroot opsexample.com ${LOG_FILE}也可以用 curl 调 Webhook 推送到企业微信或者钉钉。我个人实践是白天跑的任务才告警凌晨备份任务失败就等上班再看日志夜里不打电话、不发短信不然早就被骚扰疯了。5. 实战中常见的坑与排查实录5.1 中文文件名乱码问题中文文件名在服务器间传输是高频问题。如果远端是 Windows 上的 FTP 服务或者某些传统 Unix 系统使用 GBK 编码而本地的 lftp 默认按 UTF-8 处理你会看到一堆乱码甚至文件名直接变成问号。解决办法是在连接时指定字符集set ftp:charset GBK set file:charset UTF-8意思是“远端传输用 GBK 编码本地文件系统用 UTF-8 编码”。lftp 会在两端做自动转换。如果是纯 Linux 到 Linux 的环境一般不会遇到这个问题我遇到的大多是对接 Windows FTP 服务、或者老系统导出的文件名时才需要加这两行。还有一个相关坑某些文件系统不区分大小写但远端区分。同步时如果本地生成了Test.txt和test.txt在目标端就会互相覆盖。这种情况mirror本身不会报错但你会莫名丢文件。我的建议是文件命名规范里强制小写从源头规避。5.2 连接超时、断线重传与并发限制超时是拿 lftp 做定时同步最常碰到的问题。表现是日志里出现Timeout命令挂起很久然后失败。我排查超时的思路按顺序查网络层先ping目标机器再看端口通不通。服务端配置如果是 FTP检查服务端超时时间。如果服务端设置了 30 秒无操作就断开而你的同步任务恰好需要较长时间扫描目录就会断。lftp 参数把net:timeout调大一点并开启自动重试。推荐一组稳妥参数set net:timeout 30 set net:max-retries 5 set net:reconnect-interval-base 3 set net:reconnect-interval-multiplier 2 set net:reconnect-same-server yes这里的退避逻辑是连接失败后先等 3 秒第二次等到 6 秒第三次 12 秒以此类推最多重试 5 次。这个参数组合能扛住大多数网络抖动。并发限制这个问题也分享一个实际案例。我曾经在一台老的 FTP 服务器上跑mirror --parallel10结果同步还没开始服务端直接返回421 Too many connections。一开始以为是服务器挂掉了后来发现是被 lftp 的并发连接打爆了。解决方式很简单把--parallel降到 2 或 3同时去掉--use-pget-n让每个文件单连接传输。对于老服务器稳定比速度更重要。5.3 --delete误删风险与dry-run的必要性这个必须单独拎出来说。--delete是 mirror 命令里最危险的参数。它不只是“删除目标端多余文件”而是会让目标端完全镜像源端。如果你写反了方向比如本来想下载同步结果不小心写成mirror -R --delete 本地 远端远端会被清成和本地一模一样后果不堪设想。我有一次就差点出事。做发布同步时本地目录是临时解压出来的里面少了一个子目录。因为加了--delete如果真跑起来远端对应子目录会被整个删掉。后来我养成了一个习惯任何第一次使用的同步命令先加--dry-run跑一遍mirror -R --delete --dry-run --verbose /data/publish /data/wwwroot--dry-run会列出所有将要执行的操作但不会真正改动文件。我会看两遍第一遍扫一眼有没有意外的 delete 操作第二遍确认 transfer 的文件数量和预期一致。没问题后再真正执行。如果实在不放心上传方向加--exclude把关键目录保护起来比如--exclude /database_backups/同时在脚本里先做一次目标端的快照存档哪怕万一手滑至少能回滚。5.4 时间戳漂移导致的增量误判--only-newer依赖文件时间戳判断是否需要同步。如果两台服务器的时间不一致时间戳漂移会让 lftp 产生两种误判源端时间比目标端晚导致本来没变过的文件每次都被当作新文件重新同步。源端时间比目标端早导致真正更新过的文件反而不被同步。排查方法很简单在两端各自执行date看时间差是否在合理范围内。解决方法是统一 NTP 时间同步。配置好系统级时间同步后这个问题基本消失。如果是线下环境没法连外网 NTP也可以用内网搭建一个时间服务器把各节点都指向它。我强烈建议在做增量同步前先把所有服务器的时区和时间统一了不然后患无穷。还有一种情况某些应用发布文件时会保留原文件的 mtime而文件内容实际已经变了。此时--only-newer会漏同步。遇到这种场景我会改用--only-missing先兜底或者直接定期做一次全量同步。全量同步虽然慢一点但能保证一致性。5.5 我的一些经验和后续拓展思路如果让我总结 lftp 使用心得我最想说的一句话是别贪快先保证不断。--parallel不是越大越好--use-pget-n不是每个文件都值得开。大文件用多线程小文件靠并行文件数这个度需要根据你的实际服务端能力和带宽来调。我一般是从 2 开始逐步往上加找到稳定的临界点。至于后续扩展lftp 的能力不止服务器间同步。我还在用它做远程下载大文件的任务队列配合queue命令一次排队一批任务也尝试过用它做多种协议之间的中转拉取比如从 HTTP 抓取文件再推送到 SFTP 服务器。它就像一个低调但功能齐全的瑞士军刀很多地方都能派上用场。如果你只是把它当“加强版 ftp”用那就真的小看它了。
返回列表