我为本地网络经常使用的存储库做一些夜间和每周镜像。有几次,有人试图在 rsync 发生时进行更新但失败了,因为预期的文件还没有全部出现。
是否可以执行 rsync 以便所有更改的文件仅在完成时以正确的名称出现?我知道 rsync 在每次传输过程中使用临时 .hidden 文件,但是我可以推迟重命名直到它以某种方式完成吗?
或者,我似乎可以使用 --backup 选项将所有更改移动到一个目录并在之后自动移动它们,但我希望该功能与现在的功能相反。
我在 Linux 上是因为它的价值。
您可以使用该--link-dest=选项。基本上你会创建一个新文件夹,所有文件都硬链接到新文件夹。一切都完成后,您只需交换文件夹名称并删除旧文件夹名称即可。
在 Linux 中不可能做到 100% 原子性,因为它没有内核/VFS 支持。然而,交换名称实际上只需要 2 个系统调用,所以它应该花费不到 1 秒的时间来完成它。只有在 Darwin (MAC/OSX) 上才有可能在 HFS 文件系统上使用 exchangedata 系统调用。
我对rsync备份 [到磁盘]做了一些类似的事情,由于在备份运行时守护进程更新文件,我遇到了同样的问题。
与许多程序不同,rsync 有许多不同的错误代码 [参见手册页底部]。感兴趣的是两个:
23 -- 由于错误而部分传输
24 -- 由于源文件消失而部分传输
当 rsync 进行传输并遇到其中一种情况时,它不会立即停止。它跳过并继续它可以传输的文件。最后,它显示了返回码。
因此,如果您收到错误 23/24,只需重新运行 rsync。随后的运行会更快,通常只是传输上一次运行中丢失的文件。最终,你会[或应该得到]一个干净的运行。
至于原子性,我在传输过程中使用了“tmp”目录。然后,当 rsync run 干净时,我将其 [原子地] 重命名为<date>
我也使用这个--link-dest选项,但我用它来保持增量备份(例如--link-dest=yesterday每天)
虽然我自己没有使用过它,但它--partial-dir=DIR可以防止隐藏文件弄乱备份目录。确保 DIR 与您的备份目录在同一文件系统上,因此重命名将是原子的
当我在 perl 中执行此操作时,我编写了一个脚本,针对您的特定情况,以更详细/更精确的方式总结了我所说的内容。它采用类似 tcsh 的语法,[未经测试且有点粗糙],但将其视为伪代码,可以根据需要编写自己的bash, perl,python脚本。请注意,它对重试没有限制,但您可以根据自己的意愿轻松添加。
#!/bin/tcsh -f
# repo_backup -- backup repos even if they change
#
# use_tmp -- use temporary destination directory
# use_partial -- use partial directory
# use_delta -- make delta backup
# set remote server name ...
set remote_server="..."
# directory on server for backups
set backup_top="/path_to_backup_top"
set backup_backups="$backup_top/backups"
# set your rsync options ...
set rsync_opts=(...)
# keep partial files from cluttering backup
set server_partial=${remote_server}:$backup_top/partial
if ($use_partial) then
set rsync_opts=($rsync_opts --partial-dir=$server_partial)
endif
# do delta backups
if ($use_delta) then
set latest=(`ssh ${remote_server} ls $backup_backups | tail -1`)
# get latest
set delta_dir="$backup_backups/$latest"
if ($#latest > 0) then
set rsync_opts=($rsync_opts --link-dest=${remote_server}:$delta_dir)
endif
endif
while (1)
# get list of everything to backup
# set this to whatever you need
cd /local_top_directory
set transfer_list=(.)
# use whatever format you'd like
set date=`date +%Y%m%d_%H%M%S`
set server_tmp=${remote_server}:$backup_top/tmp
set server_final=${remote_server}:$backup_backups/$date
if ($use_tmp) then
set server_transfer=$server_tmp
else
set server_transfer=$server_final
endif
# do the transfer
rsync $rsync_opts $transfer_list $server_transfer
set code=$status
# run was clean
if ($code == 0) then
# atomically install backup
if ($use_tmp) then
ssh ${remote_server} mv $backup_top/tmp $backup_backups/$date
endif
break
endif
# partial -- some error
if ($code == 23) then
continue
endif
# partial -- some files disappeared
if ($code == 24) then
continue
endif
echo "fatal error ..."
exit(1)
end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3296 次 |
| 最近记录: |