2012年2月22日水曜日

PHP FUSEのセグメンテーション違反とバスエラーについて

こんなコマンドを流すと、PHP FUSEが落ちます(ファイル数4000個くらい?)。

mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt & find mnt &

1撃で落ちることもあれば、10回くらいで落ちることもあります。ログの位置も微妙にずれていて、確実に特定できるわけではないんですが。

コチラを参考に改修したら、確かに落ちなくなりました。
https://github.com/fujimoto/php-fuse/issues/5

I made 3 changes: removed "convert_to_array_ex(entry);" and the "zval_ptr_dtor(tmp_type);" and "zval_ptr_dtor(tmp_ino);".


個人的メモ。

2012年2月21日火曜日

PHP FUSEで関数呼び出しにUIDとGIDを付与したい


前エントリの通り、ユーザーのUIDやGIDに応じた処理を実装するには、全関数呼び出しについて引数にユーザーのUIDとGIDを付与してやる必要があるようです。というわけで、また魔改造してみました。

■改造場所
php_fuse_call_methodの中で、付いてない引数を勝手にねつ造します。

■改造内容(強引ですが)
HashTable *function_table; の直後に
uid_t uid;
gid_t gid;
uid = fuse_get_context()->uid;
gid = fuse_get_context()->gid;
zval *arg_uid;
zval *arg_gid;
MAKE_STD_ZVAL(arg_uid);
ZVAL_LONG(arg_uid, uid);
MAKE_STD_ZVAL(arg_gid);
ZVAL_LONG(arg_gid, gid);

-zval ***params = emalloc(sizeof(zval**) * (param_count));
+zval ***params = emalloc(sizeof(zval**) * (param_count+2));

va_end(va_params); の直後に
*(params+param_count) = &arg_uid;
*(params+param_count+1) = &arg_gid;
param_count = param_count+2;

efree(params); の直後に
zval_ptr_dtor(&arg_uid);
zval_ptr_dtor(&arg_gid);

■使い方
こんな感じで、全関数でUID/GIDを取得できるようになりました。
(変更前)function mknod($path, $mode, $dev)
(変更後)function mknod($path, $mode, $dev, $uid, $gid)


全然テストしてませんけど、一応動いてるみたいなんで、これでいいやw

2012年2月20日月曜日

PHP FUSEでuidやgidを正しく反映するには


引き続きPHP FUSEを魔改造させていただいております。

PHP FUSEでファイルやディレクトリを新規作成すると、操作を発行したユーザーのUIDやGIDによらず、常にPHP FUSEの実行権限で作成されてしまいます。なぜなら、オーナー情報がPHP FUSEから通知されてこないし、FUSEが気を利かせて自動でchownを呼んでくれたりもしないからです。このままでは一般用途のファイルシステムを作るには難があります。そこで、新規作成系の操作の直後に、自動的かつ強制的にchownが呼び出されるようにPHP FUSEを改造してしまいました。


■改造個所
php_fuse_mknodの中
php_fuse_mkdirの中

■改造内容
以上の関数内の最後のreturn r;の直前に、以下の行を挿入。
php_fuse_chown(path, fuse_get_context()->uid, fuse_get_context()->gid);

