Jeff Bonwick's Blog

Monday Jun 02, 2008

豪快なレイヤー分け違反

Andrew Morton が ZFS を「豪快なレイヤー違反」と呼んだのは有名ですが、その理由は、ファイルシステムの機能、ボリューム管理、RAID コントローラを統合していることにあります。 違反という言葉の意味をどう取るかで、解釈が異なると思います。 ZFS の設計に際して、ストレージスタックの標準的なレイヤー分けが、驚くほど大量の無駄手間と冗長な処理を含んでいることを発見しました。 問題点にちょっとしたリファクタリングを加えれば、つまり、レイヤーを分ける境界を移動させてやれば、全体をもっと単純化できるのではないかと気づきました。

数学 (私のバックグラウンド分野) を例にするとわかりやすいでしょう。

n=1 から 無限大まで、1/n(n+1) について数列の和を計算しなければならないと仮定します。

項ごとにして開くと、次のような計算になります。

        1/(1*2) + 1/(2*3) + 1/(3*4) + 1/(4*5) + ...

つまり、

        1/2 + 1/6 + 1/12 + 1/20 + ...

無限に足し算を続けるのはどうでしょうか。非常に難しいことのようですが、問題を正しく観察していないというだけのことです。 賢明な人は、各項を先ほどとは違うやり方で記述できることに気付いたかもしれません。

        1/n(n+1) = 1/n - 1/(n+1)

たとえば、

        1/(1*2) = 1/1 - 1/2
        1/(2*3) = 1/2 - 1/3
        1/(3*4) = 1/3 - 1/4

そこで、次のように記述することができます。

        (1/1 - 1/2) + (1/2 - 1/3) + (1/3 - 1/4) + (1/4 - 1/5) + ...

規則性に注目してください。各項の後半で引き算したのと同じ数を、その次の項で足し算する繰り返しになっています。 こういう計算で意味があるのは、学会の中だけです。 では、区切り方を変えてみましょう。つまり元の問題に対して、結合性を元に、豪快なレイヤー分け違反をします。そうして、隣接項の両端同士の計算にリファクタリングします。次のようになります。

        1/1 + (-1/2 + 1/2) + (-1/3 + 1/3) + (-1/4 + 1/4) + ...

つまり、

        1/1 + 0 + 0 + 0 + ...

別の書き方をすると、

        1.

賢いやり方ではないでしょうか。

このように、 連続した項の配置を変えて互いに消去することを、数学の用語で Telescoping (たたみ込み) と呼びます。折りたたみ式の携帯望遠鏡 (Telescope) に例えた言い方です。 簡単に言うと、ZFS がやっているのも同じことで、ストレージスタックをたたみ込んでいるのです。 それにより、ファイルシステム、ボリュームマネージャー、シングルパリティーとダブルパリティーに対応した RAID、圧縮、スナップショット、クローン作成、そのほかたくさんの有用な機能が、たった 80,000 行のコードで実現できたのです。

ストレージシステムはここまで単純ではありませんが、高いレベルで、同じ考えを実際に利用しているのです。 どのようなストレージスタックも、ある命名スキーマから別の命名スキーマへの、変換の連続だと考えることができます。最終的には、ファイルネームをディスク LBA (Logical Block Address) に変換します。 典型的な例として、次のようになるでしょう。

        ファイルシステム (上位):ファイルネームをオブジェクトに (inode)
        ファイルシステム (下位):オブジェクトをボリューム LBA に
        ボリュームマネージャー:ボリューム LBA を アレイ LBA に
        RAID コントローラ:アレイ LBA をディスク LBA に

これが、私たちがリファクタリングしようとしているスタックです。

まず、従来のファイルシステムのレイヤーはモノリシックすぎるということに注目してください。 ファイルネームをオブジェクトに変換する部分 (前半) とオブジェクトをボリューム LBA に変換する部分 (後半) で 2 つに分けたほうがよいでしょう。この分け方だと、オブジェクトと iSCSI ターゲットなど、ファイルネームを持たず種類の異なるストレージをサポートする場合に、後半のコードを再利用できます。 つまり、各ストレージクラスからオブジェクトレイヤーに直接通信することができます。 この手法は、/dev/lofi などを経由するよりも効率的です。/dev/lofi は、POSIX ファイルをデバイスのように見せかける機能を提供しています。 さらに大切なことは、分け方を変えることで、コードを追加することなく新しくて強力なプログラミングモデルを実現できるということです。つまり、オブジェクトストレージのことです。

次に、ボリューム LBA は完全に役立たずだということに注目してください。中間レイヤーを設けることで柔軟性が高まるケースは多くありますが、この場合はそうではありません。実際、英語をドイツ語に直接変換しても問題がないのに、英語をフランス語に変換してから、あらためてドイツ語に変換しているのです。 中間のフランス語は本質的に無価値です。 この処理は、アプリケーションからも RAID アレイからも見えず、管理に必要な機能を提供していません。 ただのオーバーヘッドです。

そのため、ZFS ではレイヤー全体をたたみ込んで消去しました。 ZFS には、3 つの明確なレイヤーだけがあります。従来の POSIX ファイルシステムのセマンティクスを提供する ZPL (ZFS POSIX Layer)、汎用のトランザクションオブジェクトストアを提供する DMU (Data Management Unit)、仮想ブロック割り当てとデータ変換 (レプリケーション、圧縮、そして近い将来には暗号化も) を提供する SPA (Storage Pool Allocator) です。 ZFS の変換スタック全体は、次のようになります。

        ZPL:ファイルネームをオブジェクトに
        DMU:オブジェクトを DVA (Data Virtual Address) に
        SPA:DVA を ディスク LBA に

DMU が物理ストレージの共通プールに、ファイルアクセスとブロックアクセスの両方を提供します。 ブロックアクセスは DMU オブジェクトへの直接的なマッピングですが、ファイルアクセスは ZPL 経由で行います。 DMU のトランザクション能力をもっとおもしろい方法で利用した、新しいデータアクセスメソッドも開発中で、後日紹介する予定です。

ZFS のアーキテクチャーにより、変換レイヤーが丸ごと消去され、それとともに、メタデータクラス (ボリューム LBA) も丸ごとなくなります。 ハードウェア RAID コントローラの必要性もなくなります。さらに、有用な新インタフェースであるオブジェクトストレージを提供します。モノリシックなファイルシステムに埋もれて、以前はアクセスできなかったインタフェースです。

違反しているような感じはしませんが、 どう思いますか。

Comments:

Japanese! How unexpected.

Posted by bbot on June 03, 2008 at 01:15 AM PDT #

I'm not an expert but it looks like Chinese to me.

Posted by Tobie on June 03, 2008 at 09:04 AM PDT #

Post a Comment:
Comments are closed for this entry.

Archives
Languages:
Links
Referrers