Edited at

岩舘電気の中の人が ZFS の dedup を使ってバックアップサーバを構築してみた

 ども、皆さん初めまして。岩舘電気の中の人です。

 @isseium 氏から突然、「岩手の開発者でアドベントカレンダーやってるので書きませんか?」と、ディスプレイ越しからも伝わる爽やかさで誘われてしまい、せっかくのお誘いなのでキーボードを叩いてみることにしました。なお Iwate Developers Advent Calendar 2014 のリンクはこちらです。

http://qiita.com/advent-calendar/2014/iwate-dev

 さて、岩舘電気というとアレゲなテレビCMで岩手県民ならご存知の方も多いでしょう。本業はもちろん電気工事の会社で、皆さんが普段ご利用のビルやトンネルの電気工事ももしかしたら岩舘電気が手掛けたものかもしれません。

 ちなみにロゴはこんな感じです。見たことがありますか?天気がいいと、上田の跨線橋から本社のロゴが見えます。

 余談ですが、弊社はご家庭の小さな工事も承りますので、コンセントや照明の増設など、何かお困りの事がありましたらどうぞお気軽にご相談下さい。

 そんな電気工事やさんですが、実は岩舘電気は古くからIT化に熱心に取り組んでいる会社でもあります。何を隠そう私自身が長らく外資系IT企業(SAP Japan)の Global IT 部門に在籍しており、エンタープライズなITの仕事をしてきました。そんな私が岩舘電気で構築したバックアップサーバを今回ちょこっと紹介してみます。

 まずはバックアップ対象です。私が入社した時には既に社内に HDD が二重化された NAS サーバが設置されていました。ただバックアップは単純な上書きバックアップしか取っていなかったので、これを daily backup することを目標としました。

 バックアップサーバ構築にあたって選んだ物理マシンは MX130 S2 という富士通の格安サーバです。これに合計 16GB の ECC メモリと 4TB の HDD、256GB の SSD を追加します。総額としては8万円ほどでしょうか。USBメモリに ESXi 5.5 をインストールし、その上で FreeBSD 向けに configure した VM に 8GB のメモリを割り振ります。4TB HDD と 256GB SSD は Raw Device Mapping (RDM) しました。(仮想マシンはストレージコストが高いですからね。)なおこのホストマシンには、他にもいくつかVMが動いています。

 アプライアンスは NAS4Free にしました。FreeNAS の方が有名だと思うのですが、最近のバージョンは smb 周りが不安定だという話でしたし、私自身もテスト際に怪しい印象を受けたので、あえてNAS4Free を採用しています。

 構成を図にするとこんな感じです。

 Virtual disk を 2つ割り振っていますが、一つは NAS4Free のブート用、もう一つは自作スクリプト置場です。ディスクを2つに分けたのは NAS4Free の推奨に従ったためです。

 実際の VM の設定はこちらです。

 詳しい人だと、2 CPU の物理マシンなのに仮想マシンに 2 CPU 割り振ると他のVMとの兼ね合いで CPU の待ち時間が発生しないか?と思われるかもしれません。しかしバックアップが動くのは深夜で、他の仮想マシンは夜はほとんど動かないので、まずはこのまま運用しています。

 VMが構成できたらNAS4Free をインストールします。専用アプライアンスですし、VMで動作させることがはじめから考慮されているので、インストールは極めて簡単です。インストールが終わったらNAS4Freeの Web console から設定を行います。大抵のことは GUIで設定できますが、dedup をオンにするのだけはコマンドラインからやらなくてはいけないようです。

 なお今回 256GB の SSD は zfs cache として使うように設定しました。SSD をNAS4Freeレベルでキャッシュにするのか、ESXレベルでキャッシュにするのかで悩んだのですが、NAS4Free のパフォーマンスを最大にするために zfs の cache にしてあります。

 それにしても、ESXi にしろ NAS4Free にしろ、これだけのソフトウエアを無料でつかえるのだから、とんでもない時代ですね。Datadomain (現在はEMCに買収されてしまいました)の dedup ソリューションが出てきた頃には数千万円の見積もりをもらったものですが、今や個人でも使える価格です。

 さて、早速バックアップのスクリプトを書いていきます。まずは社内のNAS サーバを smb_mount して毎晩フルバックアップをするようにスクリプトを書いてみました。NAS4Free は再起動のたびに設定と追加ディスク以外の構成がリセットされるので、smb_mount のチェックや2バイト対応ライブラリのリンクを張りなおすようにスクリプトを書いてあげます。

 見ての通り、smb_mount したディレクトリから、zfs の領域にコピーをするのですが、その際先頭に日付が入れてあります。ユーザはこの日付を頼りにリストアしたいファイルを探せば良いわけです。

 で、もちろん毎日バックアップすれば、いくら 4TB の HDD でも普通ならばあっというまに容量が無くなってしまいますが、dedup をオンにしてあるので、重複された内容が除外されるため、毎回フルバックアップをしても容量がなかなか減らないのです。

 とはいえ、このままではネットワークへの負荷が大きくなってしまいます。また、毎回社内NAS サーバから全てのファイルを転送してコピー元に負荷がかかるのも避けたいので、ちょっとした工夫を加えてみます。(下の図ではVM部分だけ書いてあります。)

 仕組みとしては簡単で、見ての通り cp ではなく rsync の差分転送を使います。その際、一旦 pre-sync というディレクトリに rsync するのですが、このディレクトリは前日の情報をそのまま保持しているので、通常10分もかからずに処理が終了してしまいます。その後 pre-sync ディレクトリから日付入りディレクトリに rsync (実質はコピー)するのですが、当然このステージでは社内NASにもネットワークにも負荷はかかりません。極めて簡単な仕組みですが、大きな改善ですね。

 ではどのくらい dedup されてるのでしょうか?

