FreeBSD で ZFS を利用する – ZFS のキャッシュの仕組みを理解する

ZFS

今回は ZFS のキャッシュについて説明します.
ZFS は読み取り用の一次キャッシュとしてメモリーを利用します.そのほか、二次キャッシュとして高速なディスク (SSD や NVMe など) を指定する事が可能です.
そもそもの動作から説明を行っていきます.

ZFS のキャッシュの動作について

単純なプール構成の場合

ZFS はキャッシュの構成も様々な構成をとる事が可能です.まずは,メモリーとディスクだけの単純なプールの場合のキャッシュ動作について解説します.

一番単純な構成の場合の状態がこの絵の形となります.

初めて出る単語があるのでまずはその説明を行います.

  • ARC (Adaptive Replacement Cache)
    最近アクセスされたファイルや頻繁にアクセスされているファイルをキャッシュし,読み取り要求時にディスクアクセスを抑制しメモリーから応答を返すためのキャッシュ領域
  • ZIL (ZFS Intent Log)
    ディスクにデータを書き込む際のバッファー領域 (正確にはバッファーではないですが,この理解の方が分かりやすいと思います)

書き込み時

ARC は読み取りキャッシュとして動作します.書き込みキャッシュにはなりません.
書き込み時,いったん ZIL 領域に書き込みが行われ,データをトランザクショングループに纏めたのちに実際のデータとしてディスクに書き込みます.
なお,ZIL 領域はプールの一部を利用していますので,プール内のディスクから見たら2回の書き込み動作が発生するディスク群が生じます.

読み取り時

読み取りの要求が来た際,まずは ARC 内にデータがあるか確認されます.ARC 内にデータがある場合はディスクへの読み取り要求を行わずに ARC 内のデータを返して終了します.
ARC 内にデータがない場合はディスクから読み取りデータを返します.

また,そのデータは ARC にキャッシュされ,次にアクセスがあった際は ARC から返される事になります.しばらくアクセスが行われないファイルの場合は ARC からドロップされます.その場合はディスクから読み取る事が必要になります.

L2 ARC キャッシュを搭載したプールの場合

ZFS はメモリーとストレージプールの間に高速なディスク (通常は SSD や NVMe など) をキャッシュ層として追加する事が可能です.

初めて出る単語があるのでまずはその説明を行います.

  • L2ARC (Layer2 Adaptive Replacement Cache)
    SSD や NVMe で構成する二次キャッシュ ARC から溢れたキャッシュデータが格納される

書き込み時

ARC/L2ARC 共に読み取りキャッシュとして動作します.書き込みキャッシュにはなりません.
書き込み時,いったん ZIL 領域に書き込みが行われ,データをトランザクショングループに纏めたのちに実際のデータとしてディスクに書き込みます.
なお,ZIL 領域はプールの一部を利用していますので,プール内のディスクから見たら2回の書き込み動作が発生するディスク群が生じます.
(ですので,書き込み時の動作に変更はありません)

読み取り時

読み取りの要求が来た際,まずは ARC 内にデータがあるか確認されます.ARC 内にデータがある場合はディスクへの読み取り要求を行わずに ARC 内のデータを返して終了します.
ARC 内にデータがない場合は L2ARC 内にデータがあるか確認されます.L2ARC 内にデータがある場合はディスクへの読み取り要求を行わずに L2ARC 内のデータを返して終了します.
いずれも失敗した場合はディスクから読み取りデータを返します.

また,そのデータは ARC にキャッシュされ,次にアクセスがあった際は ARC から返される事になります.しばらくアクセスが行われないファイルの場合は ARC から L2ARC に移動されます.
L2ARC 内のデータも ARC 同様にしばらくアクセスがないファイルはキャッシュから削除されます.

SLOG を搭載したプールの場合

ZFS はストレージプール内にある ZIL の手前に高速なディスク (通常は SSD や NVMe など) をバッファー層として追加する事が可能です.

初めて出る単語があるのでまずはその説明を行います.

  • SLOG (Secondary LOG)
    ZIL の替わりになるバッファー層のディスク領域で,書き込み時のトランザクショングループを纏めるまでのバッファー層となる

書き込み時

