我有一个目录,它经常更改,但其文件是相关的。我想将rsync
其保存到远程位置,以确保我在远程位置始终拥有一套完整的文件。也就是说,如果我有一个完整的备份,我希望将其保存到我有第二个完整的备份,以确保任何网络中断都不会破坏第一个备份的完整性。如果你仔细想想,这是--backup
行不通的,因为不清楚未备份的文件是第一个完整备份的一部分,还是第二个不完整备份的一部分。
虽然我想要做的事情是可以编写脚本的,但我认为肯定有现成的解决方案。我知道rdiff-backup
可以做到这一点,回滚部分备份,但我无法在目标机器上安装它。有人有其他线索吗?
答案1
如果您使用打开的文件(如数据库),直接读取rsync
可能不是一个好主意,因为rsync
它不会自动读取数据库中所有文件的所有块。最原子的方式需要一个启用了快照的系统。这需要一个专用分区,或像或 这样lvm
的文件系统。当对分区进行快照时,您可以自由地处理一组稳定的文件。 可用于制作远程应用程序btrfs
zfs
rsync
--delay-updates
更多的原子。
答案2
显然,正确的术语是我想要一个“原子”备份。页面--delay-updates
中的开关被称为man
“更原子”,在最后执行所有删除和移动。它对我来说很有效,如下所示:
HOME="/home/me"
BACKUPFOLDER="$HOME/Backup/"
DIRECTORYLOG="$BACKUPFOLDER/<directory>.log"
NICERSYNC="nice -n 19 ionice -c 3 /usr/bin/rsync"
REMOTEHOST="[email protected]"
REMOTEBACKUPFOLDER="/home/me/Backup"
# partial-dir must be relative when using it with temp-dir
RSYNCSWITCHES="-acv --itemize-changes --delay-updates --delete-delay --partial-dir=<directory>-partial --temp-dir=$REMOTEBACKUPFOLDER/<directory>-temp"
$NICERSYNC $RSYNCSWITCHES "$BACKUPFOLDER/<directory>" $REMOTEHOST:\"$REMOTEBACKUPFOLDER\" &>> "$DIRECTORYLOG"
虽然我不太明白细节,但当--partial-dir
与 一起使用--temp-dir
时--delay-updates
,需要给定相对路径。
atomic-rsync
目录中还有一个脚本/usr/share/rsync/scripts
。引用自man
页面:
另请参阅“support”子目录中的“atomic-rsync”perl 脚本,了解更加原子的更新算法(它使用--link-dest 和并行文件层次结构)。
对我来说,问题是,这只能拉到本地目录,而不是推送到远程目录。我编写了一个可以正确完成这项工作的脚本,如下所示。第一次成功备份后,<directory>
将始终作为完整备份存在于远程。中断的备份将显示为<directory>.1
、<directory>.2
等。任何rsync
已完成的备份都将移动到<directory>
,另一个<directory>.n
将被删除。
HOME="/home/me"
BACKUPFOLDER="$HOME/Backup/<directory>"
DIRECTORYLOG="$BACKUPFOLDER/<directory>.log"
LOCALFOLDER="/home/dev/Backup"
LOCALSUBFOLDER="Restic/<directory>"
LOCALSOURCE="$LOCALFOLDER/$LOCALSUBFOLDER"
REMOTEHOST="[email protected]"
REMOTEHOME="/home/me"
REMOTEFOLDER="Backup"
REMOTESUBFOLDER="<directory>"
REMOTETARGET="$REMOTEFOLDER/$REMOTESUBFOLDER"
NICERSYNC="nice -n 19 ionice -c 3 /usr/bin/rsync"
SWITCHES="-ac --partial-dir=\"$REMOTEHOME/$REMOTETARGET-partial\""
errormsgandexit() {
if [[ $1 -ne 0 ]]; then
echo "$2"
exit $1
fi
}
ssherrormsgandexit() {
SSHCONNECTERROR=255
if [[ $1 -eq $SSHCONNECTERROR ]]; then
echo "$2"
exit $1
fi
}
echo -e "\n$(date) Rsync <directory>\n--------------------" >> "$DIRECTORYLOG"
# If TARGET exists, we use that for links:
ssh $REMOTEHOST "[[ -d \"$REMOTETARGET\" ]]" && SWITCHLINKS="--link-dest=\"$REMOTEHOME/$REMOTETARGET\""
ssherrormsgandexit $? "ssh connect failure while checking $REMOTETARGET directory." >> "$DIRECTORYLOG"
# Find the smallest n such that TARGET.n doesn't exist. use TARGET.1-(n-1) for links.
declare -i n=1
while ssh $REMOTEHOST "[[ -d \"$REMOTETARGET.$n\" ]]"; ! ((RETURN=$?)); do
SWITCHLINKS="$SWITCHLINKS --link-dest=\"$REMOTEHOME/$REMOTETARGET.$((n++))\""
done
ssherrormsgandexit $RETURN "ssh connect failure while checking $REMOTETARGET.$n directory." >> "$DIRECTORYLOG"
SWITCHESLINKS="$SWITCHES $SWITCHLINKS"
# now I am free to copy to TARGET.n:
$NICERSYNC $SWITCHESLINKS "$LOCALSOURCE/" $REMOTEHOST:\"$REMOTETARGET.$n\" >> "$DIRECTORYLOG"
errormsgandexit $? "rsync error, code $?." # >> "$DIRECTORYLOG"
# if rsync was successful, just keep the most recent complete TARGET
ssh $REMOTEHOST "([[ ! -d \"$REMOTETARGET\" ]] || rm -r \"$REMOTETARGET\") && \
mv \"$REMOTETARGET.$n\" \"$REMOTETARGET\" && \
([[ ! -d \"$REMOTETARGET.1\" ]] || rm -r \"$REMOTETARGET.\"*)" >> "$DIRECTORYLOG"
RETURN=$?
ssherrormsgandexit $RETURN "ssh connect failure while reordering $REMOTETARGET\* directories." >> "$DIRECTORYLOG"
errormsgandexit $RETURN "error when reorganizing $REMOTETARGET* directories." >> "$DIRECTORYLOG"