失敗しても別に構いやしないんで、戻り値は捨ててしまえ(えー

■備考
symlinkとlinkについては、どう実装するかは検討の余地があると思う。リンク自体のUID/GIDをサポートしているシステムとそうでないシステムがあるし、PHPの挙動はドキュメントに書いてないので大分怪しい。勝手にchownを呼ぶより、ファイルを作成する系の関数に引数で渡してあげるようにしたほうが適切かも知れない。

よって以下は未実装のまま放置。
php_fuse_symlinkの中
php_fuse_linkの中
php_fuse_chown(path_from, fuse_get_context()->uid, fuse_get_context()->did);

■追記
読み出し制御したい場合、全ての関数に実装が必要ですよねぇ。

PHP FUSEのパフォーマンス計測(暫定)


PHP FUSEで、パススルーするだけのダミーファイルシステムを作ってみました。PHP FUSEを経由することによるオーバーヘッドを調べるべく、一応bonnie++でベンチしてみました。

■マウントオプション
allow_other,kernel_cacheを有効にしました。direct_ioを有効化するとシーケンシャルアクセスのブロックサイズが巨大化(4KB->120KB)して大幅に高速化(1.5倍速くらいに達するだろうか)するようですが、書き込み待ちや複数アクセス時のプチフリっぷりが気になったので、切りました。

■ベンチ結果まとめ
read/writeともに、ブロックサイズの大小によって挙動が大分変わるようです。シーケンシャルアクセスに関しては無視できる程度の影響であるようでした。CPUパワーは15%くらいでムンムン使っているものの、速度には影響せず。しかしブロックサイズが小さいとパフォーマンスダウンが激しいようです。特にseekの遅さの影響をモロに受けているようです。現状read&writeの度にfseekを発行しているんで、前回のoffset情報をもとに要不要を判定して余分なfseekを抑制すると、速くなったりしないかな? また今度やってみよう。

■具体的な結果:NFSマウント(From:CentOS5.7 DomU on CentOS5.7 / To:OpenIndianaのZFS)
Version  1.96       ------Sequential Output------ --Sequential Input- --Random-
Concurrency   1     -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Machine        Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP  /sec %CP
toreteru-dev-www 2G   575  98 33267   3 21715   4   835  99 40707   1  8868 175
Latency             29500us   20753ms   10807ms   19498us     438ms   83160us
Version  1.96       ------Sequential Create------ --------Random Create--------
toreteru-dev-www01. -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
              files  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
                 16    25   0  2650   1    48   0    25   0  2923   0    50   0
Latency               422ms   36661us     647ms     529ms    7140us     352ms

■具体的な結果:PHP FUSE経由でスルーパスしたもの(現実的なエラー対策とか講じてますけど)
Version  1.96       ------Sequential Output------ --Sequential Input- --Random-
Concurrency   1     -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Machine        Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP  /sec %CP
toreteru-dev-www 2G    13   5 33111   3 13880   1   763  97 37051   2  2205  12
Latency              1502ms    9371ms    6478ms   26108us     534ms   54831us
Version  1.96       ------Sequential Create------ --------Random Create--------
toreteru-dev-www01. -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
              files  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
                 16    23   0  1842   1    49   0    24   0  1879   0    49   0
Latency               499ms    2074us    5770ms     429ms   10118us     282ms

■備考メモ
実装上、最大のハマりどころは、getattrで32bit超えの値を返すとPHP FUSEの中でオーバーフローしてしまう件。これは前エントリの通り強引にパッチ当てで解消しました。

次なるハマりどころは、mknod関数の実装じゃないでしょうか。パススルーしようにも、PHPにはそのものジャストのmknod関数が存在せず。posix_mknodなる聞き慣れない関数でお茶を濁しましたが、使い方が合ってるのか、よくわかりません。引数がメジャーとマイナーに分かれてる件は、PHP FUSEから渡されてきたバイト列を上位下位で2等分して渡せばいいのかなと勝手に解釈。動いてるし、FIFOとか使わないから、まぁいいや。ファイルシステム周りはシステムコールが使えないといろいろ不安ですね。

その次のポイントは、openの実装でしょうか。read&writeのたびにfopenしてると途轍もなく遅いので、openでfopenしたファイルハンドルをメンバ変数配列で保持&ファイルディスクリプタ番号を自前で生成して返却(3〜255)、releaseでfclose、writeとreadとreleaseはpathは無視してファイルディスクリプタ番号を元にメンバ変数で保持したファイルハンドルを特定して作業するって寸法で実装しました。ファイルディスクリプタ番号は有限なので、空き番号を管理する仕組みも入れておきました。

Linux開発の本を読んでおいてよかったなぁ。

PHP FUSEで2GB超のファイル容量を正しく報告できない件について


激しく環境依存ぽいんで、アレですけれども。。

■検証環境
CentOS6.2 + FUSE 2.8.7

■現象
2GB超のファイルをlsしたりstatしたりするとオーバーフローっぽい値が表示される。

■修正内容(手抜き)
fuse.c
(修正前)int value = Z_LVAL_PP(entry);
(修正後)long value = Z_LVAL_PP(entry);

※2個所あります。だいたい前者だけで大丈夫だと思いますが。
PHP_FUSE_API int php_fuse_getattr(const char * path, struct stat * st) 内
PHP_FUSE_API int php_fuse_statfs(const char * path, struct statfs * st) 内

いかにも対症療法ですが、正しくはどうすればいいんでしょうね。。
Z_LVAL_Pも同様のようですが、とりあえず動いたんで、これで…^^; スミマセン


あ、あと、これもかな。。違うかな。。
(修正前)st->st_size = (size_t)value;
(修正後)st->st_size = (off_t)value;

2012年2月8日水曜日

ZFS-FUSE 0.7.0をCentOSに導入する


epelのrpmは0.6.9です。なんと0.7.0ではxattrが使える=GlusterFSで使えるようになったということなので、試してみたいと思いました。

ソースから入れると当然、パスやサービス登録がめちゃめちゃなので、epelのsrpmをお借りしてソースを最新に入れ替えるという方法で導入しときました。

以下手抜きメモになります。パスとかデタラメなので参考にされる方は読み解いてください;

yum install -y fuse-devel libattr-devel libaio-devel libacl-devel zlib-devel fuse-devel scons openssl-devel
yum install rpm-build

wget http://download.fedora.redhat.com/pub/epel/6/SRPMS/zfs-fuse-0.6.9-6.20100709git.el6.src.rpm
rpm -i zfs-fuse-0.6.9-6.20100709git.el6.src.rpm
cd rpmbuild/SOURCES
wget -c 'http://gitweb.zfs-fuse.net/?p=official;a=snapshot;h=maint;sf=tgz' -O 'zfs-fuse-0.7.0-snapshot.tar.gz'
rm zfs-fuse-0.6.9-snapshot.tar.gz
cd ../SPECS
vi zfs-fuse.spec

2,3c2,3
< Version:          0.6.9
< Release:          6.20100709git%{?dist}
---
> Version:          0.7.0
> Release:          7.20120208git%{?dist}
10c10
< #   wget -c 'http://gitweb.zfs-fuse.net/?p=official;a=snapshot;h=maint;sf=tgz' -O 'zfs-fuse-0.6.9-snapshot.tar.gz'
---
> #   wget -c 'http://gitweb.zfs-fuse.net/?p=official;a=snapshot;h=maint;sf=tgz' -O 'zfs-fuse-0.7.0-snapshot.tar.gz'
12c12
< #   make new-sources FILES="zfs-fuse-0.6.9-snapshot.tar.gz"
---
> #   make new-sources FILES="zfs-fuse-0.7.0-snapshot.tar.gz"

cd ..
rpmbuild -bs --clean SPECS/zfs-fuse.spec

※エラー・・・tarボールの中身がまずいらしい、強引に修正しちゃう
tar zxvf zfs-fuse-0.7.0-snapshot.tar.gz
mv official-maint-6abfdcf official
tar czvf zfs-fuse-0.7.0-snapshot.tar.gz official

※気を取り直して
cd rpmbuild
rpmbuild -bs --clean SPECS/zfs-fuse.spec

rpm -Uvh RPMS/x86_64/zfs-fuse-0.7.0-7.20120208git.el6.x86_64.rpm

よし、入った。

※20120220追記
これ結局やめました。orz
これでもってマウントオプションでxattrを有効にすると想定通りGlusterFSで使える状態でマウントできました。これでGlusterFSとZFSを組み合わせてウハウハだぜ、と思ったら、ZFS-FUSEのヘルプメッセージに書いてある通り、パフォーマンスが大幅に劣化しておりまして…。正確には覚えてなくてすみませんが、無視できない感じで猛烈に遅かったんで、結局GlusterFSもろとも諦めました。orz 今は、「2台あるから落ちても大丈夫」ではなくて「そもそも落ちない」ストレージの構築を目指して、OpenIndianaの導入に踏み切っております。なかなかうまくは行きませんね。

2012年2月7日火曜日

時々ファイルのタイムスタンプが失われてしまう件


以下のような構成があるとします。ていうか、あります。

サーバA:FreeBSD(ZFS)
サーバB:CentOS6.2(GlusterFSクライアント)
サーバC:CentOS6.2(XFS/GlusterFSホスト、ローカルでレプリケーション構成)

サーバCは複数のGlusterFSボリュームをエクスポートしており、サーバBはそれをmhddfsで束ねてマウントしています。このマウントポイントを「/hogemoge」とします。

この状態で、サーバBにて以下のようなrsyncを実行します。
rsync -a サーバA:/hoge/moge/* /hogemoge/

つまりサーバAからrsyncプロトコルで読み出し、サーバCへmhddfs+GlusterFSを介して書き出します。

すると500ファイルに1件くらいでしょうか。ファイルのタイムスタンプ(Modify)が失われる現象が発生するようです。由々しき事態です。
タイムスタンプが失われたファイルには、(ZFSが1sなのに対し)1nsの日付分解能をもつタイムスタンプが書き込まれています。ファイルを書いた時点のタイムスタンプが適用されているようです。rsyncによる日時の修正処理が適用されていない状態になっているようです。

原因は不明ですが、何らかの理由でタイムスタンプが正しく設定されていないタイミングで「ファイル情報に不一致があった場合、新しい方を正とする」というGlusterFSの仕様が発動して不要なレプリケーションが走ってしまい、不正なタイムスタンプが設定されてしまっているのかなぁと想像したりしています。rsyncがファイルを書き込んでタイムスタンプを修正した後、GlusterFSが片方のファイルのタイムスタンプを更新した段階でファイルの復元処理が走り、新しいタイムスタンプのファイルで上書きされてしまったりしているんじゃないかなぁと。

ローカルで2台レプリケーションっちゅー構成がイレギュラーなのかな。。うーん。。。
やっぱり本物のハードウェアでテストしたいなぁ。。

2012年2月4日土曜日

GlusterFS+mhddfsの書き込み速度の検証


mhddfs→GlusterFSと、FUSEを2回通ることによるパフォーマンスダウンが懸念されますので、簡単にベンチしてみました。

■別マシンの仮想サーバからネットワーク越しに書き込みテスト
○準備運動
[root@gluster01 storage]# dd if=/dev/zero of=/dev/null bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB) copied, 0.153937 s, 6.8 GB/s

○mhddfsを通さずGlusterFSに直接書き込み
[root@gluster01 storage]# dd if=/dev/zero of=pair01/zero3 bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB) copied, 22.86 s, 45.9 MB/s

○mhddfsを通してGlusterFSに書き込み
[root@gluster01 storage]# ls
pair01  pair02  pair03  pair04  storage01
[root@gluster01 storage]# dd if=/dev/zero of=storage01/zero4 bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB) copied, 67.8727 s, 15.4 MB/s

■同一マシンのローカルで書き込みテスト
○準備運動
[root@kfs02 storage]# dd if=/dev/zero of=/dev/null bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB) copied, 0.0946512 s, 11.1 GB/s

○mhddfsを通さずGlusterFSに直接書き込み
[root@kfs02 storage]# dd if=/dev/zero of=pair01/zero bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB) copied, 47.8904 s, 21.9 MB/s

○mhddfsを通してGlusterFSに書き込み
[root@kfs02 storage]# dd if=/dev/zero of=mhddfs01/zero2 bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB) copied, 45.7485 s, 22.9 MB/s

■結果まとめ
リモートとローカル、mhddfsの使用と不使用で、結果が全然違う。
ローカルの方が当然速いだろうと思いきや、リモートでmhddfs不使用がダントツで速い。でもmhddfsを通すと一気に遅くなる。
ローカルではmhddfsの使用不使用は関係なく、同じくらい遅い。
何度か繰り返しましたが、同等の結果が得られました。

■考察
意外な結果になりました。
リモートでmhddfsが遅くなるのは、ネットワークを経由することによるレイテンシ起因とかでしょうか。同期書き込みなら妥当な挙動かなぁ。
ローカルアクセスとリモートアクセスでGlusterFSの速度が段違いなのは、リモートでアクセスするとGlusterFSの処理がリモートとローカルに分割されるので高速化するとか、そんなところでしょうか。

○リモート/クライアント側
・mhddfsあり
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
15763 root      20   0  251m  20m 1424 S 106.7  6.6  66:46.59 glusterfs
15988 root      20   0  309m  960  384 S 19.9  0.3   0:39.16 mhddfs
18092 root      20   0  103m 1696  576 S  4.0  0.5   0:01.16 dd

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND          
15763 root      20   0  251m  20m 1424 S 24.3  6.6  67:42.98 glusterfs        
18134 root      20   0  103m 1700  580 S  4.3  0.5   0:00.68 dd              

○リモート/サーバ側
・mhddfsあり
    PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 4654 root      20   0  410m  22m 1912 S 22.2  0.3  50:14.01 glusterfsd
 4658 root      20   0  410m  22m 1916 S 20.6  0.3  49:10.81 glusterfsd

・mhddfsなし
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 4654 root      20   0  412m  22m 1912 R 34.5  0.3  50:51.63 glusterfsd
 4658 root      20   0  412m  22m 1916 R 33.5  0.3  49:46.95 glusterfsd

○ローカル(ちなみにsystem負荷が高かったので、XFSの負荷も無視できないかも知れません)
・mhddfsあり
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
12848 root      20   0  230m  35m 2140 R 121.2  0.5   3:25.39 glusterfs
 4654 root      20   0  414m  22m 1912 S 55.1  0.3  52:43.88 glusterfsd
 4658 root      20   0  414m  22m 1916 S 50.8  0.3  51:36.55 glusterfsd
13092 root      20   0  309m  904  544 S 16.6  0.0   0:09.56 mhddfs
14460 root      20   0  103m 1688  568 S  5.6  0.0   0:00.50 dd

・mhddfsなし
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
12848 root      20   0  230m  35m 2116 R 103.8  0.5   2:36.40 glusterfs
 4658 root      20   0  414m  22m 1916 R 100.8  0.3  50:56.41 glusterfsd
 4654 root      20   0  414m  22m 1912 R 93.7  0.3  52:05.21 glusterfsd
14452 root      20   0  103m 1684  568 S 44.4  0.0   0:02.82 dd

■で、どうする?
遅いけど、まぁ、仕方ないよね。。データの初期コピーの最初だけ、mhddfsを通さずに実施したいと思います。
読み出しは、どの組み合わせでも70〜80MB/sくらい出るようなので問題視しないことにします。。

mhddfsが導入できないクライアントのための中継機能は、ストレージサーバ自体に持たせようと思います。mhddfsで束ねた領域をNFSでエクスポートしちゃうの。パフォーマンスが多少いいので。

mhddfsとGlusterFSの組み合わせ方


GlusterFSとmhddfsの組み合わせ方を逆にしてみようと思いました。
神が舞い降りてきた感じがします。

■これまでの発想
ハードディスクをmhddfsで束ねて作った領域を、他サーバとGlusterFSでミラーリングする。
クライアントでGlusterFSをマウントする。

■これからの発想
ハードディスクをGlusterFSで他サーバのハードディスクとミラーリングする。
クライアントでGlusterFSをマウントし、それをmhddfsで束ねる。

■絵にしてみた

■違い
これまでは、サーバ内で複数のHDDをmhddfsで束ねたうえで、そこにフォルダを掘って、GlusterFSでサーバ間ミラーしようと思っておりました。
これからは、ディスク単体についてGlusterFSでサーバ間ミラーしたうえで、クライアント側でmhddfsを使って領域を結合しようと思いました。

"これまでの構成"だとディスクの容量がバラバラでも余すところなく使えますが、反面、どのディスクに何のファイルが入っているか明確になりません。たとえ容量が揃っていても、ディスクが欠落するとGusterFSが他のディスクに復元を始めてしまいます。復元を完了させるにはディスクの全域にわたってfind&statしなければならず、容量に比例して所要時間が膨大なものになります。両サーバのHDDが1台づつ故障した時点でデータロストが発生します。また、GlusterFSがmhddfsを経由してディスクにアクセスするなんてことはGlusterFS開発陣は想定していないでしょうから、どのような不具合が出るか、わかりません。

"これからの構成"だと、対になるディスクは容量が揃っていないとGlusterFSの動作に不具合が生じますが、ディスクのペアごとに、記録内容が完全に一致します。あるディスクが停止しても、GlusterFSはHAを維持してくれますが、勝手に復元することはありません。復元を完了させるには当該ペアだけfind&statすればよく、範囲を限定できます。ペアのディスクが同時に故障した時点でデータロストが発生しますが、これまでの構成よりは確率的に低いといえるでしょう。GlusterFSへの書き込みはmhddfsを使用しますが、GlusterFS自体は検証済みのファイルシステムを直接使用しますから、問題が発生する可能性は少ないでしょう。

"これからの構成"の欠点としては、全クライアントにmhddfsを導入しなければならないので、OS環境を選びます。現在主力のCentOS5.7では正しく使用できません。まぁこれは、SPOFを受認しなければなりませんが、GlusterFS+mhddfsをNFSで再エクスポートする中継サーバを用意すれば回避できそうに思います。あとディスク構成を変更した場合にクライアント間で設定変更のタイムラグが発生しますので、運用手順をよく検討すればいいかなと。

■雑感
そもそも言ってしまえば、GlusterFSのバランシングアルゴリズムが微妙なんですよねぇ。性能差を考慮しない均等なハッシュ割り当てって、ちょっとねぇ。それによる諸問題をmhddfsで回避して、実用的にしてみようという試みです。

こんな感じで、あと一晩考えてみたいと思います。

2012年2月3日金曜日

CentOS6.2にいろんなファイルシステムを導入する方法 まとめ


Linuxでいろんなファイルシステムを試してみたいと思って、いろいろ導入してみたので、メモしておきます。

■検証環境
CentOS6.2 x86_64

■ELrepoとEPELの導入(一部のファイルシステムで使用、必要に応じて)
rpm -Uvh http://elrepo.org/elrepo-release-6-4.el6.elrepo.noarch.rpm
sed -i 's/enabled=1/enabled=0/g' /etc/yum.repos.d/elrepo.repo

rpm -Uvh http://download.fedora.redhat.com/pub/epel/6/x86_64/epel-release-6-5.noarch.rpm
sed -i 's/enabled=1/enabled=0/g' /etc/yum.repos.d/epel.repo


■XFSの導入
yum install xfsprogs

ファイルの一覧取得は速いけど、削除は遅いらしい。大容量対応と高信頼性がウリだと思うんですけど、fsckにメモリを食うとか、ハード障害に弱いとか、ジャーナリングしてるくせに電プチすると結構よく壊れるとか、色々言われている様子。現時点でどこまで改善されているのか、よくわかりません。
x86_64ではローカルアクセス以外の、NFSなんかで使うとkernel panic連発とか。本当かな。でも僕もmhddfsとGlusterFSを経由してファイルを大量コピーしてる最中に原因不明のリブートが発生した時は、XFSを使っていた。その後はリブートしてない。濡れ衣かも知れないけど、状況的には疑わしいと言えるかも知れない。要重点検証。
GlusterFSではXFSが推奨されています。他のファイルシステムでも使えるけど、あんまり検証してないよって。でも僕がやろうとしているmhddfsをかましてGlusterFSで束ねるって方法だとGlusterFS開発陣による検証とか関係ないような気がするので、他のファイルシステムと横並びで比較してみたいと思います。


■JFSの導入
yum --enablerepo=elrepo install kmod-jfs

XFSと似たような特性らしいが、CPU負荷が低いらしい。悪い噂を聞かないのは、導入事例が少ないせい? ざっくり使った所、なんとなくレスポンスが遅い感じがする。ライトキャッシュの効きが甘い? 古いんでSMPではスケールしない? よくわかんないんで、ちゃんと検証しておきたいなと思います。


■ReiserFSの導入
yum --enablerepo=elrepo install kmod-reiserfs reiserfs-utils

将来性が云々と言われます。。しかも、これも性能的にはXFSとそんなに変わらないらしいけど。。まぁ何を選んでも数年後には見直すことになるでしょうから、今回は検討の対象に入れておきます。

※2012/2/4追記
GlusterFS3.2.5ではReiserFS(3.6)は使用不可のようでした。ドキュメントにはReiserFSもOKと書いてあるんですけど、正常にマウントできません。ReiserFSパーティションにattrコマンドを発行するとattrコマンドが落ちるので、多分attrコマンドかReiserFSのattr周りのハンドリングに何らかの問題があるんじゃないかと思いました。
ということは、GlusterFS on Linuxで使えるファイルシステムは、通常であればext3/4、XFS、JFSに絞られるかと思います。

■NILFS2の導入
rpm -Uvh http://www.nilfs.org/pub/centos/6/RPMS/x86_64/kmod-nilfs2-0.3.1-1.el6.x86_64.rpm
rpm -Uvh http://www.nilfs.org/pub/centos/6/RPMS/x86_64/nilfs-utils-2.1.1-6.x86_64.rpm

常時自動スナップショット。CoW。ファイル削除が鬼のように速いらしい。ただしファイルを部分的に更新すると激しく断片化するという。倉庫には向いてそうだが、起動ディスクや仮想マシンイメージには向いてなさそう。用途が読み切れないので今回は検証しません。導入方法のメモだけ残しておきます。


■Btrfsの導入
yum install btrfs-progs

ZFS並みに色々詰め込まれたファイルシステム。これが入れられれば悩み事は大体解決しそう。でもまだプロダクション環境で使える品質でないようなので検討しません。導入方法のメモだけ残しておきます。


■ZFS-FUSEの導入
yum --enablerepo=epel install zfs-fuse

もしやと思ったけれども、やっぱりattrは使えなかった。ZVOLも未サポート。よってGlusterFSとは組み合わせ不可になりますので検証しませんが、導入方法のメモだけ残しておきます。ZFS自体の性質上、パフォーマンスは半ばどうでもいい気がするんですが、FUSEでメモリ消費とかどうなんでしょうね。

GlusterFSの異常系の検証(ディスク編)


CentOS 6.2
GlusterFS 3.2.5
mhddfs 0.1.38

仮想サーバ2ノードでreplicaして、他のノードからNative Clientでマウントしました。
今回はディスクイメージをマウントしたディレクトリで検証しました。

■まとめ
実機検証じゃないと何とも言えないですね。
あるいは実機だったとしても、どこまで実際の故障を再現できるものか。
これはもう定期バックアップを前提にぶっつけ本番投入するしかないかしら。
仮想サーバでの検証では、わかんないです。

書き込み中にdisk01が消滅した場合(rm -rf disk01.img )
→何故か書き込み続行され、イメージが削除されているにも関わらず正常動作が続く。不気味。
※物理マシンでHDDをぶっこ抜いた場合とは挙動が違うんじゃないかな。。

書き込み中にmhddfsがumountされた場合(umount -l mhddfs01)
→片方のノードのみで書き込み続行。
→書き込みが完了するとアクセスできなくなる。
→復帰すると稼動再開

書き込み中にdisk01がumountされた場合(umount -l disk01)
→片方のノードのみで書き込み続行。
→書き込みが完了するとアクセスできなくなる。
→復帰すると稼動再開


■準備
mkdir /storage
cd /storage
dd if=/dev/zero of=disk01.img bs=1M seek=1000 count=1
mkfs.xfs disk01.img
dd if=/dev/zero of=disk02.img bs=1M seek=1000 count=1
mkfs.xfs disk02.img
mkdir disk02
mkdir disk01
mount -o loop disk01.img disk01
mount -o loop disk02.img disk02
mkdir mhddfs01
mhddfs -o mlimit=10% disk01,disk02 mhddfs01

↑これを192.168.0.131と192.168.0.132の両方でやっておく

gluster peer probe 192.168.0.132
gluster volume create kfs replica 2 192.168.0.131:/storage/mhddfs01/kfs 192.168.0.132:/storage/mhddfs01/kfs
gluster volume start kfs

他のサーバでマウントする。
mkdir kfs
mount -t glusterfs 192.168.0.131:kfs kfs

■書き込み中にdisk01が消滅した場合(rm -rf disk01.img )
ディスクが物理的に外れた場合を想定。

書き込み中に192.168.0.132でdisk01.imgをrm -rfする
→何も起こらない。書き込み続行。

192.168.0.132のdisk01.imgは確かに消滅しているのに、mhddfsやdisk01の中身は正常に書き込み進行しているように見える。
GlusterFSやmhddfsを通さずとも、mountもdf -khもstatも、あまつさえdd of=/dev/nullでさえも、あたかもそこに完全なファイルが正常に存在しているかのような挙動を示す。
一体どこに書き込んだのか不明である。disk01を一旦umountすると、復旧できない(だってdisk01.imgがないもの)
消す前のdisk01.imgを作り直したり再設置したりしても何ら影響無し。切り離されて動いている様子。
容量的には元のdisk01.imgと同じサイズが上限になる。それでも割り当てメモリは超えてるし、swapしてる様子も無い。

えー、GlusterFSもmhddfsも関係ないっぽいけど、なんか驚愕の挙動なんですけど。。
仮想マシンイメージの実サイズが膨らんでたので、どこかに一時ファイルが作られているとしか。。。
ディスクイメージをマウントするのに-o loopしてるので、その影響でしょうか。。
実機じゃないと検証にならんな。。でも空きマシンは無いなぁ。。

■書き込み中にmhddfsがumountされた場合(umount -l mhddfs01)
mhddfsが落ちた場合を想定。内容が消失してローカルディレクトリに差し変わる結果、brickとして使っているディレクトリが消滅する。
GlusterFSがどのように動作するか、見物である。

書き込み中に192.168.0.132でumount -l mhddfs01する
→何も起こらない。書き込み続行。

書き込み完了後、クライアントでマウントポイントにアクセスできなくなる。
> ls: kfs: 入力/出力エラーです

mhddfs01を再マウントすると自動復帰する

■書き込み中にdisk01がumountされた場合(umount -l disk01)
mhddfsが束ねているファイルシステムが落ちた場合を想定。
mhddfsがどのように動作し、GlusterFSにどのような影響を与えるか、見物である。

書き込み中に192.168.0.132でdisk01をumount -fする
→192.168.0.132は止まり、192.168.0.131だけで書き込み続行。

書き込み完了後、クライアントでマウントポイントにアクセスできなくなる。
> ls: kfs: 入力/出力エラーです

disk01.imgを再マウントすると自動復帰する

2012年2月2日木曜日

GlusterFSの異常系の検証(ディレクトリ編)


CentOS 5.7
GlusterFS 3.2.5
※今回はmhddfsは無し。

2ノードでreplicaして、他のノードからNative Clientでマウントしました。
今回はディレクトリで検証しました。

こんな感じ。
gluster volume create kfs replica2 192.168.0.252:/storage/disk01/kfs 192.168.0.252:/storage/disk02/kfs

■まとめ
異常があったら、まずglusterdを落として、じっくり検討。
復帰操作は一発勝負。勝手に書かれちゃうんで。

glusterdプロセスが落ちた場合
→いずれかのプロセスが存在すれば正常稼動する。
→両方落ちると書き込み異常終了。
→いずれかが復帰すると稼動再開。
※これは想定内な感じがします。

brickのディレクトリが消滅した場合
→いずれかのノードが稼動していれば正常稼動する。
→両方落ちても書き込み続行。データは行方不明に。
→復帰時は両方のノードが稼動するまで復帰できない
※要するに考慮されてないっぽいので、こういうオペレーションはダメっぽい


■glusterdプロセスが落ちた場合の挙動確認
書き込み中に片方のglusterdを落とす
→残ったノードだけで書き込み続行

書き込み中に落としたglusterdを、その書き込み中に上げる
→すぐには何も起こらないが、書き込み終了後に復元動作が走り、落とした方が修復される

書き込み中に両方のglusterdを落とす
→書き込み異常終了
> dd: writing `kfs/zero': 通信端点が接続されていません
> dd: 出力ファイル `kfs/zero' をクローズ: 通信端点が接続されていません
マウントは外れていないが、参照できない状態になっている。
変なファイルがローカルディスクに書き込まれる恐れは無さそう。

そのまま片方のglusterdを上げる
→即、自動復帰する

もう片方のglusterdも上げる
→タイムラグがあるようだが、数十秒以内に自動復帰する
→ファイルアクセスをキックに、差分も自動修正される

■brickのディレクトリが消滅した場合の挙動確認
書き込み中に片方のディレクトリをrm -rfする
→残ったノードだけで書き込み続行

書き込み中に消したディレクトリを、その書き込み中に再作成する
→復帰するようだが、直ちには何も起こらない
→ファイルアクセスをキックに、差分も自動修正される

書き込み中に両方のディレクトリをrm -rfする
→何も起こらない。書き込み止まらない。
マウントは外れていないが、参照できない状態になっている。
変なファイルがローカルディスクに書き込まれる恐れは無さそうだが、データはどこに消えているか不明。

そのまま片方のディレクトリを再作成する
→自動復帰しない。
> ls: kfs: 入力/出力エラーです
> touch: cannot touch `kfs/test': そのようなファイルやディレクトリはありません
> stat: cannot stat `kfs': そのようなファイルやディレクトリはありません

サーバ側のglusterdを再起動する
→何も起こらない。変化無し。
> ls: kfs: 入力/出力エラーです
> touch: cannot touch `kfs/test': そのようなファイルやディレクトリはありません
> stat: cannot stat `kfs': そのようなファイルやディレクトリはありません

クライアント側のglusterdを再起動する
→何も起こらない。変化無し。
> ls: kfs: 入力/出力エラーです
> touch: cannot touch `kfs/test': そのようなファイルやディレクトリはありません
> stat: cannot stat `kfs': そのようなファイルやディレクトリはありません

クライアントで一旦umountし、再マウントする
→何も起こらない。変化無し。
> ls: kfs: 入力/出力エラーです
> touch: cannot touch `kfs/test': そのようなファイルやディレクトリはありません
> stat: cannot stat `kfs': そのようなファイルやディレクトリはありません

もう片方のディレクトリも再作成する
→自動復帰する

同一ディレクトリに大量のファイルを設置した場合のパフォーマンス調査


ext3で、同一ディレクトリにファイルが大量に存在すると遅くなるというのは有名かと。
ext4では、H-treeで高速化したとwikipediaに書いてあったんですけど、期待ほどではなかった様子。。

以下、4985個のファイルが置いてあるディレクトリで試しました。一応2回づつ。
(ユーザーとしての個人的感覚では、そんなに大量というほどのファイル数ではないつもり)

■ext4(@CentOS6.2)
time ls disk01/kfs/pb/generated/122
real    0m16.153s
user    0m0.044s
sys     0m0.288s

time ls disk01/kfs/pb/generated/122
real    0m8.402s
user    0m0.034s
sys     0m0.104s

■XFS(@CentOS6.2)
time ls xfs05/kfs/pb/generated/122
real    0m0.175s
user    0m0.030s
sys     0m0.142s

time ls xfs05/kfs/pb/generated/122
real    0m0.075s
user    0m0.023s
sys     0m0.047s

■JFS(@CentOS6.2+ELrepo)
yum install jfsutils
rpm -Uvh http://elrepo.org/elrepo-release-6-3.el6.elrepo.noarch.rpm
yum install enablerepo=elrepo kmod-jfs
mount /dev/sdg jfs07
mount /dev/sdh jfs08

time ls jfs07/kfs/pb/generated/122
real    0m0.134s
user    0m0.021s
sys     0m0.092s

time ls jfs07/kfs/pb/generated/122
real    0m0.073s
user    0m0.026s
sys     0m0.043s

■ZFS(@FreeBSD)
/usr/bin/time -h -p ls /kfs01/kfs/pb/generated/122
real 0.12
user 0.00
sys 0.01

/usr/bin/time -h -p ls /kfs01/kfs/pb/generated/122
real 0.16
user 0.00
sys 0.01

ext4の圧倒的遅さが際立っております。
これで問題にならない使い方なら問題ないんでしょうけれども、僕の場合は問題ありありなので困ります。デジタル写真とか扱ってたら1フォルダ数百〜数千個くらいはすぐ貯まっちゃうでしょう。。貯めるなってのはユーザーフレンドリーじゃないのでダメです。

では何がいいかと言うと。。んー。。。やっぱりJFSかぁ?

mhddfsの容量フル時の挙動について(不具合報告)

mhddfsの不具合? マニュアルの記載ミス? を見つけました。
けどロシア語よくわかんないしw こちらで。

■対象バージョン
最新:mhddfs_0.1.38.tar.gz

■内容
# df -kh
Filesystem            Size  Used Avail Use% マウント位置
/dev/sda              917G  867G  4.0G 100% /storage/disk01
/dev/sdb              917G  3.1G  868G   1% /storage/disk02
/storage/disk01;/storage/disk02
                      1.8T  870G  872G  50% /storage/mhddfs01

うーむむむ、1台目を100%まで使い切っちゃってるじゃないか。空き容量が一切ないのはメンテナンス時にハマる可能性があるような気がする。READMEにはDefault value is 25%って書いてあったんだけどな。。
http://svn.uvw.ru/mhddfs/trunk/README

ていうかソース読んでみた。嘘じゃん。バグってるじゃん。
http://svn.uvw.ru/mhddfs/trunk/src/parse_options.c

#define DEFAULT_MLIMIT ( 4l * 1024 * 1024 * 1024 )
#define MINIMUM_MLIMIT ( 50l * 1024 * 1024 )

どこを読んでもデフォルト25%なんてインテリジェントなオプション解釈はやってない感じがする。ていうかマウント時のメッセージにもはっきり出てるじゃん orz
mhddfs: move size limit 4294967296 bytes

4GB決め打ちですね。容量9割がた埋まるとパフォーマンスが激落ちする某FSなんかで使うとハマるでしょうねぇ。。

%指定を解釈するロジックは入っていたので(100未満の値は%と見なしてますね)、その点は問題ないようです。

mhddfsを使う時は、今のところ、-o mlimit=XXの明示が必須ということで。

2012年2月1日水曜日

mhddfs+GlusterFSでレプリケーションを復元してみる


相変わらずローカル環境でのテストを続けております。
今回は、GlusterFSによるレプリケーションの自動修復を試してみました。

■準備
書き込み稼動中のディスク1台分のマウントを外してみた(umount -f)
→mhddfsおよびGlusterFSでinput/output errorが出て書き込めなくなった。今回はサーバ一台だけでテストしてますが、これ、複数サーバの1つが落ちた状態でも同じ動作なら意味ないですね。全然HAじゃない。要検証。

外したディスクをフォーマットした(mkfs.ext4 /dev/sda)
→あえてXFSじゃないのは、ext4も試してみたかったから。安定するならどっちでもいい。

ext4をmountした(mount)
→mhddfsもGlusterFSも、自動復帰しなかった。

mhddfsをrestartした(umount&mount)
→GlusterFSは自動復帰しなかった。

GlusterFSをrestartしてクライアントでマウントし直した(service gusterd restart, umount & mount)
→アクセスおk

■自動修復させてみた
ファイルにアクセスする度に自動復元されますが、案の定と言いますか、想像並みに重い感じでした。

ディレクトリの内容をlsすると、そのディレクトリ内のファイルが復元され、lsが帰ってきます。この段階ではファイルが欠損しているほうのディスクに空ファイルが作られるのみで、(おそらくそこにはattrで色々書かれていて)データ本体はまだミラーされていない状態に留まります。データ本体は同期しないので高速なんでしょうが、3000ファイルで30秒くらいかかりました。その間lsはフリーズ状態で待機です。対象ディレクトリに子ディレクトリエントリが含まれていた場合、おそらくその子ディレクトリ内のファイルの数を確定するためでしょうが、やたらめったら時間がかかります。複数のサブディレクトリ内に合計ウン十万個のファイルがあるディレクトリをlsした時、時間は計り忘れましたが2時間近くはCtrl-Cも効かなかったかなぁ。

データ本体はデータを読み出した時に復元されます。読みながら書いていくので、所要時間もそれなりです。ただlsの場合と違ってデータ本体に一括アクセスすることは普通ないと思いますので、これはさほど問題ないかなと思いました。でも3000ファイル4GBをtime cat * > /dev/nullで6分強。全体を完全に同期完了させるには全ファイルを読み出さないとならないので、データ量が増えると所要時間が半端無いですね。まぁ未使用領域はスキャンしないので、mdadmよりはマシと思うことにしましょうか。。brickに直接アクセスして同期すべきファイルを特定するスクリプトを作って回したら、読み出す範囲を限定できるので、部分的な損傷の時に高速化できるかなぁと思った。ちなみにcatで読み出すより公式コマンド「find <gluster-mount> -print0 | xargs --null stat >/dev/null」のほうが倍くらい速かった。20〜30MB/secくらい。バックアップマシンからrsyncでリストアするよりもちょびっと速いかも知れない。

■まとめ
当然ながらGlusterFSでのミラー復元はデータ量に応じて膨大な時間を要するので、これをアテにしたHDDの取り付け取り外しは現実的じゃないなと思いました。とはいえ普通のRAIDだって復元には膨大な時間がかかるわけですので、純粋に筐体間RAIDと考えて非常事態に備えるHA目的での運用は、あり得るのかなと思いました。

あとは複数サーバをまたがるボリュームの、異常系の動作検証が必要ですね。書き込みエラーでも動作継続できますように。

GlusterFS+mhddfs+XFSを試してみた


mhddfsで束ねたXFS領域をGlusterFSでミラーする構成を試しています。

■感想
・GlusterFSはCPUを大食いだ。
・速度は問題無し。むしろ想像より速くてびびった。
・なんか不安定な感じがする。だいぶ不安。

■構成
最終的にはネットワーク越しで構成しますが、マシンに空きがないので、とりあえずローカルでテスト。

○検証方法
・CentOS6.2をSDカードにインストールしてmhddfsとGlusterFSを導入する。
・XFSでフォーマットしたSATA HDDを4台用意する。
・mhddfsで2台ずつ束ねる。
・束ねたhdd領域をGlusterFSでレプリカする。
・他のサーバでマウントし、適当なテストデータを大量コピー(rsync)して様子を見る。

○挙動
以下いずれもGlusterFSかmhddfsかXFSか、どの影響かわかりませんが、気が付いた点。

・パフォーマンスは悪くない。Write/Read共に80〜90MB/sくらい出てます(WD10EADS-00L5B1)。なんだ、ZFSなんかよりよっぽど速いじゃないか。RAID1の同一ディスクにイメージファイル作ってXFSフォーマットしてマウントしてGlusterFSでレプリカして、なんていう構成だと4MB/sくらいだったし、mhddfsは遅いという話を散見してたのでドキドキしてましたが、これなら実用に堪える感じ。同一ディレクトリに1万個くらいファイル設置してみましたが、これも応答速度に問題無し。XFSのおかげでしょうが。ランダムアクセスはあんまり発生しないので調べなくていいや。

・コピー途中に本構成を仕込んでるサーバが突然リブートした模様; SDカード起動の影響かな。。これなんか不安定なんすよ。SDカードはそのままにアダプタを変えると挙動が大幅に変わるし。でも起動ディスクごときにSATAポート取られたくないんだよなぁ。。

・発生条件がよくわかりませんが、permission errorでmhddfs領域に書き込めなくなる場合がある模様(もちろんpermission設定的には書き込める状態ですよ、ディレクトリ777とかで)。mhddfsのマウントし直しで解消。書き込めない最中はクライアントに対してはGlusterFSを通じてpermission errorがそのまま返る模様。多いに不安。dmesgには何も出てないし発生の瞬間には立ち会っていなかったのでよくわかりませんが、両方とも発生してたので、もしかするとmhddfsのせいじゃないかも知れない。またネットワーク越しだと違うかも知れない。

・mhddfsをGlusterFSで束ねるんですが、GlusterFS領域をローカルでマウントできません。mountコマンドを打っても無視されます。もちろんmhddfsを通さなければ動作します。FUSEの2重化が不可なんでしょうかね。ネットワーク越しではマウントできるので目をつぶることにします。

・ディスクへの書き込みは同時ではなく数秒おきにラウンドロビンするようですが、同時並行アクセスが全くないわけではないようです。ライトキャッシュも効いてる様子で、細かいファイルはかなり溜め込んでから書き込んでます。メモリ消費具合や挙動から察するに、GlusterFSがラウンドロビンして、XFSが遅延書き込みしてる感じかな?(想像) ということはbrick間やディスク間では結構な量の不一致が発生してるはずなので、運用上は留意が必要かなぁ(想像)。混ぜるな危険、みたいな。もしレプリカ修復が日常的に発生するようだと、 レプリカ3本欲しいかも。。でもコストが。。

・CPU負荷が高いす。マルチコアプロセッサは必須かなぁ。atomでは無理そうだ。具体的にはこんな感じ↓@Core 2 Quad Q6600

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 2278 root      20   0  737m  28m 2012 S 68.1  0.4  62:26.57 glusterfsd
 2282 root      20   0  737m  24m 2012 R 66.4  0.3  61:48.47 glusterfsd
 5631 root      20   0 1294m  16m  608 S 21.3  0.2  20:00.89 mhddfs
 5648 root      20   0  975m  22m  604 S 20.3  0.3  19:15.53 mhddfs

書き込みアクセス中。mhddfs領域2つをローカルでレプリケーションしてるので2つずつ上がってると思われる。
読み込みは、glusterfsdプロセスが増える場合と増えない場合がある模様。条件は不明。
メモリ消費量が小さくないようなので、小メモリ構成だと同時アクセスが増えたら危険かも知れない。この感じだと、同時100アクセスに備えるなら4GB+キャッシュ分は必要でしょうかねぇ。

もうちょっとテストしてみます。

2012年1月31日火曜日

mhddfsをCentOS6.2に導入する(完全版)


CentOS5.7ではkernelとglibcが古くて入れようが無かったmhddfsですがCentOS6.2では問題ないようです。

■必要パッケージ
yum install make gcc glibc-devel fuse fuse-libs fuse-devel

■warning対策
mkdir /usr/include/attr
ln -s /usr/include/sys/xattr.h /usr/include/attr/xattr.h

■make
wget http://mhddfs.uvw.ru/downloads/mhddfs_0.1.38.tar.gz
tar zxvf mhddfs_0.1.38.tar.gz
cd mhddfs-0.1.38
make
cp mhddfs /usr/local/bin/

■動作テスト
mkdir test
mkdir brick1
mkdir brick2
mhddfs brick1,brick2 test

■/etc/fstabに書くときの書式
mhddfs#/kfs/fuse/brick1,/kfs/fuse/brick2 /kfs/fuse/test fuse defaults,allow_other 0 0

これで一応動いているようです。。

2012年1月29日日曜日

CentOS5.7 mhddfsのmake時のwarningを解消する

気持ち悪い、というかちゃんと動いていない気がするので、warningの解消を試みました。

■結論
CentOS5.7には入れられません。後日CentOS6への移行を試みます。

■xattr問題
警告:src/main.c:37:24: 警告: attr/xattr.h: そのようなファイルやディレクトリはありません
原因:CentOS5.7では sys/xattr.h に入っている。
対策:シンボリックリンクを作ってお茶を濁す。

mkdir /usr/include/attr
ln -s /usr/include/sys/xattr.h /usr/include/attr/xattr.h

■lutimes問題
警告:main.c:(.text+0x1ca9): warning: warning: lutimes is not implemented and will always fail
原因:Linuxシステムコールlutimesはglibc2.6で追加されたもの。CentOS5.7は2.5なので、搭載されていない。
対策:utimesに変えてしまえ。
注意:正常に動作しない場合がありそうな気がする。
utimesに変えると、シンボリックリンク自体のタイムスタンプを変えられなくなる。シンボリックリンクのリンク先ファイルのタイムスタンプが書き変わってしまう。シンボリックリンクを使わなければ問題にならないのでよしとする・・・ と思ったんですが、GlusterFSでミラーするのに正しくタイムスタンプが変えられないのは深刻な問題のような気がするので、今回の用途としてはCentOS5.7では安心しては使えなさそうな気がしました。

2012/1/29追記
> futimes() is available since glibc 2.3. lutimes() is available since glibc 2.6, and is implemented using the utimensat(2) system call, which is supported since kernel 2.6.22.
CentOS5.7の最新kernelは2.6.18なので、純正環境ではどうあがいても無理ですね。はい。

2012年1月28日土曜日

mhddfsをCentOSに導入する

warningを放置すると正常に動作しません!! 次のエントリをご参照ください。

公式rpmは用意されてないのでソースから。
makeするとxattr周りでwarningが出ますが検証してませんので自己責任でどうぞ。

■make
yum install gcc glibc-devel fuse fuse-libs fuse-devel
wget http://mhddfs.uvw.ru/downloads/mhddfs_0.1.38.tar.gz
tar zxvf mhddfs_0.1.38.tar.gz
cd mhddfs_0.1.38
make
cp mhddfs /usr/local/bin/

■動作テスト
mkdir test
mkdir brick1
mkdir brick2
mhddfs brick1,brick2 test

■/etc/fstabに書くときの書式
mhddfs#/kfs/fuse/brick1,/kfs/fuse/brick2 /kfs/fuse/test fuse defaults,allow_other 0 0

GlusterFSはmhddfsと相性が良さそうだ

GlusterFSとZFSを組み合わせるのを、やめることにしました。mhddfsにします。

ZFSとGlusterFSの相性は、前回エントリの通り、最悪です。チェックサムによるデータ保護やsnapshotを諦めてしまえば、mhddfsがとても素敵に見えます。(どうしてもチェックサムやsnapshotが欲しければ、GlusterFS Geo Replicationかrsyncか何かでZFSに非同期バックアップを取っておけば、それで十分かなと思った。)

1ストレージサーバに複数ディスクを取り付けてGlusterFSで束ねるべく、1サーバに複数のbrick(1ディスク=1brick)を割り当てると、ものすごく使いにくい。
ディスクが壊れてもbrickを個別停止できません。GlusterFSのデーモンを落としてサーバを丸ごと停止する必要があります。
デーモンを落とさずbrickをマウント解除すると空ディレクトリに書き込みを始めてしまうし、ディレクトリを消すとまともに動かない。
ディスクが壊れる前に事前にデーモンを落とせれば良いが、そうでない場合、致命傷を受ける可能性があります。
束ねる際に対になるディスクは容量が揃ってないと予期せぬ動作を催します。空き容量に関係なくファイル名ハッシュで満遍なく分散保存されてしまうので、対になってないディスクでも容量が大きい分が丸ごと無駄です。
brick内のファイルを直接触るのは危険です。容量が増えれば増えるほど再構成の負担が増大します。

そこで、mhddfsでディスクをコンカチして、そこにディレクトリを掘って、GlusterFSでサーバー間でミラーリングすると、全て解決します。
ディスクが壊れたら、そのディスクのマウントポイントを削除すれば、mhddfsはそのディスクが無かったものとして動作続行し、GlusterFSがミラー復旧に努めてくれます。(マウント解除されると空ディレクトリに書き込まれちゃうのは同じなんですが、マウントポイントが消失しても問題ないのが良い点)
ディスクとbrickが結びついていないので、brickをマウント解除したりディレクトリを消去することはありません。(外したディスク以外にディレクトリエントリが記録されていなかった場合を除くものの)
よって事前にデーモンを落とせなくても、GlusterFSの困った動作の影響は受けません。(大体は。まぁメリットはエラー対処よりディスク容量問題の方が大きいんで堪忍してください)
個々のディスクの容量を揃える必要はありません。サーバ間で揃っていれば良いし、あるいはまったく揃えずとも満杯になりそうになったらディスクを手軽に追加投入して解消できます。手持ちのディスクを空きポートの数だけ全部突っ込めます。
ディスクは前方から順番に使用されていきます。負荷分散はできませんが、各ディスクのファイルは直接触っても問題ないので、ファイルを手動でコピーすればいかようにも再構成できます。

まぁパフォーマンスは測定しないといけませんけど、いいことづくめではないでしょうか。ストレージプールに追加したディスクは絶対に取り外せないZFSよりもHA運用に向いていると言えなくもないくらいじゃないですか・・・?

この路線で考えてみます。

2012年1月27日金曜日

GlusterFSとZFSを組み合わせるには

GlusterFSとZFSを組み合わせて使うのに、一悶着あったので、書き残しておきます。
何かを見落としていなければ、かなりの冒険が必要のようです。

■結論(持ち越し)
・ZFSとGlusterFSは、そのままでは組み合わせ不可能(ZFSがxattrに対応してないから)
・ZVOLを作ってUFSフォーマットしてマウントすれば使えるが… えー、それマジっすか?

・ソリューション選択で何とかならないかなぁ。
FreeBSD+ZFS(ZVOL)+UFS+GlusterFS
CentOS+ZFS-FUSE(ZVOL)+XFS+GlusterFS
CentOS+mhddfs+XFS+GlusterFS(そもそもZFS無くても良くね? と思ってきた)

■GlusterFSとZFSの併用について
GlusterFSはディレクトリを束ねるソリューションであって、ストレージの挙動には関与しません。データの中身の整合性であるとか、ディスクのリプレースとか容量拡張とか、考慮されていません。それはそれで正しいんでしょうけど、これで複数のディスクを束ねて順次拡張しながら長期運用しようとすると困難に直面することがあるようです。(ディスクを止められないとか、最小容量のディスクに引っ張られるとか、挙動が怪しくなるとか)

その点、ZFSが併用できれば便利そうです。データをチェックサムで点検したり、書き込みホール無しのダブルパリティで物理障害に備えたり、ホットスペアを用意したり、容量の異なるディスクを継ぎ接ぎしたり、スナップショットとれたり、持続的な発展的運用にはもってこいじゃないですか。(メモリ食うし安定させるの大変だけど)

■プラットフォームの問題
GlusterFSは一応RedHat系Linuxが推奨環境になります。ZFSはFreeBSDなら安心ですが、Linuxですと今のところZFS-FUSEになるかと思います。あんまり安心して使える感じじゃないんですよね。

ここはソリューション選択で解決できそうな気がします。
・GlusterFSでミラーされてるしバックアップもあるし、データ保護は半ばどうでもいいのでZFS-FUSEを使う。
・ZFSの安定性を重視するなら(いろいろ間違ってる気がするが)Debian GNU/kFreeBSDにGlusterFSを入れる。

うーん、一応両方評価してみようかなと思います。。

■ZFSの仕様の問題
しかし、しかしです。ZFSには重大な欠点があります。GlusterFSの必須用件であるattrがサポートされていません; GlusterFSとZFSを組み合わせることは、そもそも不可能なんです;

ZFS上でattrコマンドを実行するとエラーです。
zfs set xattr=onも通りません。

これはSolarisと他OSにおける「attr」の仕組みの違いによるものです。Sorarisにはext2/3やXFS、UFSでいうところの「attr」と一致するものが存在しません(しないようです)。なのでZFSではそんなものは仕様上考慮されておらず、搭載されていないと。こりゃ時間が解決してくれる手の問題ではなさそうで、どうにもなりません。

このattr問題に関し、FreeBSD.orgのドキュメントを参照しますと驚愕の対処法が書かれています。

# zfs create -V 10g tank/ufs
# newfs /dev/zvol/tank/ufs
# mount /dev/zvol/tank/ufs /ufs

引用元:http://wiki.freebsd.org/ZFSQuickStartGuide

なんと斬新な・・・ 驚愕を通り越して感動すら憶えます。しかし、最近のFreeBSDにはSoftUpdateが付いてるとはいえ、これでsnapshotとか取って大丈夫なんだろうか。。疑問疑問。。スマートとも言えない。。ですよね。。容量拡張はZFSでサイズ変更してからgrowfsか?

しかしZFSを使う限り宿命なので、これで検証することにします。フォーマットは、FreeBSDならUFS、LinuxならXFSでしょうか。

■ZFSやめようかな
単にHDDを束ねるだけならmhddfs(FUSE)という手がある。ディレクトリをコンカチしてくれる素敵ソリューション。

・ファイルシステムの上のレイヤーで動くJBODのようなもの。複数のディレクトリを束ね、1つのものとして見せてくれる。mhddfs自体は中継レイヤーであり、普通のファイルシステムではない。

・mhddfsで束ねたディレクトリに書き込むと、束ねる際に指定した順番で前方のディレクトリから順次、容量フルになるまで書き込まれていく(デフォルト設定ではフルになる前に次のディレクトリに移行するけど)。

・書き込みはブロック単位ではなくファイル単位で行われる。ファイルがディレクトリをまたがって書き込まれることは無い。追記途中でディレクトリが一杯になったら次のディレクトリに自動的にマイグレーションされる(けどサイズが大きいと時間かかりまくるんじゃないかなと想像。。これは善し悪しかも知れない。)

・束ねたディレクトリは1つづつ独立した普通のディレクトリなので単独でマウントして中身を拾えるし、マウントパラメータ以外に管理情報も持っていないので運用中に適当に抜いたり追加したりしても大丈夫。

・運用中に構成ディレクトリを外すとそこにあったファイルは見えなくなるが、元通りマウントすれば復活する。冗長性は無いが、ディスクが故障した場合、そこに記録されているファイルは失われるが他のファイルは無事なので全損にはならない。

・束ねるディレクトリ間でファイル名やディレクトリ名が衝突した場合、一番前方のディレクトリにあるもののみが読み書きの対象になる。ということは、ファイルを更新してもディレクトリのタイムスタンプが更新されないケースが生じうる。プログラム的にはここ要注意かも知れない。

冗長性はGlusterFSによるreplicaでカバーできるものとすれば、これこそGlusterFSと相性がいいと言えるかも知れない。

○ディスク数を減らしたい場合
・ディスクを外したいサーバのGlusterFSプロセスを落とす(自動フェイルオーバーで稼働継続)
・mhddfsをumountして交換したいディスクのマウントポイントを外してmountし直す(欠損が発生)
・GlusterFSプロセスを上げる
・欠損部分がミラーで自動修復される(笑

○ディスク数を増やしたい場合
・ディスクを追加したいサーバのGlusterFSプロセスを落とす(自動フェイルオーバーで稼働継続)
・mhddfsをumountして取り付けたディスクのマウントポイントを最後に追加してmountし直す
・GlusterFSプロセスを上げる
・既存ディスクが埋まり次第、新しいディスクが使われていく

というわけで、チェックサムによるデータ保護はないものの、brickの構成を変更せずに素早くディスクを切り替えられてhappyになれる。

しかし。

・mhddfsはFUSEを使う。FUSEが2重になるとパフォーマンスや安定性が微妙そうな気が何となくする。
・mhddfsをCentOSに導入するのは大変そうだ。公式パッケージは無い。

うーん、決定打がない。

いっそmhddfsを改造するとかして、同期レプリケーションに特化した新しいファイルシステムを作っちゃうか?

・write系は、両方に同期ミラーで書く。
・read系は、両方から読む。データは比較してもしなくてもいいや。
・read系で、片方にファイルが無かった場合は、もう片方からコピってくる。
・タイムアウトなりエラー検知なりした場合、そのディレクトリの使用を中止する。

これでNFSを束ねれば十分じゃないか? ていうか、もしかして現存するんじゃないか?

なんか徒然と書いてしまいましたが、今日はこの辺で。

※2012/2/1修正
徒然し過ぎていたのでちょっと整理整頓しました。

2012年1月25日水曜日

GlusterFS 容量フル時の挙動を確かめてみた

容量フルにならない運用を心がけるのは当然なんでしょうが、一応、そうなっちゃった時の挙動を確かめておきました。

■使用環境
CentOS5.7
GlusterFS3.2.5

■テスト方法
ダミーファイルをxfsでフォーマットし、適当にマウントし、GlusterFSで束ねます。
ダミーファイルの大きさを不均等にしておいて挙動を見ます。
今回はローカルでのテストなので、ネットワーク越しだと違うかも知れません。

■用意(zero1だけ200MB、他は1GB)
dd if=/dev/zero of=/glvols01/disk01/zero1 seek=200 bs=1M count=1
dd if=/dev/zero of=/glvols01/disk02/zero2 seek=1000 bs=1M count=1
dd if=/dev/zero of=/glvols01/disk03/zero3 seek=1000 bs=1M count=1
dd if=/dev/zero of=/glvols01/disk04/zero4 seek=1000 bs=1M count=1
mkfs.xfs /glvols01/disk01/zero1
mkfs.xfs /glvols01/disk01/zero2
mkfs.xfs /glvols01/disk01/zero3
mkfs.xfs /glvols01/disk01/zero4
mkdir /glvols01/zero1
mkdir /glvols01/zero2
mkdir /glvols01/zero3
mkdir /glvols01/zero4
mount -t xfs -o loop /glvols01/disk01/zero1 /glvols/zero1
mount -t xfs -o loop /glvols01/disk01/zero2 /glvols/zero2
mount -t xfs -o loop /glvols01/disk01/zero3 /glvols/zero3
mount -t xfs -o loop /glvols01/disk01/zero4 /glvols/zero4
gluster volume create zero replica 2 192.168.0.252:/glvols/zero1 192.168.0.252:/glvols/zero2 192.168.0.252:/glvols/zero3 192.168.0.252:/glvols/zero4

■テスト結果:レプリカディレクトリの空き容量が均等な場合
空き容量不足で正常に終了するようです。

[root@kfs02 glvols01]# dd if=/dev/zero of=/zero/zero bs=1M
dd: writing `/zero/zero': デバイスに空き領域がありません
dd: 出力ファイル `/zero/zero' をクローズ: デバイスに空き領域がありません

[root@kfs02 glvols01]# df -kh
Filesystem サイズ 使用 残り 使用% マウント位置
/glvols01/disk01/zero1
197M 4.3M 193M 3% /glvols01/zero1
/glvols01/disk02/zero2
997M 4.3M 993M 1% /glvols01/zero2
/glvols01/disk03/zero3
997M 997M 20K 100% /glvols01/zero3
/glvols01/disk04/zero4
997M 997M 20K 100% /glvols01/zero4
glusterfs#192.168.0.252:zero
1.2G 1001M 192M 84% /zero

■テスト結果:レプリカディレクトリの空き容量が不均等の場合
片方が埋まっても、両方が埋まるまで超低速で書き込みが続いてしまうようです。
正確な速度は調べてませんが、0.5MB/sも出てない感じ。
未確認ですが、この状態で書き込みが集中すると鯖落ちということになるんでしょうか。

[root@kfs02 glvols01]# dd if=/dev/zero of=/zero/azero bs=1M

[root@kfs02 glvols01]# df -kh
Filesystem サイズ 使用 残り 使用% マウント位置
/glvols01/disk01/zero1
197M 197M 20K 100% /glvols01/zero1 ←注目
/glvols01/disk02/zero2
997M 237M 761M 24% /glvols01/zero2 ←注目(zero1を超えてる)
/glvols01/disk03/zero3
997M 997M 20K 100% /glvols01/zero3
/glvols01/disk04/zero4
997M 997M 20K 100% /glvols01/zero4
glusterfs#192.168.0.252:zero
1.2G 1.2G 0 100% /zero

■考察
ファイル名でハッシュ値をとって分散しているので、brick間での空き容量に関係なく書き込みが試行されます。
書き込み先のbrickが一杯になった時点で容量フルのエラー応答。
書き込み先のbrickのうちミラーの片割れだけが容量フルになっても、エラーを返さず超低速で動き続けます。容量フルのbrickのファイルのタイムスタンプも更新され続けているので、書き込みを試行し続けているのかな。動作が遅くなるのはxfsのせいだろうか? CPUはほとんどidolで、何をやってるのかよくわかりません。
レプリカの正誤判定は、タイムスタンプの新しいほうを正とみなす、なんてロジックでしたっけ? だとすると破滅的な挙動に繋がるかも知れませんが確かめておらず。

■まとめ
brickごとに容量監視が必要です。
replicaで対になるbrickの容量は揃えておいたほうが良さそうです。
対にならないbrickに関しては容量が揃っていなくても深刻な問題は無さそうですが、分散アルゴリズム上、容量差は考慮されないので、容量が大きい方が無駄になる可能性が高いようです。
適当にディレクトリを切ってbrickごとの容量差を近づければ無駄にはなりませんが、パフォーマンスが落ちるであろう点と、後でbrickを1つに合併させるのは困難であろう点が気になります。
長期運用中にディスクを追加したくなった場合に、その時点でバイト単価の最も安いディスクをチョイスしても無駄になっちゃいますね。
しかし全リプレースするにしてもreplace-brickにかかる時間が馬鹿にならないだろうし、ディスク追加のパフォーマンスは良くないように思います。

このへんはZFSを組み合わせてローカルディスクを単一ディレクトリにまとめてしまえば回避できますが、メモリ&CPUリソースが食われるんでGlusterFSの長所が一つ潰れてしまいます。
しかもZFS@FreeBSDではattrが使えないんで、そもそもだめですね。
ついでにGlusterFS公式ではFreeBSDやZFSでの動作は検証の対象外のようですね。そりゃGlusterFS自体がRedHat傘下だしなぁ。大量データを任せるのはハイリスクなんじゃないでしょうか。

なんだか、スモールスタートでの長期運用には向いていないんじゃないか、って感じがします。
最初から構成を固定するとか、一時的かつ再現可能なデータに限って使用するとか、将来的に代替ハードを用意&大容量データを全コピー(低速)する羽目に陥るリスクを受容するとか、何らかの妥協がいりそうです。。

2012年1月21日土曜日

ZFSとGlusterFSの操作の対比

最近GlusterFSをいじっています。
ZFSが長年染み付いているので、対比表を作ってみました。

1年以上前にも導入を検討しましたが、いろいろあって見送りました。
最近システム構成を考える中で意外と行けるかもと思い直すようになりました。
ZFSよりもメモリへの要求が少ないのが、特にいいですね。

■確認したバージョン
GlusterFS 3.2.5(CentOS5.7)
ZFS v28(FreeBSD9.0)

まずは概念図から。
GlusterFSのマニュアルはZFSと同じだけど意味の違う用語が入り乱れているので、読んでて混乱します。
頭に叩き込んでおきましょう。



次にファイルシステムを作成する段取りについて。

ZFSでの操作GlusterFSでの操作

サーバにデバイス(ディスク)を設置する
/dev/ada0
/dev/ada1
/dev/ada2
/dev/ada3
/dev/ada4
/dev/ada5
/dev/ada6
/dev/ada7

サーバを信任する(例:2台)
gluster peer probe 192.168.0.131
gluster peer probe 192.168.0.132

ブリック(ディレクトリ)を作成する
mkdir /gluster-bricks/brick01
mkdir /gluster-bricks/brick02
mkdir /gluster-bricks/brick03
mkdir /gluster-bricks/brick04

デバイスからストレージプールを作成する
zpool create tank0 mirror ada0 ada1 mirror ada2 ada3 mirror ada4 ada5 mirror ada6 ada7

ストレージプールからファイルシステムを作成する
zfs create tank0/hogemoge

ブリックからボリュームを作成する
gluster volume create hogemoge replica 2 transport tcp 192.168.0.131:/gluster-bricks/brick01 192.168.0.132:/gluster-bricks/brick01 192.168.0.131:/gluster-bricks/brick02 192.168.0.132:/gluster-bricks/brick02 192.168.0.131:/gluster-bricks/brick03 192.168.0.132:/gluster-bricks/brick03 192.168.0.131:/gluster-bricks/brick04 192.168.0.132:/gluster-bricks/brick04

ボリュームを利用開始する
gluster volume start hogemoge

マウントポイントを設定する(マウント自体は全自動)
zfs set mountpoint="/hogemoge" tank0/hogemoge

マウントする
echo "192.168.0.131:hogemoge /hogemoge glusterfs default,user_xattr,_netdev 0 0" >> /etc/fstab
mount -a







最後に、もうちょっと細かい操作コマンドの違いについて。
オプションは一切省いているので、説明書を必ず熟読してください。
GlusterFSは設定ファイルを直接いじれば、リネームとかも可能なんだと思いますけれども、覚えるのが面倒なのでコマンドラインツールで操作できる内容に絞りました。

ZFSの操作ZFSでのコマンドGlusterFSでのコマンドGlusterFSの操作
ZFSにはGlusterFSの"信頼されたストレージプール"に相当する概念はない。
サーバ構成は自分自身の1台のみで完結なので関係ない。
gluster peer probeサーバを信任する("信頼されたストレージプール"に追加する)
gluster peer detachサーバを信任解除する("信頼されたストレージプール"から取り除く)
ファイルシステムのマウント許可(デフォルト)zfs set canmount=ongluster volume startボリューム利用開始
ファイルシステムのマウント禁止zfs set canmount=offgluster volume stopボリューム利用停止(デフォルト)
デバイスからストレージプールを作成するzpool creategluster volume createディレクトリからボリュームを作成する
ストレージプールからファイルシステムを作成するzfs create
ストレージプールを破棄するzpool destroygluster volume deleteボリュームを破棄する
ファイルシステムを破棄するzfs destroy
ストレージプールにデバイスを追加する(容量拡大、ホットスペア、ZIL、L2ARC)zpool addgluster volume add-brickボリュームにブリックを追加する(容量拡大のみ)
ZFSでは容量は縮小できない(通常デバイスは取り外せない)gluster volume remove-brickボリュームからブリックを取り外す(そのブリックに記録されているデータはボリュームから消失する)(*1)
ストレージプールからデバイスを取り外す(ホットスペア、ZIL、L2ARC)zpool removeGlusterFSにはそうした特殊デバイスは存在しない。
デバイスを入れ替えるzpool replacegluster volume replace-brickブリックを入れ替える
ZFSでは記録済みデータはリバランスできないgluster volume rebalanceブリック間で記録済みデータをリバランスする
ストレージプールにミラーデバイスを追加するzpool attachGlusterFSではミラー数は途中変更できない。
ストレージプールのミラーデバイスを削除するzpool detach
ストレージプールの一覧を表示するzpool listgluster volume info allボリュームの構成情報を表示する。ただし容量は表示されない。(*2)
ストレージプールの状態を表示するzpool status
ファイルシステムの一覧を表示するzfs list
デバイスの使用を停止するzpool offlineGlusterFSではブリックは個別停止できない。(*3)(*5)
デバイスの使用を再開するzpool online
エラーチェック&修復zpool scrubレプリケーションはファイルにアクセスする度に自動修復される。(*4)
ファイルシステムをリネームするzfs renameGlusterFSではボリューム名は途中変更できない。


(*1)ファイル消失について
ボリュームの構成情報のみが削除され、データは残る。
各ブリックはただのディレクトリなので、ストライピングしていなければ直接救出可能。
ストライピングしている場合はファイルの一部分がsparseで欠損しているので非常に大変だと思うが、不可能ではないだろうとは思う。
まぁディスクなりブリックなりを一度追加したら簡単には外せないというのはZFSもGlusterFSも似たような状況ということで。

(*2)容量の確認方法
容量はマウント先でdf -kコマンド等で確認すればよい。
ただしGlusterFSのボリュームは普通のディレクトリの寄せ集めのため、ディレクトリ毎に空き容量がバラバラなので、df的には空いててもバランシングの状況次第では容量フルでエラっちゃう可能性がある気がする。
容量オーバーを防止するなら構成ディレクトリをそれぞれ個別に監視しないといけませんね。

(*3)ブリックは個別停止できない件について
ミラーされていて、かつNative Clientでマウントしていれば自動でフェイルオーバーされるので、停止させずに抜いちゃっても問題ないはず・・・(と思うけど確かめたわけではない)(*5)

(*4)レプリケーションの修復について
インデックスのみで良ければ find <gluster-mount> -print0 | xargs --null stat >/dev/null
ファイル内容まで完全に find <gluster-mount> -type f -exec dd if='{}' of=/dev/null bs=1M; > /dev/null 2>&1
チェックサム情報は(多分)持っていないので静的なデータ破壊までは点検できない(と思うけど確かめたわけではない)


以下20120124追記

(*5)試してみた
稼働中に、brickに使ってるディスクをマウントしてあるディレクトリをumountしてみました。
umountされてもGlusterFSは何事も無かったかのように稼働し続けました。素晴らしい。ではなくて、大変な事態に陥りました。

マウントポイントはマウント解除されることによって単なる空ディレクトリに変わりますが、GlusterFSはその空ディレクトリを使って勝手にレプリカの復元を始めてしまいます。おそらくファイルシステムの異変は感知せずレプリカの片割れが欠落したとだけ認識してしまうんでしょう。USB起動だったので起動ディスクが一瞬で埋まってしまいました・・・orz

では単にumountするだけではなくマウントポイントのディレクトリを削除するとどうなるかというと、復元動作は一応停止しますが、レプリケーションの片割れが読み書きできないことでクライアントにinput/output errorが返ってしまい、稼働継続できませんでした。レプリケーションの片割れは正常であるにも関わらずです。

シンプル設計との観点でいえば妥当な動作ではあろうと思いますが、運用中にマウントが外れることは、異常/正常を問わず有り得ると思うんですよね。これじゃ単発ディスクがSPOFになっちゃう。その対策としてディスクとファイルシステムで2重に冗長化するのはコスト高でしょう。やっぱりbrickは明示的に個別に一時停止できたほうが、いいんじゃないかなぁ。

これがネットワーク切断やサーバダウンによる片割れ停止だったら異常検知されて稼働し続けられるのかなぁと想像しますが、どうなんでしょう。後日、試してみたいと思います。