ARC/L2ARC 共に読み取りキャッシュとして動作します.書き込みキャッシュにはなりません.
SLOG がある場合,ZIL は SLOG 内に内包 (統合) されます.
書き込み時,いったん SLOG 領域に書き込みが行われ,データをトランザクショングループに纏めたのちに実際のデータとしてディスクに書き込みます.
ZIL 領域は SLOG 内に内包され,プールの中には存在しない事になりますので,プール内のディスクから見たら1回の書き込み動作で完了する事になり,書き込み性能の向上が見込めます.

読み取り時

読み取りの要求が来た際,まずは ARC 内にデータがあるか確認されます.ARC 内にデータがある場合はディスクへの読み取り要求を行わずに ARC 内のデータを返して終了します.
ARC 内にデータがない場合は L2ARC 内にデータがあるか確認されます.L2ARC 内にデータがある場合はディスクへの読み取り要求を行わずに L2ARC 内のデータを返して終了します.
いずれも失敗した場合はディスクから読み取りデータを返します.

また,そのデータは ARC にキャッシュされ,次にアクセスがあった際は ARC から返される事になります.しばらくアクセスが行われないファイルの場合は ARC から L2ARC に移動されます.
L2ARC 内のデータも ARC 同様にしばらくアクセスがないファイルはキャッシュから削除されます.
(ここは先と変化はありません)

もっと細かい話

https://www.45drives.com/community/articles/zfs-caching/ の和訳です.

ZFS は,プール化されたストレージ,データ スクラビング,圧縮や重複排除など,多くの有益な機能を提供する高度なファイルシステムです.
ですが,ZFS の最も有益な機能の一つは,読み取りと書き込みをキャッシュする方法です.
ZFS はメモリーを使用してデータを階層的にキャッシュします.

ZFS のキャッシュの一番目のレベルは ARC です.ARC 内のすべての領域が使用されると ZFS は最新の頻繁に使用されたデータを L2ARC に配置します.

ARC と L2ARC,ZIL および SLOG はそれぞれが実際にどのような役割を果たすのかについて各方面で説明にブレがあり混乱を生じさせています.

ARC,L2ARC は読み取りキャッシュです.これらは,システムがデータを見つける必要があるたびに低速なディスクへのアクセスを行う必要がないようにサーバーでの読み取りを高速化するために存在します.

書き込みの場合,ZIL はあくまでもログであり、別のログ デバイス (SLOG) が存在する場合でも,実際には書き込みキャッシュではありません.(書き込みキャッシュと呼ばれることが多いですが) .

ここでは,それらすべての用語が何を行うのか、また,それらを実装することでサーバーにどのようなメリットがあるのか​​を明らかにします.
まず書き込み.つまり ZIL と SLOG について説明します.

書き込み

ZFS は書き込み要求を受けると,即ディスクへの書き込みを開始するのではなく,書き込みを RAM にキャッシュしてから,設定された間隔 (デフォルトは 5 秒) でトランザクショングループ (TXG) に送信します.
これはトランザクションファイル システムと呼ばれます.

これによって、ディスクへの書き込みがより適切に整理され,ディスクの処理が大きく簡素化されるため,パフォーマンスが向上します.
また,電源障害が発生した場合でも部分的な書き込みが発生しないため,データの一貫性にもメリットがあります.
電源障害が発生した場合,TXG 内のすべてのデータが破棄される事になります.

ZFS が書き込みを処理する方法の基本を理解するには,同期書き込みと非同期書き込みの違いを理解する必要があります.

非同期書き込み

データはすぐにメモリーにキャッシュされ,クライアントには書き込み完了が返され,その後ディスクに書き込まれます.

クライアントが書き込みリクエストを送信すると,そのリクエストは直ちにメモリーに保存されます.
その後,サーバーは書き込みが完了したことをクライアントに通知します.
トランザクショングループが RAM に保存されると,サーバーはトランザクショングループをまとめてディスクに書き込むまで,ディスクに何も書き込まずにさらにリクエストを受け付けます.
非同期書き込みは,データが高速なメモリーに保存されるだけで完了したとみなされるため,ユーザーから見た場合は非常に高速な書き込みプロセスです.

問題は,データの一貫性は維持されますが,電源障害が発生するとトランザクショングループはメモリーにのみ存在するためすべてが失われます.
同期書き込みはデータの一貫性を確保することを目的としていますが,パフォーマンスが犠牲になります.

