私は3.7TiBのライブbtrfsファイルシステムを持っています。これは古いスナップショットと新しい4TBバックアップハードディスクを含めて90%以上いっぱいです。既存のすべてのスナップショットをバックアップハードディスクにコピーするにはどうすればよいですか?
私は試した
# btrfs send home_1 home_2 home_3 share_1 share_2 share_3 ...
ただし、スナップショットの2/3が送信される前に、バックアップハードディスクがいっぱいでした。だから私はいくつかの研究をしました:
# ### create test image
# dd bs=1M count=1000 > btrfs_test.dd
# mkfs.btrfs btrfs_test.dd
# ### create snapshots
# btrfs subvol create testvol/
# btrfs subvol snapshot -r testvol/ testvol_0/
# ### (copy some ISO image)
# btrfs subvol snapshot -r testvol/ testvol_1/
# ### (proceed until testvol_3)
私のテストファイルシステムは、818MiBを使用して91%いっぱいでした。
# btrfs send testvol_* | wc -c
At subvol testvol_0
At subvol testvol_1
At subvol testvol_2
At subvol testvol_3
1466441978 # 1398MiB >> 1000MiB
1つのコマンドですべてのスナップショットを送信するだけでは、データが複製され、ストリームのサイズと受信側のスナップショットのサイズが、元の使用済みスペースとハードディスクの容量を超えます。
したがって、実際の質問は次のようになりました。2つ以上のスナップショットに含まれるデータを複製せずに複数のスナップショットをコピーするにはどうすればよいですか?
この単純なテストケースでは、インクリメンタルアプローチを正常に試しました。
# ( btrfs send testvol_0; btrfs send -p testvol_0 testvol_1; btrfs send -p testvol_1 testvol_2; btrfs send -p testvol_2 testvol_3 ) | wc -c
At subvol testvol_0
At subvol testvol_1
At subvol testvol_2
At subvol testvol_3
838778546 # 800 MiB < 1000MiB
ただし、実際のファイルシステムには複数のサブボリュームがあり、それぞれに複数のスナップショットがあります。 -p
で使用する順序を定義できません。データブロックがサブボリュームhome_1
、home_2
、およびshare_3
で共有されている場合は、もちろん1回だけ送信して保存したいと思います。これを行う方法はありますか?
TL; DR:冒頭で説明した-c
パラメーターの使用は一般的に機能します。スナップショットにハードリンクが含まれている場合、スナップショットの送信時にエラーをトリガーするLinuxカーネルのバグがあります。詳細については、回答の最後にある結論を参照してください。
私は-c
パラメーターを試していますが、有望に見えます。
# for i in {0..3}; do btrfs send testvol_$i $(ls -d testvol_* | head -n$i | sed 's/^/-c /'); done | wc -c
### btrfs send testvol_0
### btrfs send testvol_1 -c testvol_0
### btrfs send testvol_2 -c testvol_0 -c testvol_1
### btrfs send testvol_3 -c testvol_0 -c testvol_1 -c testvol_2
At subvol testvol_0
At subvol testvol_1
At subvol testvol_2
At subvol testvol_3
838778546 # also 800MiB
これが私に必要なものかどうかはまだわかりません。このソリューションに関するコメントはありますか?
更新:実際のファイルシステムでこれをテストするために、一連のサブボリュームを快適に送信するPerlスクリプトを作成しました(-c
のリストをすばやく作成します)退屈になりました)そしていくつかのデータを/dev/null
に送信しました:
#!/usr/bin/env Perl
use strict;
use warnings;
my @subvols = @ARGV
or die "Usage: $0 SUBVOLUME ...\n";
for(@subvols) {
-d $_
or die "Not a directory: $_\n";
}
for my $i (0 .. $#subvols) {
my $subvol = $subvols[$i];
my @clones = map { ('-c', $_) } @subvols[ 0 .. $i-1 ];
print "btrfs send $subvol @clones\n";
}
結果:
btrfs send some-subvolme_* | pv > /dev/null
:24GiB 0:04:17 [95.2MiB/s]Perl btrfs-send-all.pl some-subvolume_* | bash | pv > /dev/null
:12.7GiB 0:03:58 [54.7MiB/s]これはパフォーマンスの向上にはなりませんが、ストレージスペースがほぼ50%減少します!私は今これを実際に実行しようとしています…
更新:2つのスナップショットを正常に転送しましたが、3番目のスナップショットではbtrfs receive
が失敗し、次のエラーメッセージが表示されました。
ERROR: unlink path/to/some/file/in/the/snapshot failed. No such file or directory
名前付きファイルはsubvol_2
とsubvol_3
にありますが、notはまだsubvol_1
にあります。
送信されたスナップショットと受信されたスナップショットを比較しようとしました。
# ### sender
# du -s subvol_{1,2,3}
132472304 subvol_1
117069504 subvol_2
126015636 subvol_3
# ### receiver
# du -s subvol_*
132472304 subvol_1
117069504 subvol_2
132472304 subvol_3
最初の2つのスナップショットは正しく転送されたようですが、subvol_3
はsubvol_1
のクローンです。バックアップディスクの使用済みスペースはスナップショットの合計サイズの39%にすぎないため、これは間違いなくクローンです。ほとんどのファイルを共有しているため、スナップショットの合計サイズは1/3をわずかに上回っています。
btrfs send subvol_3 -c subvol_1 -c subvol_2 | btrfs receive
がスナップショットを正しく転送せず、subvol_1
のクローンを作成してから、subvol_3
に保持する必要があり、subvol_2
にのみ存在するファイルの削除に失敗するのはなぜですか。
更新:このバグでしょうか? https://patchwork.kernel.org/patch/10073969/
パッチより古いように見えるカーネル4.9でDebian9Stretchを実行しています。
更新:解決策が見つからなかったため、各サブボリュームの最新のスナップショットをコピーしただけです。次に、約500GiBの空き容量があり、コピー済みのスナップショットを-p
パラメーターとして使用して前のスナップショットを追加しようとしました。次に、上記と同じスナップショットに対して同じエラーメッセージが表示されました。
結論:上記のリンクにあるバグに遭遇したと結論付けます。このマシンを新しいLinuxカーネルで再起動するか、別のコンピューターからファイルシステムにアクセスする必要がありましたが、これは実稼働システムであるため、実行できません。
これまでbtrfsに問題はありませんでしたが、rsnapshotを実行すると(多くのハードリンクが作成されます)、btrfsスナップショットを送信すると、現在のDebian安定版で問題が発生する可能性があります。