ローカルネットワークで頻繁に使用されるリポジトリのミラーリングを毎晩、毎週行っています。予期されるファイルがまだすべて存在しないため、rsyncの実行中に誰かが更新を試みて失敗したことがまれにあります。
all変更されたファイルが完了時に正しい名前でのみ表示されるようにrsyncを実行することは可能ですか? rsyncが各転送の進行中に一時的な.hiddenファイルを使用することを知っていますが、何らかの方法で完了するまで名前の変更を延期できますか?
または、--backupオプションを使用してすべての変更を1つのディレクトリに移動し、その後にそれらをアトミックに移動できるようですが、この機能を現在の機能とは逆に機能させたいと思います。
私はLinuxを利用しています。
--link-dest=
オプション。基本的には、新しいフォルダーを作成します。すべてのファイルは新しいフォルダーにハードリンクされます。すべてが完了したら、フォルダ名を入れ替えて古いものを削除できます。
カーネル/ VFSのサポートがないため、Linuxでこれを100%アトミックに実行することは不可能です。ただし、名前の交換は実際には2回のシステムコールで行われるため、完了までに1秒もかかりません。 Darwin(MAC/OSX)でのみ可能であり、HFSファイルシステムでexchangedataシステムコールを使用します。
rsync
バックアップ[ディスクへ]でも同様のことを行っていますが、バックアップの実行中にファイルを更新するデーモンが原因で同じ問題が発生しました。
多くのプログラムとは異なり、rsyncにはmanyさまざまなエラーコードがあります[manページ下部を参照]。興味深いのは2つです。
23-エラーによる部分的な転送
24-ソースファイルの消失による部分的な転送
Rsyncが転送を行っているときにこれらの状況の1つに遭遇した場合、それはただちに停止するわけではありません。それはスキップして、ファイルを続行しますcan転送します。最後に、戻りコードが表示されます。
したがって、エラー23/24が発生した場合は、rsyncを再実行してください。後続の実行ははるかに速く進みます。通常は、前の実行から欠落しているファイルを転送するだけです。最終的には、クリーンランが得られます(または得られるはずです)。
アトミックであることについては、転送中に「tmp」ディレクトリを使用します。次に、rsyncの実行がクリーンになったときに、名前を[原子的に] <date>
に変更します
私は--link-dest
オプションも使用していますが、それを使用して差分バックアップを保持しています(例:--link-dest=yesterday
for daily)
私自身は使用していませんが、--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
ミラー同期は自動ですか(cronタスクなど)?もしそうなら、おそらくあなたはこれのために専用のOSユーザーを使用しています、そうですか?したがって、解決策は単にコピーするのではなく、
欠点は、同期プロセス中(所要時間は不明)、ターゲットディレクトリにアクセスできないことです。ここで問題ないかどうかを自分で決める必要があります。
これが役立つかどうかはわかりませんが...
毎回データセット全体をコピーしてもかまわない場合andシンボリックリンクを使用してターゲットディレクトリを参照できる場合は、すべてを一時ディレクトリにrsyncしてからスワップ(rename())新旧のシンボリックリンクをアトミックに次のように記述します。
_% mkdir old_data new_data
% ln -s old_data current
% ln -s new_data new
% strace mv -T new current
_
走る
rename("new", "current")
= 0
そして与える
_current -> new_data
_
これが機能する場合でも、この設定から読み取ろうとするすべてのクライアントは、読み取りを試みる前に、シンボリックリンクによって参照されるディレクトリにcd
する必要があります。そうしないと、古いコピーから一部のコード/データと新しいもの。