同期書き込み SLOG が無い場合

書き込みが完了したとみなされる前に,ディスクに書き込まれたことが確認される必要があります.

クライアントが同期書き込みの書き込みリクエストを送信すると,非同期書き込みと同様に最初にメモリーに保存されますが,サーバーは ZIL に記録されるまで書き込みが完了したことを通知しません.

ZIL が更新されると,書き込みがコミットされ,書き込み完了の通知が行われます.ZIL はデフォルトでストレージプールの一部として存在します.つまり,ZIL を更新し,実際にデータをプールのに保存するには,ハードディスクのヘッドの場所を物理的に移動する必要があるため,パフォーマンスにさらに影響します.特に小さなランダム書き込みの場合に,パフォーマンスの問題が発生します.

同期書き込みによる速度の低下や望ましくないデータ損失に対する ZFS の解決策は,ZIL を通常は SSD や NVMe などの別の高速永続ストレージ デバイスに配置することです.

SLOG を使用した同期書き込み

ZIL が SSD/NVMe に格納されている場合,クライアントの同期書き込みリクエストは ZIL に高速に記録されます.こうすることで,停電により RAM 上のデータが失われた場合でも,システムは次に電源が入ったときに ZIL をチェックし,コミット前のデータを見つけることが可能になります.

あるいは,データは ZIL に保存されたデータへのポインタとともに,すぐにディスクに書き込まれることもあります.
次の TXG が送信された後,正しい場所を指すようにデータのメタデータが更新されます.
停電が発生した場合,サーバーは ZIL をチェックしてデータがどこにあるかを見つけます.システムは実際には,次のトランザクショングループが通過するまでデータがどこに格納されているかを認識しておらず,メタデータにはデータの格納場所が表示されないため ZIL を確認する必要がありました.
SLOG に関して注意すべき点の 1 つは,電源障害が発生した場合にデータの一貫性を確保するというジョブを実行できるようにミラーリングすることが最善であるということです.

SLOG はパフォーマンスにどの程度貢献するのか

SLOG のインパクト,パフォーマンスはアプリケーションによって異なります.
小規模な IO では大幅な改善が見られ,シーケンシャル IO でもかなりの改善が見られる可能性があります.
データベース サーバーやホスティング VM などのユースケースなど,多くの同期書き込みの場合にも役立つ可能性があります.ただし、SLOG の主な機能はパフォーマンスの向上ではなく,停電時に失われるデータを保存することです.
ミッション クリティカルなアプリケーションの場合,次のトランザクション グループが送信される 5 秒間のデータが失われると,かなりの影響が発生する可能性があります.これが,SLOG が実際にはキャッシュではなく,その名前が示すようにログである理由でもあります.SLOG には,予期しない電源障害が発生した場合にのみアクセスされます.

失われる可能性のある 5 秒間のデータが重要な場合は,パフォーマンスの低下と引き換えにすべての書き込みを強制的に同期として実行することができます.
そのデータにミッションクリティカルなものがない場合は,同期を無効にすることができ,トランザクショングループが失われる危険性はあるものの,すべての書き込みは単純にメモリーをキャッシュとして使用できます.標準同期はデフォルトであり,書き込みごとにアプリケーションと ZFS によって決定されます.

SLOG 用のデバイスを選択するための非公式の要件は,単一のキュー深さで適切に機能するドライブを選択することです.同期書き込みは,ほとんどの SSD が最も得意とする大規模なバッチでは行われないため,標準の SSD を使用すると実際にはパフォーマンスが低下する可能性があります.Intel Optane ドライブは,低いキュー深度での高速性と,停電時に書き込みを完了するバッテリーのおかげで,一般に SLOG として使用するのに最適なドライブの 1 つと考えられています.データを保存するという目的を達成するには、SLOG にバッテリーを搭載することが重要です.

※ Intel Optane は廃止になってしまっているので,SSD や NVMe をバッテリーバックアップ可能な構成にして利用する.が現状の解となると思います.

読み取り

