web-dev-qa-db-ja.com

データを複製せずに一度に複数のスナップショットをコピーするにはどうすればよいですか?

私は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_1home_2、およびshare_3で共有されている場合は、もちろん1回だけ送信して保存したいと思います。これを行う方法はありますか?

3
Daniel Böhmer

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_2subvol_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_3subvol_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安定版で問題が発生する可能性があります。

2
Daniel Böhmer