Nabe International | Takeru Boost >> Takeruを回せ! >>

zfsのsplitオプションを使ったアーカイブについて

RHEL7/CentOS7以降、TakeruシステムのメインのストレージはZFS構成をデフォルトとしています。 CopyOnWrite方式による高い信頼性、ストレージプール方式のため拡張が容易であること、圧縮やsnapshotなどの機能面で優れていることなどが主な理由ですが、今回のポストではメインのストレージ用というよりも、アーカイブ用途として実際に社内でも活用している方法の一つ、splitのオプションについて紹介したいと思います。

ZFSのMirror/Split機能

ZFSはファイルシステムではありますが、ext4/xfsなどと違い、ストレージマネージャの機能も備えています。従ってZFS的なRAIDを構成することができ、以下のRAIDレベルが選択可能です。
  • Mirror (RAID 1)
  • RAID Z (RAID5相当 : Single Parity)
  • RAID Z2 (RAID6相当 : Double Parity)
  • RAID Z3 (Triple Parity)
今回紹介するSplit機能というのはMirrorで構成された複数のデバイスを分割して、レプリカを作成する機能のことです。

Split機能のメリット

冒頭で主にアーカイブ用として社内で活用していると書きましたが、アーカイブ用途の場合、"データを貯めていくフェーズ"と"保管・(必要に応じて)参照"する2つフェーズがあります。 データを貯めている途中にディスクが壊れてしまうとデータロストしてしまうので、"データを貯めていくフェーズ"においては冗長化のためにRAID構成としておきたいところです。 ただ、参照するフェーズにおいては必ずしもRAID構成である必要ではないことも多いと思います。 別々のマシンで同じデータを参照したい場合や、遠隔地に保管するDisaster Recovery的に保管するような場合でも、単体ドライブとして使用できる方がポータビリティが上がりますので、便利なケースは多いのではないかと思います。 弊社では、案件毎に納入時点のOSイメージというものを保管しています。 これはソフトウェアの追加・更新などのサポート依頼を受けた際に、現地と同じOS、ソフトウェア構成を復元した上で検証をするために保管しているもので、非常に重要なデータです。 弊社ではこのデータの保存にZFSのMirror/Split機能を使っています。

社内での運用方法

実際には、メインのBackup Serverとして8TBのHDD3本でZFSのMirror を構成しDaily Snapshotを取得、さらに別のサーバー(BackupのBackupサーバー)にZFSのsend/recv機能を使って差分バックアップを毎日取っています。 また、圧縮機能をdefaultのlz4からgzipに変更した上で、さらにメモリを多めに積んで重複排除もONにしています。 下記は最近の状態なのですが、4.95xという数字が重複排除率を示しており仮にこの率が維持されれば、8TBのディスク1本で40TB近くのデータを保存できることになります。
[Backup Server] 
# zpool list -v Backup_2019-1A
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
Backup_2019-1A  7.25T   657G  6.61T         -     2%     8%  4.95x  ONLINE  -
  mirror  7.25T   657G  6.61T         -     2%     8%
    sdb      -      -      -         -      -      -
    sdc      -      -      -         -      -      -
    sdd      -      -      -         -      -      -

[Backup of Backup Server]
# zpool list -v
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
Backup-of-Backup_2019-1A  7.25T   689G  6.58T         -     5%     9%  5.01x  ONLINE  -
  sdb  7.25T   689G  6.58T         -     5%     9%
上記のディスクは現在"データを貯めていくフェーズ"にあるわけですが、ディスクがFullになったら、sdb,sdc,sddの3本ミラーで構成しているBackup_2019-1Aというストレージプールを3つにsplitし、その後は参照する際に1本だけ搭載、残りの2本はオフラインで保管、というような形で利用しています。 Mirror構成のまま参照しても悪くはないのですが、サーバー側のディスクスロット数も限りがあるためこのような運用にしています。

他のRAIDとの比較

