nkjmkzk.net

powered by Kazuki Nakajima

Archive for the ‘ocfs2’ tag

OCFS2はcache-coherentなクラスターファイルシステム。それってどういうこと?

OCFS2はcache-coherentなクラスターファイルシステムです。

これは結構すごい機構だと思うのですが、整理して理解するにはすこしばかり低レイヤの技術知識が必要になります。ということでまず一般的なI/Oの仕組みをおさらいした上で、cache-coherentではないNFSとcache-coherentなOCFS2を比較することによってcache-coherent何たるかを理解していきたいと思います。

とあるプロセスからI/O、つまりディスクへのデータ書き込みまたはディスクからのデータ読み込みを行うにはいくつかの経路があります。

一つはlibcのstdioを用いたbuffered I/Oで、fwrite()等がそれです。このライブラリを使ったI/Oではユーザ空間でキャッシュが行われます。

もう一つはカーネルのシステムコールを用いたより低レイヤで実装されているwrite()等です。これは通常カーネルが管理するキャッシュを経由してディスクにアクセスを行います。

また、同じwrite()であってもそもそもファイルをオープンするときにO_DIRECTフラグを立ててオープンしたファイルへの読み書きはキャッシュを迂回して最短距離でアクセスされます。

キャッシュはI/O高速化のためにとても重要ですが、OSはディスク上のデータとキャッシュ上のデータの差異を意識してアクセスをハンドリングし、あるタイミングで同期させなければなりません。

スタンドアロンの環境ではOSはうまく複数プロセスからのアクセスをさばきつつ同期を行います。例えばプロセスAがとあるファイルを更新し、その更新データがキャッシュ上にのみ存在してディスクとは同期されていない状態で、プロセスBがそのファイルにアクセスしたとします。そうするとOSはキャッシュ上の最も新しいデータをプロセスBに返します。もしプロセスBが読み込みではなく更新処理を行う場合でも最新のデータを踏まえて更新が行われるので整合性は保たれます。

しかしこれが複数のOSにまたがった場合はそう簡単ではありません。例えばサーバA、サーバBという2ノードからNFSでファイルシステムを共有している場合の挙動を見てみましょう。サーバAがNFS上にあるファイルにwirte()システムコールで更新(追記)処理を行ったとします。この場合もデータはまずカーネル空間のキャッシュに書き込まれ、ディスクへの同期は保証されません。したがってまだディスクに追記データが書き込まれていない状態だとサーバBからは更新情報を知る術がなく、その状態で同じく更新(追記)処理を行ってしまうとデータが破壊されてしまいます。なので2ノードから同一ファイルを同時更新するような構成はとることができません。

ここで活躍するのがcache-coherentなクラスターファイルシステム、OCFS2です。OCFS2では前述のように2ノードから同一ファイルを同時更新するような構成をとることができます。それも同期書き込み等を必要とするわけではなく、一般的なwrite()システムコールでいままで通りカーネルのキャッシュを利用した書き込みでそれを実現します。それはOCFS2がcache-coherentだから、つまり、カーネル空間のキャッシュも含めてクラスターを構成するノード間でデータの整合性が取れるような仕組みが備わっているからです。先ほどNFSで行ったのと同じ処理をOCFS2に置き換えて実施してみると、サーバBはサーバAがまだディスクに書き出していないキャッシュ上の更新データを認識し、サーバAの更新を踏まえて自身の更新処理を行います。したがってすべての更新データは保護されます。

*ちなみにcoherentとなるキャッシュはカーネルが管理するキャッシュです。ユーザ空間で管理されるキャッシュは対象となりません。

この挙動を実際のアプリケーションで確認するのに僕は2ノードでクラスター化されているnginxのアクセスログを用いました。通常Webサーバを並べてクラスター化する場合、読み取り専用のコンテンツファイル、あるいは実行ファイルも含めNFSをはじめとした共有ストレージで共有されることが多いと思いますが、更新が行われるログファイルは各ノードがそれぞれ自身のファイルを持つことが一般的だと思います。

アプリケーションによって確実に同期書き込みが行われるデータベースのトランザクションログとは異なり、Webサーバのアクセスログは通常のカーネルキャッシュを経由した書き込みが行われる実装が多いと思います(多分ね)。実際にnginxも僕がソースを見た限りではwrite()(非同期)でログを更新しており、特にfsync()で都度同期させるようなことも行っていませんでした。その実装で、cache-coherentでないファイルシステム上のログファイルに対して複数ノードから同時更新を行うと更新内容はランダムに失われてしまいます。

挙動を確認するために実際にNFS上にログファイルを置き、それを2ノードから共有させてテストを行いました。2ノードに並行して負荷をかけ、アクセスした数とアクセスログに出力されたログの件数をつき合わせてみるというものです。

