データを複製せずに複数のスナップショットを一度にコピーする方法は?

データを複製せずに複数のスナップショットを一度にコピーする方法は?

古いスナップショットと新しい4TBバックアップドライブを含む90%を超える3.7TiBライブbtrfsファイルシステムがあります。既存のスナップショットをすべてバックアップハードドライブにコピーする方法は?

頑張った

# btrfs send home_1 home_2 home_3 share_1 share_2 share_3 ...

ただし、スナップショットの3分の2が転送される前にバックアップハードドライブがいっぱいです。それで私はいくつかの調査をしました。

# ### 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回のコマンドですべてのスナップショットを転送すると、データが重複してストリームのサイズだけでなく、受信側のスナップショットサイズも元々使用していたスペースとハードディスクの容量を超えてしまいます。

したがって、実際の質問は次のようになります。複数のスナップショットに含まれるデータをコピーせずに複数のスナップショットをコピーするにはどうすればよいですか?

この簡単なテストケースでは、段階的なアプローチを成功させようとしました。

# ( 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_2share_3これを行う方法についてのアイデアはありますか?

答え1

簡単に言うと:通常、-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

これが私に必要なのかどうかはまだわかりません。このソリューションについてご意見をお持ちですか?

修正する:実際のファイルシステムでこれをテストするためにサブボリュームセットを簡単に送信し(リストの作成はすぐに-c退屈です)、いくつかのデータを次に送信するPerlスクリプトを作成しました/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/秒]
  • perl btrfs-send-all.pl some-subvolume_* | bash | pv > /dev/null:12.7GiB 0:03:58 [54.7MiB/秒]

これはパフォーマンスを大幅に向上させませんが、ほとんどストレージスペースが50%減少しました。!今実際に実行しようとしています...

修正する:2つのスナップショットが正常に送信されましたが、3番目のスナップショットはbtrfs receive次のエラーメッセージで失敗しました。

ERROR: unlink path/to/some/file/in/the/snapshot failed. No such file or directory

指定されたファイルsubvol_2がに存在しますsubvol_3が、いいえしかし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%にすぎないため、これは間違いなく複製です。ほとんどのファイルを共有します。

btrfs send subvol_3 -c subvol_1 -c subvol_2 | btrfs receiveスナップショットが正しく送信されていないためにレプリケーションがアーカイブされ、存在するファイルのみを削除できないのはなぜですかsubvol_1subvol_3subvol_2

修正する:このバグではないでしょうか?https://patchwork.kernel.org/patch/10073969/

私はカーネル4.9でDebian 9 Stretchを実行していますが、パッチよりも古いようです。

修正する:解決策が見つからなかったため、各サブボリュームの最新のスナップショットをコピーしました。次に、約500GiBの空き容量があり、コピーされたスナップショットを-pパラメータとして使用して古いスナップショットを追加しようとします。その後、上記と同じスナップショットに対して同じエラーメッセージが表示されました。

結論として:私の結論は、上記のリンクされたエラーが発生したことです。最新のLinuxカーネルでこのシステムを再起動するか、別のコンピュータからファイルシステムにアクセスする必要がありますが、これは本番システムなので不可能です。

これまでbtrfsに問題はありませんでしたが、rsnapshot(多くのハードリンクを生成します)を実行してbtrfsスナップショットを送信することは、現在のDebian安定リリースでまだ問題になる可能性があります。

関連情報