同様のことが他のRAID構成でできるのかどうかについても少し考えてみたいと思います。 Broadcom(LSI)のRAIDコントローラーによるHardware RAIDは性能もよく、管理面でも便利なのですが、RAID1を構成したディスクを明示的にSplitして同じデータを持った別々のドライブとして利用することはできなかったと思います。 もちろん、RAID1の情報を残した上で1本ずつDegraded状態で認識させることは可能は可能ですが、、、という感じです。 また、RAIDコントローラーで構成してしまうと、同じ型番(必ずしも同一型番でなくてもいいケースが多いですが)のRAIDコントローラーがあるマシンでないと使えない、という意味でポータビリティはかなり下がります。 また、LinuxのSoftware RAID(MD)の場合は未確認ですが、少なくともHardware RAIDと同様にDegraded状態で参照するということは可能です。 もしかすると片方のディスクをfail扱いにして、md raidお解除するためにremoveした後zero-superblockすれば可能かもしれませんが、圧縮や重複排除はext4, xfsなどのファイルシステムではできません。(xfsは最近dedupの機能が追加されたようなニュースを見たような気もします)

Mirror/Splitの手順

では、実際に手順を見てみたいと思います。

3本Mirrorのzpool構成

KVMの仮想マシンにおいての手順を紹介します。あくまでデモ用なので容量は各ディスク32GBしかありません。
$ zpool create r3-a mirror vdb vdc vdd  # r3-aという名前のストレージプールを作成

$ zfs create r3-a/home -o mountpoint=/home  # r3-aのストレージプールの下にr3-a/homeという名前のファイルシステムを作成(/homeにマウント) 

その後、10GB程度のファイルをコピーした時点でのzpool listが以下の通り

$ zpool list
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
r3-a  31.8G  10.1G  21.6G         -     0%    31%  1.00x  ONLINE  -

また、split後の挙動確認のためにも、snapshot取得、その後一部ファイルの削除、ということも行なっておきます。

$ zfs snap r3-a/home@FirstSnap
$ zfs list -t snap
NAME                  USED  AVAIL  REFER  MOUNTPOINT
r3-a/home@FirstSnap    28K      -  10.1G  -

$ rm /home/takeru/file_11  # 約100Mのファイルを1つ削除

$ zfs list -t snap  # file_11を削除したことで、snapshotのUsedもその分増加しています。
NAME                  USED  AVAIL  REFER  MOUNTPOINT
r3-a/home@FirstSnap   101M      -  10.1G  -

Splitで3つに分割

上記の状態からSplitします。
$ zpool list -v  # split前のPoolの状態
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
r3-a  31.8G  10.1G  21.6G         -     0%    31%  1.00x  ONLINE  -
  mirror  31.8G  10.1G  21.6G         -     0%    31%
    vdb      -      -      -         -      -      -
    vdc      -      -      -         -      -      -
    vdd      -      -      -         -      -      -

$ zfs set readonly=on r3-a  # 切り離したディスクが書き換えられないようファイルシステムをreadonlyに変更
$ zfs get readonly
NAME                 PROPERTY  VALUE   SOURCE
r3-a                 readonly  on      local
r3-a/home            readonly  on      inherited from r3-a
r3-a/home@FirstSnap  readonly  -       -


$ zpool split r3-a r3-c   # splitを実行。切り離したディスクは、r3-cというストレージプール名となる。
                                                                    # デフォルトでは、後ろのディスクから順番に切り離される

$ zpool list -v  # vddが切り離されていることがわかる
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
r3-a  31.8G  10.1G  21.6G         -     0%    31%  1.00x  ONLINE  -
  mirror  31.8G  10.1G  21.6G         -     0%    31%
    vdb      -      -      -         -      -      -
    vdc      -      -      -         -      -      -

$ zpool split r3-a r3-b  # もういちどsplitを実行。切り離したディスクは、r3-bというストレージプール名になる。

$ zpool list -v   # 冗長性の無い単体ディスクで構成されたストレージプールになる。
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
r3-a  31.8G  10.1G  21.6G         -     0%    31%  1.00x  ONLINE  -
  vdb  31.8G  10.1G  21.6G         -     0%    31%

切り離したディスクをマウント

切り離した2つのストレージプールをImportしてマウントし、確認します。
$ zpool import  # 引数無しでimportコマンドを実行すると、import可能なストレージプールの一覧が表示されます。
   pool: r3-b
     id: 3415264450577376184
  state: ONLINE
 action: The pool can be imported using its name or numeric identifier.
 config:

        r3-b        ONLINE
          vdc       ONLINE

   pool: r3-c
     id: 16155892436419908890
  state: ONLINE
 action: The pool can be imported using its name or numeric identifier.
 config:

        r3-c        ONLINE
          vdd       ONLINE

