はじめに
皆様こんにちは。ストレージアーキテクトの矢澤祐司です。 Yahoo! JAPANにて利用されているマルチペタバイトなストレージ達と仲良く過ごしている私なのですが、今回はFlashCacheを用いたI/Oの最適化について検証した結果の一部を皆様にご紹介させていただきます。
FlashCacheとは
SSD製品が安価に調達できるようになった昨今であっても大容量なストレージを構築する際はHDDに頼らざるを得ず、さすがにフルSSDで大容量なストレージを構築してしまうとコスト過多で現実的ではないと判断される方が大半かと思います。確かにSSDを利用することによってI/O性能が課題だったシステムを改善された事例はたくさんあるものの、大容量なストレージをSSDだけで構築する事はコスト面で現実的ではない場合もあり、少なくとも稟議を起案する際にはいろいろと工夫が必要かと思います。
今回ご紹介するFlashCacheはFacebookがフラッシュデバイスを活用するために開発したといわれているdevice mapperを利用してブロックレベルでキャッシュしてくれるものでして、HDDで構築したストレージの前段にキャッシュとしてSSDまたはioDriveのようなPCIe NAND Flashデバイスを利用し、Activeなデータを極力キャッシュ内部で処理することによってI/O性能を向上させるというものです。今回はTechblogをご覧の皆様にとって身近な環境とバージョンを利用した検証の結果を公表しましたのでご興味のある方は試していただければと思います。
なお、今回はFusion-ioさんにご協力いただきましてioDriveにてテストを実施しました。
検証環境について
サーバについて
今回テストした環境は下記のとおりです。 FlashCacheそのものはkernel 2.6.18系もしくは2.6.38系でテストされているようです。
OS | CentOS 5.7 (2.6.18-274.3.1.el5) |
メモリ | 4GB |
HDD | SATA1TB 7.2Krpm |
ディスク本数 | 12本 |
RAID | RAID1+0 |
FlashCacheなどについて
ioDrive DuoはmdadmでRAID0してテストしています。
バージョン | facebook-flashcache-1.0-105-g9887f0a.tar.gz |
モデル | Fusion-io ioDrive Duo SLC 320GB |
デバイスドライバ | v2.3.1 |
インストール方法
FlashCacheのインストールに関連する一連の作業に必要なパッケージ類をインストールします。
[yujyazaw@storage-test01 ~]$ yum install -y dkms gcc make yum-utils kernel-devel unifdef |
kernelのソースが入っていない場合はFlashCacheをインストールするサーバと同じバージョンのkernelのソースをインストールします。
[yujyazaw@storage-test01 ~]$ wget http://vault.centos.org/5.7/updates/SRPMS/kernel-2.6.18-274.3.1.el5.src.rpm [yujyazaw@storage-test01 ~]$ sudo rpm -ihv ./kernel-2.6.18-274.3.1.el5.src.rpm [yujyazaw@storage-test01 ~]$ cd /usr/src/redhat/SPECS/ [yujyazaw@storage-test01 ~]$ sudo rpmbuild -bp --target=`uname -m` kernel.spec |
gitからFlashCacheのソースを取得してmakeします。
[yujyazaw@storage-test01 ~]$ tar xvfz facebook-flashcache-1.0-105-g9887f0a.tar.gz [yujyazaw@storage-test01 ~]$ cd facebook-flashcache-9887f0a [yujyazaw@storage-test01 ~]$ make [yujyazaw@storage-test01 ~]$ sudo make install |
RAIDを組んだHDDとFusion-ioを使ってcachedevというデバイスを作成します。今回の環境ではcache sizeは307GBまで指定できましたが、キリのいいところで300GBを指定しています。 Fusion-ioのioDriveは通常/dev/fioaのようなデバイスパスとなるのですが、ioDrive Duoは/dev/fioaと/dev/fiobの2つのデバイスが見えますのでSoftware RAIDでRAID0を組んで/dev/md0としています。
[yujyazaw@storage-test01 ~]$ flashcache_create -p thru -s 300g cachedev /dev/md0 /dev/sda4 |
これで/dev/mapper/cachedevが作成されたはずです。 あとはmkfsしてmountすればローカルのファイルシステムと同様に使える状態になります。
[yujyazaw@storage-test01 ~]$ mkfs -t xfs /dev/mapper/cachedev [yujyazaw@storage-test01 ~]$ mount -t xfs /dev/mapper/cachedev /mnt |
ベンチマーク結果
今回はbonnie++を利用したテストの結果をご紹介します。 グラフはすべてHDD単体の性能を100%とした場合のFlashCacheの性能をプロットしています。
Sequential create
HDDのみの場合の結果を100%とすると173%の性能が出ました。 このテストはOSもFlashCacheもデフォルトのパラメータが適用されたままの状態ですのでWrite throughですが十分な性能向上が確認できました。詳細は後半にて触れていますがWrite through以外にWrite around, Write backが選択可能ですのでデータの保全性とトレードオフする形でさらなる性能向上を狙う事が可能です。
Sequential read
HDDのみの場合の結果を100%とすると16倍以上の性能が出ました。 いわゆる"あたたまった"状態になるとこのくらいの性能向上が期待できます。
Sequential delete
HDDのみの場合の結果を100%とすると84%程度まで性能が落ち込みました。 本ブログを執筆している段階では調査中なのですがxfs, ext4を試したものの両方ともDeleteのI/O性能は落ちてしまいました。 バッチ処理の類でファイルを一気に削除するような処理で検討されている方には向いていないのかもしれません。
Random create
HDDのみの場合の結果を100%とすると220%程度の性能がでました。 sequential createよりもFlashCache側の伸び率が高い部分に違和感を感じる方もいらっしゃると思いますが、ランダムにファイルが作成されますのでsequential createと比べるとHDD側の数字が悪くなっています。そのために比率で比べた場合にFlashCacheの数字がより良く見えています。
Random read
HDDのみの場合の結果を100%とすると約22倍もの数字が出ました。恐ろしいです。sequential readと比較するとFlashCache側の伸び率が高い部分に違和感を感じる方もいらっしゃると思いますが、random createと同様の理由で比率がより良くみえています。今回のテストではrandom readの数字はsequential readの数字の約60%程度の性能でした。
Random delete
HDDのみの場合の結果を100%とすると31%程度まで落ち込んでしまいました。 sequential deleteと同じ原因だと思いますが未だ調査中です。
Random delete
iozoneでも簡単なテストを実施してみました。 readのテストだけFlashCacheなしとほぼ同等の性能となっていますが、これはキャッシュに十分なデータがたまっていないためにI/Oが基本的にHDD側まで行ってしまった結果だと推測しています。
その他パラメータ類について
FlashCacheのパラメータ類について解説します。 意訳している部分がありますので、万一間違いにお気づきの方はこっそりお知らせいただけますと幸いです。
統計情報の取得について
/proc/flashcache/<cache name>/flashcache_statsを参照することによって各種統計情報(dmsetup statusコマンドと同等)が取得可能です。基本的にここの情報を見ながら各種チューニングを検討すると良いと思います。
[yujyazaw@storage-test01 ~]$ cat /proc/flashcache/md0+sda4/flashcache_stats reads=27417868 writes=43458973 read_hits=27392742 read_hit_percent=99 write_hits=5633018 write_hit_percent=12 replacement=25095 write_replacement=90631 write_invalidates=0 read_invalidates=0 pending_enqueues=0 pending_inval=0 no_room=0 disk_reads=25372 disk_writes=19097792 ssd_reads=27392742 ssd_writes=30019576 uncached_reads=146 uncached_writes=13464774 uncached_IO_requeue=0 pid_adds=0 pid_dels=0 pid_drops=0 pid_expiry=0 [yujyazaw@storage-test01 ~]$ |
/proc/flashcache/<cache name>/flashcache_errorsを参照することで各種エラーの統計情報が取得可能です。
[yujyazaw@storage-test01 ~]$ cat /proc/flashcache/md0+sda4/flashcache_errors disk_read_errors=0 disk_write_errors=0 ssd_read_errors=0 ssd_write_errors=0 memory_alloc_errors=0 [yujyazaw@storage-test01 ~]$ |
/proc/flashcache/<cache name>/flashcache_iosize_histを参照することでI/Oサイズの統計を確認する事が出来ます。
[yujyazaw@storage-test01 ~]$ cat /proc/flashcache/md0+sda4/flashcache_iosize_hist 512:0 1024:13464869 1536:0 2048:0 2560:0 3072:0 3584:0 4096:103300875 4608:0 5120:0 5632:0 6144:0 6656:0 7168:0 7680:0 8192:0 8704:0 9216:0 9728:0 10240:0 10752:0 11264:0 11776:0 12288:0 12800:0 13312:0 13824:0 14336:0 14848:0 15360:0 15872:0 16384:0 [yujyazaw@storage-test01 ~]$ |
キャッシュモードの選択
FlashCacheでは3つのキャッシュモードを選択する事が出来ます(詳細はflashcache-sa-guide.txtの"Choice of Caching Modes"参照)。キャッシュモードはキャッシュデバイスを作成する時にしか選択できませんのでご注意ください。
キャッシュモード | 説明 |
---|---|
Writethrough | WriteされたデータをSSDにキャッシュすると共にHDDにも書き込む3つのパラメータの中で最もデータの保全性が高い設定です。デフォルトではReadのI/Oは全てキャッシュされます(チューニング可能)。 |
Writearound | WriteされたデータはSSDにキャッシュされずHDDに直接書き込まれます。ReadのI/Oが発生した際にSSDにキャッシュする設定です。 デフォルトではReadのI/Oは全てキャッシュされます(チューニング可能)。 |
Writeback | WriteされたデータはSSDのみにキャッシュして後でHDDに書き込む設定です。一番速い設定ではありますが、SSDに障害が発生した場合にデータロストや不整合を起こすリスクがあります。 デフォルトではReadのI/Oは全てキャッシュされます(チューニング可能)。 |
キャッシングコントロールについて
FlashCacheはCache EverythingもしくはCache Nothingの2つのモードを選択する事が可能で、デフォルトではCache Everythingが適用されています。これら2つのモードはブラックリストとホワイトリスト(/proc/flashcache/<cache name>/flashcache_pidlists)を持っています。 Cache everythingはブラックリスト以外の全てのI/Oをキャッシュし、Cache nothingはホワイトリストのI/Oのみをキャッシュします(詳細についてはflashcache-sa-guide.txtをご参照ください)。FlashCache関連のsysctlについて(全キャッシュモード共通項目)
キャッシュモード | 説明 |
---|---|
dev.flashcache.<cachedev>.cache_all | デフォルトでは1(cache everything)がセットされており、0をセットする事によってcache nothingにする事が可能です。 |
dev.flashcache.<cachedev>.zero_stats | 1をセットする事で各種統計情報のカウンタをリセットする事が可能です。 1をセットした後は0をセットし直して再度1をセットすればカウンタをリセットできます。 |
dev.flashcache.<cachedev>.reclaim_policy | 0をセットするとFIFO(First In First Out)、1をセットするとLRU(least recently used)になります。 本パラメータはオンラインのまま変更可能です。 |
dev.flashcache.<cachedev>.io_latency_hist | 有効にすると応答時間の統計を250us単位で集計することができ、dmsetup status コマンドで表示する事ができます。 1をセットすると有効になり、デフォルトは0がセットされており無効化されています。 |
dev.flashcache.<cachedev>.max_pids | pidのホワイトリストもしくはブラックリスト(/proc/flashcache/<cachedev>/flashcache_pidlists内に記載)に記載するpidの上限数を設定します。 |
dev.flashcache.<cachedev>.do_pid_expiry | 1をセットするとpidのホワイトリストもしくはブラックリスト(/proc/flashcache/<cachedev>/flashcache_pidlists内に記載)に有効期限(dev.flashcache.<cachedev>.pid_expiry_secsの値が適用されます)が設定できます。 |
dev.flashcache.<cachedev>.pid_expiry_secs | pidのホワイトリストもしくはブラックリスト(/proc/flashcache/<cachedev>/flashcache_pidlists内に記載)を適用する有効期限を設定できます。 この設定を有効にするためにはdev.flashcache.<cachedev>.do_pid_expiryに1をセットする必要があります。 |
FlashCache関連のsysctlについて(Writebackモードのみ)
項目 | 説明 |
---|---|
dev.flashcache.<cachedev>.fallow_delay | read/writeされていない時、セットされた値(秒)の間dirty blockをクリーニングします。 0をセットするとこの動作を無効化できます。 |
dev.flashcache.<cachedev>.fallow_clean_speed | 1秒当たりの"fallow clean"する回数の最大値を指定します。 デフォルトでは2がセットされています。 |
dev.flashcache.<cachedev>.fast_remove | このオプションを有効にする事によりキャッシュデバイスを速く切り離す(fast_remove)事が可能です。 キャッシュデバイスを切り離す際にdirty blockはSyncされません。flashcache_loadした際もキャッシュデバイスにはdirty blockもclean blockも保持されています。 uncommitなデータはキャッシュデバイスの切り離し後もキャッシュデバイス側に保持されHDD側には書き込まれていません。 |
dev.flashcache.<cachedev>.dirty_thresh_pct | dirty blockの比率をここにセットされた値(%)未満に保持します。 閾値を低くすることによってディスクへのWriteは増えますが、Readキャッシュ用の領域を多く確保する事が出来ます。 |
dev.flashcache.<cachedev>.stop_sync | キャッシュデバイスからHDDへのSyncを途中で停止させます。 |
dev.flashcache.<cachedev>.do_sync | 定期的にdirty blockをクリーニングします。(この値を変更する理由はほとんどありません) |
dev.flashcache.<cachedev>.max_clean_ios_set | dirty blockをクリーニングする際に発行できるwriteの回数の上限を設定します。 |
dev.flashcache.<cachedev>.max_clean_ios_total | 全blockをSyncしている際に発行できるwriteの回数の上限を設定します。 |
まとめ
向き/不向きがありますので適性を見極めましょう
FlashCacheに限った話ではありませんがキャッシュを活用してI/Oを高速化する仕組みはキャッシュに乗らないとまったく速くならず、それどころかミスキャッシュする分レイテンシも高まってしまい結果としてI/O性能が低下してしまいます。
今回掲載されているテスト以外にも筆者の性格がバレてしまうようなさまざまなテストを実施していますが、キャッシュデバイスの空き容量に関係なく一定以上の容量のファイルに対するI/Oはキャッシュされていないように見受けられる結果も出ました。また、ベンチマーク用のデータは「サーバのメモリ容量以上キャッシュデバイスの容量未満」なものの数百万個~数千万個のファイルを作成してテストした場合もキャッシュとして活用しきれていない場面が見受けられました。FlashCacheはブロック単位でキャッシュしてくれていますので、基本的に特定のブロックやファイルにI/Oが偏っている場合に効果が出やすい思いますのが、まずはI/Oについて課題のあるシステムのI/Oの特性を見極める事が大切だと思います。
キャッシュ用のデバイスは一定以上の性能を有したものを使用しましょう
キャッシュ用のデバイスというとRead性能ばかり注目されがちですが、キャッシュされていないデータに対するI/Oが発生した時はHDDからSSDに対してWriteのI/Oが発生します。期待する性能にもよりますがキャッシュデバイスに利用するSSDの性能が低いとSSDがボトルネック化してしまいます。
実際にもっと性能の低いSSDを利用して同様のテストを実施してみましたが、使用するSSDによってはHDD単体よりも遅くなってしまうケースが見受けられました。カタログスペックで優劣を評価しがちな部分ですが各社の製品を評価しているとI/O性能が安定しない製品も見受けられますので可能な限り実機を用いた検証をする事をお勧めします。SSD製品の評価はHDD製品とは違う工夫が必要な部分もありますのでそのあたりもご注意ください。
統計情報を監視する仕組みを用意しましょう
残念な事にシステムの設計時に想定していない要件がリリース後に追加されるなど、当初予定していたI/Oの傾向と変わってしまう場合があります。統計情報を有効活用することによってキャッシュとして有効に活用できていないことをいち早く検知できるようにしましょう。
次回について
今回は一般的なバージョンでテストしましたが、せっかくLinux kernel 3.1系にマージされましたので、そちらのテストも実施して公開したいと思っています。後はホワイトリストやブラックリストを使った検証も面白いような気がしています。InfiniBandの検証レポートについてもぜひ公開したいと思いますが、なにかリクエストのある方はフィードバックいただけますと幸いです。
こちらの記事のご感想を聞かせください。
- 学びがある
- わかりやすい
- 新しい視点
ご感想ありがとうございました