負荷はクライアントマシンから下記のようなスクリプトを実行してかけています。

#!/bin/bash

for i in {1..10000}
do
    curl http://172.22.0.61/61.html
done &

for i in {1..10000}
do
    curl http://172.22.0.62/62.html
done &

本来であれば20000件のログがアクセスログに出力されるはずですが、この構成での結果は下記の通りです。

[root@server-a]# cat /srv/nginx/log/access.log | wc -l
11740

多くのログが失われていることがわかります。
したがってNFSで共有ストレージが使える環境でもアクセスログは複数ノードに分散させることになるため解析時には分散したログファイルをマージしなければなりません。

そこでcache-coherentなOCFS2の出番です。OCFS2はこれまで見てきたとおり別ノード上のカーネルキャッシュ上の更新データに関して把握しながら更新を行うことができます。したがって複数ノードから一つのアクセスログを共有して同時更新することができるはずです。こちらも実際にテストを行いました。

この構成での結果は下記の通りです。

[root@server-a]# cat /srv/nginx/log/access.log | wc -l
20000

出力されるはずのログ数がすべて出力されていることがわかります。
そもそもアクセスログを共有するのがよいのかどうか、というような議論はさておき、OCFS2上だと複数ノードからカーネルキャッシュを経由した同時更新を行っても完全性のある出力結果が得られることがわかりました。これがcache-coherentである、ということになります。

without comments

Written by 中嶋 一樹

3月 3rd, 2011 at 2:19 pm

Posted in Uncategorized

Tagged with

OCFS2 1.6の新機能

Oracle Linux 5.6とOracle Linux 6.0が相次いでリリースされました。いずれもE-Deliveryからどなたでもフリーでダウンロードできます。
http://edelivery.oracle.com/linux

そしてこれら2つのディストリビューションから、デフォルトのkernelがUEK(Unbreakable Enterprise Kernel)となりました。

*デュアルkernel構成としてインストールされています。つまり、起動時にUEKか、RHEL互換kernelかを選択できます。

以前の記事でもご紹介しましたが、UEKでは性能面のチューニングが施されている他、OCFS2の1.6という最新バージョンが使えるようになっています。OCFS2 1.6は多くの機能追加が行われており、とても魅力的なファイルシステムとなっています。今回はその主要な新機能をご紹介します。

拡張属性

タグのようなものです。ディレクトリ、ファイルに対してNAME:VALUEという形式で情報を付加できるようになっています。

POSIX アクセス制御

通常、ファイルは所有ユーザ:グループ:その他という分類でそれぞれにrwx(読み取り、書き込み、実行)のパーミッションが付与されます。POSIXアクセス制御ではよりきめ細かな制御が可能になります。tanakaはr、yoshidaはrw、yamadaはrwみたいな。

Indexed Directories

Unix/Linuxのディレクトリは配下にファイルを配置することによって階層構造を表現していますが、このディレクトリエントリ(つまりディレクトリ配下のファイル)がめちゃくちゃ多くなったときに、そのリストの取得や更新を高速化させるための仕組みです。

メタデータ・チェックサム

メタデータ(つまりinode等)の整合性をチェックするためのチェックサムを導入。さらに1 bitのエラーであれば修復する機能も追加。

Reflink

OCFS2 1.6の目玉機能。ファイルベースで瞬間複製/スナップショットが取れる。詳しくはこちらの記事を。「Unbreakable Enterprise Kernelを使おう – OCFS2 1.6 Reflink編」

User / Groupベースの容量制限(クォータ)

userまたはgroupベースで容量制限をかけられる機能。

割り当て予約

特に徐々にデータの書き込みが行われたりする大容量ファイルでシーケンシャルなI/Oを可能にして読み書きを高速化するための機構。あらかじめ連続したブロックを予約しておくことで1ファイルが実際にはディスクのあちこちにデータが保存されて長いseek時間要するような挙動を回避する。さらにブロックの予約は「消費」ではないので予約されていても未使用領域であれば必要に応じて譲ることが可能。

JBD2

16TBまでのファイルシステムサイズを実現するジャーナル機構JBD2を採用。

Discontiguous Block Group

OCFS2はinodeをファイルシステム フォーマット時ではなく、動的に作成します。なのでフォーマットが早く、事前に不要かもしれないinodeのための容量をガッツリ消費することがありません。ただし動的に作成する際に固定長の連続領域を必要とするため、空き領域がひどく断片化していると問題になります。この機構はそのようなケースで固定長連続領域の確保要求に対して不連続領域をうまく当てがうためのものです。内部的な機構のための機構なのでユーザにはあまり関係ないかも。