$ zpool import r3-b  # r3-bのストレージプールをImportします。
cannot mount '/home': directory is not empty

$ zpool import r3-c  # r3-cのストレージプールをImportします。
cannot mount '/home': directory is not empty
同一マシン上でこれを行うと上記のようなエラーが出てしまいます。 元々、同一マシンで2つの同じ内容のディスクをマウントすることはあまり想定していないのですが、r3-a/home, r3-b/home, r3-c/homeのファイルシステムがmountpoint=/homeという同じプロパティを持っていることが原因す。 マウントポイントを変更すれば参照できるようになりますが、上でreadonly=onにしてしまっているのでこれをいったんoffにしないとマウントポイントの変更もできず面倒です。 各ファイルシステムのマウントポイントのプロパティは、デフォルト通りストレージプール名を含んだものにしておいたほうが良さそうです。

動作確認

切り離してImportしたストレージプール、ファイルシステムを確認してみます。以下のように単体でも使用可能な3本の同一のHDDができています。
$ zpool list -v     # ストレージプールは以下の通りそれぞれ以下のようにSplitされています。
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
r3-a  31.8G  10.1G  21.6G         -     0%    31%  1.00x  ONLINE  -
  vdb  31.8G  10.1G  21.6G         -     0%    31%
r3-b  31.8G  10.1G  21.6G         -     0%    31%  1.00x  ONLINE  -
  vdc  31.8G  10.1G  21.6G         -     0%    31%
r3-c  31.8G  10.1G  21.6G         -     0%    31%  1.00x  ONLINE  -
  vdd  31.8G  10.1G  21.6G         -     0%    31%

$ zfs list -t snap  # snapshotの情報も当然Splitしたファイルシステム毎に存在しています。
NAME                  USED  AVAIL  REFER  MOUNTPOINT
r3-a/home@FirstSnap   101M      -  10.1G  -
r3-b/home@FirstSnap   101M      -  10.1G  -
r3-c/home@FirstSnap   101M      -  10.1G  -

$ ls /r3-b/home/takeru/file_11        # file_11というファイルは上で削除してしまったのでありませんが、
ls: cannot access /r3-b/home/takeru/file_11: No such file or directory

$ ls /r3-b/home/.zfs/snapshot/FirstSnap/takeru/file_11 -lh    # splitしたzfsのsnapshot上には存在しています。
-rw-rw-r-- 1 takeru takeru 101M Jan 26 23:00 /r3-b/home/.zfs/snapshot/FirstSnap/takeru/file_11

もしsplit後に1本故障したら

単体にsplitした後に、いずれかのHDDが故障した場合は単体ドライブのデータを維持したまま、Mirror構成にすることはできないので、コピーするほかありません。snapshotを取って、それをsend/recvするのが一番速いですが、rsyncなどでも普通にコピーできます。

まとめ

上記ではアーカイブ用途の想定で書いていましたが、遠隔地保管などの用途の他、共同研究先とのデータのやりとりなどにも使えるかもしれません 。もちろんただデータを移動するだけであれば、ext4/xfsでコピーした方が楽ですし、zfsは手動でインストールする必要があるという点もハードルではありますが、圧縮機能で容量が増えるのであればそのハードルを超えてもメリットがある場合が多そうな気がします。 また、重複排除についてもう少し触れておく必要があるかもしれません。 重複排除の機能をONにしたままストレージを運用するにはメモリが大量に必要で、数十TBを超えるストレージで重複排除をONにすることはメモリ容量的に現実的ではありません。 現在、市場で購入可能な単体HDDの最大容量は、14TBでして以前のポストにも記載したように圧縮のオプションをデフォルトのlz4からgzipに変更することで2x程度の圧縮率が得られるケースは多いと思います(データの種類に依存しますが)。 2xの圧縮率が得られれば、HDD1本で30TB前後のデータの保管も可能ですのでこれだけでもかなりメリットはあるのではないかと思います。