約7ヶ月半のバックアップを運用した結果がこちらです。

 なんと、28.5TB ものデータが保存され、圧縮率は実に176倍!しかもまだまだディスクには余裕があり、4TB のうちまだ1TBも使っていません。この調子だとこのマシン1台で数年分くらいのバックアップは保存できそうです。圧縮率がどれだけ伸びるか楽しみですね。またこれだけ大量のファイルがあっても、リストアは日付の入ったフォルダを探すだけなので、ユーザビリティもばっちりです。

 このサーバ1台だけでも実用的ですが、実は同じ構成のバックアップサーバをもう1台作成して、テストのためにネットワークの帯域をわざと 100Mbps にして接続してあります。帯域が狭くなったにもかかわらず、rsyncで転送容量が減ったおかげでバックアップに支障ありません。もちろんバックアップ対象のディレクトリの構成が丸々変更になるような事態になれば大量のファイル転送が発生するので話は別ですが、通常の利用では問題なさそうです。

 なんでこんなテストをしているのかというと、このもう1台のバックアップサーバ、将来的にはDRサイトに設置する予定なのです。本社から遠い回線の細いところに設置して問題ないか試験しているんですね。ただ、いざ広域災害が発生して DR が必要になった時に、私が生きていないと問題対応が出来ない可能性がありますね。このあたり、BCPの設計の難しいところです。

 追記(12/8/2014):スナップショットを使った方が良いのではないかというご指摘を Twitter でいただきましたので補足します。なぜこのような構成にしたのかについてはいくつか理由があるのですが、既存のNASはHDDが二重化されていてホットスワップが可能な専用ハードウエアだったので、これを最大限利用したいというのが一番の理由でした。将来NASをリプレースしスナップショットが取れるようになったら、1時間に1度などの頻繁な回数でスナップショットを取得することになるかと思います。(実は今年そのような構成を導入予定でしたが、諸事情により見送っています。中の人の頭の中ではハードウエアリプレースの構想が数年先まであるのですが、部分最適化と全体最適化のバランスや、社員のリテラシの状況次第で予定が前後します。)

 またハードウエア障害を考えると、スナップショットはバックアップの代わりにはならないため、NASをリプレースしても同様の仕組みでバックアップを取得しつづけることになると思います。たとえば、スナップショットは1時間に1度取得し、履歴を数日分残しつつ、dedup backup は1日1度取得して長期間保存する、といった運用です。

 追記(6/19/2019):この方法だと、毎回すべてのファイルをコピーすることになるため、キャッシュが溢れてしまいます。次のコマンドでメタデータのみキャッシュすることで、パフォーマンスを向上しかつメモリの使用量を減らすことができます。

zfs set primarycache=metadata tank/dataset