より詳細を求める方はOCFS2 1.6のリリースノートを参照ください。

OCFS2 user’s GUID for release 1.6

with one comment

Written by 中嶋 一樹

2月 16th, 2011 at 4:05 pm

Posted in Uncategorized

Tagged with

Unbreakable Enterprise Kernelを使おう – OCFS2 1.6 reflink編

Unbreakable Enterprise KernelではOCFS2の最新バージョン、1.6がサポートされます。この日をどれだけ待ちわびたかことか。

OCFS2 1.6の何が良いのか? それは何と言っても「reflink」です。reflinkについては過去にも幾度が言及されていますが、今回初めてすぐに使える&サポートされる形でモジュールが提供されてきました。

reflinkとは感覚的に言えばハードリンクとスナップショットが一緒になったようなものです。スナップショットは非常に便利な機能で、最小限の容量で差分バックアップを一瞬で作成し、複数世代保持できます。通常スナップショットはLUN単位またはファイルシステム単位で取得することになります。reflinkはこのスナップショットをファイル単位で取得できるというものです。これは一部の商用製品を除いてこれまで実現できなかった機能です。アプリケーションデータのスナップショットからVMイメージのスナップショットまでいろんな活用例が容易に想像でき、夢が広がります。

では早速reflinkしてみましょう。

こちらのポストでUnbreakable Enterprise Kernelをインストールすれば、すぐにOCFS2 1.6及びreflinkが使える状態になっています。

まずOCFS2でフォーマットするためのブロックデバイスを用意します。VM環境であれば「Create New Virtual Disk」で新しい仮想ディスクを追加してあげます(ちなみにオンラインで追加できます)。

OCFS2->create_new_virtual_disk

追加が完了するとこうなります。

OCFS2->created_new_virtual_disk

ゲストOSからは/dev/xvdbとして新しいブロックデバイスが見えています。このブロックデバイスをOCFS2でフォーマットします。今回はクラスターは組みませんので-M localでローカルファイルシステム専用にしています。–fs-features=refcontを指定することでこのファイルシステムでreflinkが有効になります。

[root@~]# mkfs.ocfs2 -M local --fs-features=refcount /dev/xvdb

mkfs.ocfs2 1.6.3
Label:
Features: sparse backup-super unwritten inline-data strict-journal-super refcount
Block size: 4096 (12 bits)
Cluster size: 4096 (12 bits)
Volume size: 1073741824 (262144 clusters) (262144 blocks)
Cluster groups: 9 (tail covers 4096 clusters, rest cover 32256 clusters)
Extent allocator size: 4194304 (1 groups)
Journal size: 67108864
Node slots: 1
Creating bitmaps: done
Initializing superblock: done
Writing system files: done
Writing superblock: done
Writing backup superblock: 0 block(s)
Formatting Journals: done
Growing extent allocator: done
Formatting slot map: done
Formatting quota files: done
Writing lost+found: done
mkfs.ocfs2 successful

フォーマット完了です。マウントします。

[root@~]# mount /dev/xvdb /mnt

さぁ、reflinkのテストを行いましょう。abcと書かれたテキストファイル、a.txtを作成します。そしてそのa.txtをreflinkしてaa.txtを作成します。そしてaa.txtをcatしてみると、abcと書かれています。つまり、a.txtとaa.txtがリンクしているのがわかります。

[root@~]# vi a.txt
abc
[root@~]# reflink a.txt aa.txt
[root@~]# cat aa.txt
abc

つぎにaa.txtの中身を編集してみます。その後、a.txtとaa.txtを見てみると別々の文字列が保存されていることが確認できます。これが単なるハードリンクではなく、「ハードリンク+スナップショット」と書いた由縁です。

[root@~]# vi aa.txt
abc
def

[root@~]# cat a.txt
abc

[root@~]# cat aa.txt
abc
def

次の実験。reflinkで作成したファイルはCoWなので作成時には容量を消費しません。まずは現在のOCFS2ファイルシステムの空き容量を確認します。そしてddで100Mbyteのファイルtest.imgを作成し、空き容量が100Mbyte消費されることを確認します。次にtest.imgをreflinkしてtest.img.bakを作成し、双方のファイル容量とファイルシステム空き容量をもう一度確認します。ファイルは双方とも100Mbyte消費しているものの、ファイルシステムの空き容量は減っていないことが確認できます。