書き込みと同様に,ZFS は読み取りをメモリーにキャッシュします.読み取りキャッシュを ARC と呼んでいます.これは IBM ARC の修正バージョンであり,ARC が使用するより複雑なアルゴリズムにより,平均的な読み取りキャッシュよりも高性能です.

ARC

ARC は,最近使用されたデータと最も頻繁に使用されたデータをメモリーに保存することによって機能します.メモリー上の ARC に存在するデータはディスク上のストレージプールにも存在するため,これは ZIL とは異なり,本当のキャッシュ機能です.
読み取りパフォーマンスの高速化に役立つのは ARC のみであり,通常は優れたパフォーマンスを発揮します.大規模な ARC を使用すると,大量のメモリーが占有される可能性がありますが,他のアプリケーションが必要とする場合はそのメモリを放棄し,システムに最適と思われる値に設定できます.

ARC は,コールド ヒットが発生するたびに,どちらかにより多くのスペースを割り当てることにより,最近使用されたデータと最も頻繁に使用されたデータの割合を変更して使用します.
コールド ヒットは,以前にキャッシュされていたものの,ARC が新しいデータを格納できるようにするためにすでにプッシュされていたデータの一部が要求された場合に発生します.
ZFS は,コールドヒットを認識できるようにするために,キャッシュが削除された後にどのデータがキャッシュに保存されたかを追跡します.新しいデータが入ってくると,しばらく使用されていないデータや,新しいデータほど使用されていないデータが押し出されます.

システムのメモリーが多いほど,読み取りパフォーマンスが向上するため,より優れています.マザーボードのメモリースロットと予算の制約により,ARC を追加するには物理的およびコストの制限があります.ヒット率が高くならず ARC がいっぱいになっており,システムにこれ以上のメモリーを搭載できない場合は,L2ARC の追加を検討することをお勧めします.

L2ARC

L2ARC は,高速なメモリーではなく SSD や NVMe 上に構成します.ただし、ハードディスクよりもはるかに高速であるため,ARC のヒット率が低い場合は,L2ARC を追加する事でパフォーマンスが向上する可能性があります.
ハードディスクからデータを見つける代わりに,システムはメモリーと SSD/NVMe を調べてパフォーマンスを向上させます.通常,64 GB 以上のメモリーを搭載しているにもかかわらず,ARC のヒット率が 90% 未満の場合 L2ARC が検討されます.

L2ARC がいっぱいになるのは,ARC がいっぱいになり,そのアルゴリズムがより重要であると判断した新しいデータ用のスペースを空ける場合に限られます.この排出されたデータは L2ARC に移動されます.L2ARC がいっぱいになるまでに長い時間がかかる可能性があります.

※ L2ARC は,L2ARC に保存されるすべてのデータはストレージプール内に存在するため,SLOG のようにミラーリングする必要はありません.

L2ARC は,そこに保存されているデータを追跡するためにメモリー上の一定量のスペースを使用するため,通常は L2ARC を検討する前にメモリーを追加することをお勧めします.
SSD/NVMe はハードディスクより高価ですが,メモリーよりははるかに安いため,この決定を行う際には,価格とパフォーマンスのトレードオフを発生させる可能性があります.

まとめ

  • ZIL は,確認がクライアントに送り返される前に同期書き込みが記録されるスペースです.デフォルトでは,ストレージ プールの一部として存在します.
  • SLOG は,ZIL が存在する別のデバイスです.一部の特定の用途ではパフォーマンスが向上する可能性があります.ただし、その主な機能は、停電時に失われる可能性があるデータを保存することです.
  • ARC は,読み取りパフォーマンスを高速化するためにデータをキャッシュするために使用される RAM の一部です.
  • L2ARC は ARC の拡張機能であり,通常は SSD/NVMe 上にあります.これは,メモリーを追加するという物理的な制約を回避しながら,ARC のサイズを増やすことを目的としています.

和訳も追加をさせて頂きましたが,ZFS のキャッシュの仕組みの説明でした.
ARC/L2ARC や ZIL/SLOG について理解が深められればと思います.

次回ですが,実際に ARC の設定や L2ARC,SLOG デバイスの追加などオペレーションの方法を解説したいと考えています.




seichan

ご連絡は X (twitter) の DM へお願いします.

seichanをフォローする
ZFS

seichanをフォローする




コメント

タイトルとURLをコピーしました