2012年2月22日水曜日
PHP FUSEのセグメンテーション違反とバスエラーについて
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を付与したい
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);
■追記
読み出し制御したい場合、全ての関数に実装が必要ですよねぇ。
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超のファイル容量を正しく報告できない件について
激しく環境依存ぽいんで、アレですけれども。。
(修正前)int value = Z_LVAL_PP(entry);
(修正後)long value = Z_LVAL_PP(entry);
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の容量フル時の挙動について(不具合報告)
けどロシア語よくわかんないし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を解消する
■結論
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に導入する
公式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と相性が良さそうだ
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を組み合わせるには
何かを見落としていなければ、かなりの冒険が必要のようです。
■結論(持ち越し)
・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プロセスを落とす(自動フェイルオーバーで稼働継続)
・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の操作の対比
ZFSが長年染み付いているので、対比表を作ってみました。
1年以上前にも導入を検討しましたが、いろいろあって見送りました。
最近システム構成を考える中で意外と行けるかもと思い直すようになりました。
ZFSよりもメモリへの要求が少ないのが、特にいいですね。
■確認したバージョン
GlusterFS 3.2.5(CentOS5.7)
ZFS v28(FreeBSD9.0)
まずは概念図から。
GlusterFSのマニュアルはZFSと同じだけど意味の違う用語が入り乱れているので、読んでて混乱します。
頭に叩き込んでおきましょう。
次にファイルシステムを作成する段取りについて。
ZFSでの操作 | GlusterFSでの操作 |
サーバにデバイス(ディスク)を設置する | サーバを信任する(例:2台) ブリック(ディレクトリ)を作成する |
デバイスからストレージプールを作成する ストレージプールからファイルシステムを作成する | ブリックからボリュームを作成する ボリュームを利用開始する |
マウントポイントを設定する(マウント自体は全自動) | マウントする |
最後に、もうちょっと細かい操作コマンドの違いについて。
オプションは一切省いているので、説明書を必ず熟読してください。
GlusterFSは設定ファイルを直接いじれば、リネームとかも可能なんだと思いますけれども、覚えるのが面倒なのでコマンドラインツールで操作できる内容に絞りました。
ZFSの操作 | ZFSでのコマンド | GlusterFSでのコマンド | GlusterFSの操作 |
ZFSにはGlusterFSの"信頼されたストレージプール"に相当する概念はない。 サーバ構成は自分自身の1台のみで完結なので関係ない。 | gluster peer probe | サーバを信任する("信頼されたストレージプール"に追加する) | |
gluster peer detach | サーバを信任解除する("信頼されたストレージプール"から取り除く) | ||
ファイルシステムのマウント許可(デフォルト) | zfs set canmount=on | gluster volume start | ボリューム利用開始 |
ファイルシステムのマウント禁止 | zfs set canmount=off | gluster volume stop | ボリューム利用停止(デフォルト) |
デバイスからストレージプールを作成する | zpool create | gluster volume create | ディレクトリからボリュームを作成する |
ストレージプールからファイルシステムを作成する | zfs create | ||
ストレージプールを破棄する | zpool destroy | gluster volume delete | ボリュームを破棄する |
ファイルシステムを破棄する | zfs destroy | ||
ストレージプールにデバイスを追加する(容量拡大、ホットスペア、ZIL、L2ARC) | zpool add | gluster volume add-brick | ボリュームにブリックを追加する(容量拡大のみ) |
ZFSでは容量は縮小できない(通常デバイスは取り外せない) | gluster volume remove-brick | ボリュームからブリックを取り外す(そのブリックに記録されているデータはボリュームから消失する)(*1) | |
ストレージプールからデバイスを取り外す(ホットスペア、ZIL、L2ARC) | zpool remove | GlusterFSにはそうした特殊デバイスは存在しない。 | |
デバイスを入れ替える | zpool replace | gluster volume replace-brick | ブリックを入れ替える |
ZFSでは記録済みデータはリバランスできない | gluster volume rebalance | ブリック間で記録済みデータをリバランスする | |
ストレージプールにミラーデバイスを追加する | zpool attach | GlusterFSではミラー数は途中変更できない。 | |
ストレージプールのミラーデバイスを削除する | zpool detach | ||
ストレージプールの一覧を表示する | zpool list | gluster volume info all | ボリュームの構成情報を表示する。ただし容量は表示されない。(*2) |
ストレージプールの状態を表示する | zpool status | ||
ファイルシステムの一覧を表示する | zfs list | ||
デバイスの使用を停止する | zpool offline | GlusterFSではブリックは個別停止できない。(*3)(*5) | |
デバイスの使用を再開する | zpool online | ||
エラーチェック&修復 | zpool scrub | レプリケーションはファイルにアクセスする度に自動修復される。(*4) | |
ファイルシステムをリネームする | zfs rename | GlusterFSではボリューム名は途中変更できない。 |
(*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は明示的に個別に一時停止できたほうが、いいんじゃないかなぁ。
これがネットワーク切断やサーバダウンによる片割れ停止だったら異常検知されて稼働し続けられるのかなぁと想像しますが、どうなんでしょう。後日、試してみたいと思います。