[root@~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/xvdb             1.0G   81M  944M   8% /mnt

[root@~]# dd if=/dev/zero of=test.img bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 0.311367 seconds, 337 MB/s

[root@~]# df -h /mnt
Filesystem            Size  Used Avail Use% Mounted on
/dev/xvdb             1.0G  187M  838M  19% /mnt

[root@~]# reflink test.img test.img.bak
[root@~]# ll -h
total 200M
-rw-r--r-- 1 root root    8 Sep 21 01:48 aa.txt
-rw-r--r-- 1 root root    4 Sep 21 01:36 a.txt
drwxr-xr-x 2 root root 3.9K Sep 21 01:35 lost+found
-rw-r--r-- 1 root root 100M Sep 21 01:52 test.img
-rw-r--r-- 1 root root 100M Sep 21 01:54 test.img.bak

[root@~]# df -h /mnt
Filesystem            Size  Used Avail Use% Mounted on
/dev/xvdb             1.0G  187M  838M  19% /mnt

さらに、reflinkが面白いのはスナップショットにあるマスター/スレーブのような主従関係がないことです。つまり、reflink元のファイル、a.txtを消去してもaa.txtは影響を受けません。容量は効率的に消費するものの、ファイルとしては完全に独立しているのです。

[root@~]# rm a.txt
[root@~]# cat aa.txt
abc
def

楽し過ぎます。これがOCFS2 1.6の目玉機能、reflinkです。

with 3 comments

Written by 中嶋 一樹

9月 21st, 2010 at 3:07 pm

Posted in Uncategorized

Tagged with , ,

OCFS2のreflink機能

OCFS2はLinuxカーネルのメインストリームに採用されているクラスターファイルシステムで、Oracle VMにおいて仮想マシンのデータを格納する共有ストレージはOCFS2でフォーマットします。(NFSの場合を除く)

このOCFS2ですが、現在魅力的な新機能が開発されています。それはreflinkです。

このreflinkについてOracle VMの責任者Wimが最近ブログエントリーを書いています。

OCFS2 reflink by Wim Coekaerts on May 4, 2009

以下はこのブログエントリを簡潔にまとめたものです。

reflinkとは簡単に言えばファイルのスナップショット機能です。あるファイルをreflinkするとそのファイルがコピーされたようになりますが、実際のデータブロックは複製せずに同じ実体を共有しており、新たに作成するはのはその新規ファイルを指すinodeだけです。そして該当データに書き込みが会った場合にはじめてデータをチャンクと呼ばれる単位でコピーするというCoW(コピー・オン・ライト)という仕組みを使っています。したがってreflinkした時点では新しいファイルはディスクを消費しません。その後も変更されないデータブロックについては共有したままとなり、特にVM環境でのテンプレートプロビジョニングにおいて大幅なディスク消費削減が見込まれます。CoWは新しいプロセスをfolkしたときのメモリのコピーにも同様の仕組みが採用されていたり、考え方自体は目新しいものではありません。ただし、このファイルベースのCoWは通常特殊なファイルフォーマットを必要とします。例えばVMwareのvmdkやMicrosoftのVHDです。OCFS2の場合はユーザはそれを意識する必要はありません。違うのはファイル複製時にcpではなくreflinkコマンドを使用するというだけです。reflink元のファイルもreflink後のファイルも通常のファイルとして扱うことができ、ユーザもOS(VFSまでの上位レイヤ)もその違いを意識することはありません。そしてOCFS2のファイルなので当然クラスターの中で安全にどのサーバからも取り扱うことができます。

実際このreflink機能の開発をはじめたのはOracle VMを見据えてとのこと。前述したVMテンプレートのプロビジョニングや既存VMの複製、バックアップではこの機能はめちゃくちゃ重宝しそうです。まだOracle VM用のreflink対応OCFS2バイナリはでていませんが、近々テストパッケージをリリースするようです。楽しみですね。

without comments

Written by 中嶋 一樹

5月 11th, 2009 at 3:15 pm

Posted in Uncategorized

Tagged with

OCFS2をローカルだけで使うには

OCFS2は主にFibreChannelやiSCSIで接続されたボリュームを複数サーバからマウントしてサーバ間でデータを共有できるようにするためのクラスターファイルシステムです。
OCFS2でボリュームをフォーマットしたりマウントするためには、通常クラスタの情報を記述したcluster.confファイルが必要になります。なので気軽に使うにはちょっと面倒、と感じている方もいらっしゃるかもしれません。しかし実はこのOCFS2、クラスタファイルシステムとしてではなく、ローカルだけで(スタンドアロンで)使用するファイルシステムとしても利用できます。その場合はcluster.confといった設定ファイルも作成する必要がありません。

OCFS2をローカルのみで使用するようにするには、ボリュームを”-M local”オプションをつけてフォーマットするだけです。

# mkfs.ocfs2 -M local --force /dev/sdb

これでOKです。あとは普通にマウントすれば使えるようになります。

# mount /dev/sdb /var

without comments

Written by 中嶋 一樹

2月 10th, 2009 at 2:45 pm

Posted in Uncategorized

Tagged with