ffsysとは
ffsysは、ffsrvmodを使ったシステム全体の総称です。
ffsysの中心になるffsrvmodは、Linuxシステムコールのファイル操作に関するものだけをフックし、外部にメッセージを送信する カーネルモジュール(LKM) です。
カーネルモジュールとして動く ffsrvmod はシンプルであり、sys_open,sys_close,をはじめ,utime,rename…など、ファイル操作をメッセージ順にSocketへ流し込みます。ただそれだけです。
(全てではありません。最終的にファイルが完成?ファイル操作が終了?した時点でメッセージが流れるようにしています。)
ffsrvmod は、コマンド、ファイルのフルパス、その他必要なオプション(アクセス権など)を流すだけで、ファイルのデータそのものは扱いません。(もしかしたらデータも扱うかもしれませんが、今のところ予定はありません。)
現在はデータを冗長させるサンプルプログラムしか付属していませんが、今後ffsrvmodを使った大容量ストレージ・負荷分散・データベースの高速化を紹介して行く予定です。

特徴
システムコールをフックしているため、環境を選ばずにデータの冗長が可能になります。あらゆるWEBサービス、プログラムに変更を加えずに使用できます。
分散ストレージとして、広域なサーバー郡での負荷分散で、開発環境でのデプロイツールとして、様々な利用方法が考えられます。
専用のAPIや関数などは必要ありません。既存のソースに変更を加えることなく分散が可能になります。
なぜ
ハードディスクへの変更を複製しようとする場合は、ブロックデバイスへのI/Oをフック・完全に横取り(仮装ブロックデバイスを作成)するのが確実ですが、それらは既に長い歴史のあるSoftwareRAIDがあり、最近ではDRBDなどの素晴らしい仕組みが既にあります。私はそれらをとても便利に使っています。
ネットワーク越しにデバイスを使うには、NBD(NetworkBlockDevice)や iscsi 等の仕組みもあり、それらをまとめて一つにするLVM、複数台で扱えるCLVM(クラスタLVM)等も有名です。
(誤解・誤認があるといけないので、これらの仕組みについての詳細はそれぞれ調べて下さい。)
上記のようなシステムは、(ブロック単位?)ファイル名などを一切意識せずにやり取りを行うため、非常に高速でほぼ全てのデータを取り扱うことが出来ます。私も多用しています。
ほとんどの仕組みがブロックデバイスとして扱えるように設計されているため、その上に乗っかるファイルシステムは何でも良く、意識することなく1台のHDとして使う事が出来ます。とても便利です。
しかし、その領域はほぼ専用な領域になってしまいます。
増やすことは容易に出来ても、はずす事はとても難しいです。
(ここら辺も誤解・誤認があるといけないので、これらの仕組みについての詳細はそれぞれ調べて下さい。)
役割分担がはっきりしているシステム全体であればとても有効ですが、「あのWEBサーバーがあまったよ。そっちってDISK大変だよね。もってっていいよ。・・・・あっ、こっちで足りなくなった。・・」とかには対応できそうにありません。
もちろん、あっち・こっちも含めた全体構成を作り上げておけばいいのですが(それらを解決するべくクラウドと言った言葉もあり、アマゾンS3やEC2もスタートしてます。)自社内でやろうとした場合は、無駄が出てしまいそうです。
私はブロックデバイスドライバを新たに作らず、既に Linux に組み込まれているファイルシステム(ext2やext3)を使い冗長化や大容量ストレージを作ろうと思い立ちました。
ファイル(フォルダ)名をその都度解釈してるため、単体でのスピードに関しては上記システムより絶対に、間違っても早くなることはありませんが、システム全体の最適化を考えた場合、有効に働く場所があると考えています。
さらに既存のファイルシステムをそのまま使うため、再構成する必要が無く稼動中の構成にも多少の手間で導入することが出来ますし、障害が発生してもそのまま動きつづけます。またOSを選ぶ必要も無くなります。(現在はCentOSしか動きません。)
Diskスペースの空いているマシンがあれば投入することが可能になります。
Diskの値段、製能は時間と共に激しく変化します。2年前に購入した2Tのストレージが今はもう使えません。いえ、使う事は出来ますが、Disk1つ300Gの構成で増やすしか手が無いため、新しいストレージを買った方が安く済んでしまいます。
私は結構高めのストレージを使っています。
私はISCSI(ソフトウェア)+LVMも気に入っています。アクセスが激しくなければISCSI+CLVM+GFSで構成を組みます。
ほとんどのサーバーでNFSを使いマウントしてます。
私はRAIDコントローラがのってるサーバーをよく選びます。
私はffsysを使います。
最終目的
速度は非常に重要な要素ですが使いづらかったり、汎用性がなかったりすることを出来るだけ避けた負荷分散機能(データベースの負荷分散については、ファイルシステムを上手に活用したものを考えています。)や、いくつのもサーバーにまたがった分散ストレージの構築を目指しています。
ダウンロード
http://lab.deepvalley.jp/source/ffsys/ffsys-0.2.1.tar.gz
(日本語がガッツリ書き込まれてます。コメントなんかで・・。UTF8)
インストール
モジュールを組み込むサーバーでは、カーネルの再コンパイルが必要になります。
現バージョン(2008年11月現在)のCentOS5.2カーネルでは、標準でシステムコールをフックできないように変更されています。
十分注意して構築してください。
カーネルの再構築が終われば、以下のようにコンパイルするだけです。
cd /usr/src;
gtar -xvzf ./ffsys-0.2.1.tar.gz;
–モジュールのコンパイル–
cd /usr/src/ffsys-0.2.1/mod;
make;
モジュールの組み込み
insmod /usr/src/ffsys-0.2.1/mod/ffsrvmod.ko;
設定方法は下の方に書いてあります。(配布READMEにも書いてあります。)
–サンプルクライアントのコンパイル–
cd /usr/src/ffsys-0.2.1;
./configure;
make;
make install;
(フォルダ /usr/local/ffsrv を作っておいてください。
ここでは説明しませんが、ファイルロックモードで使用します。)
起動
/usr/local/bin/ffsrv 3103 300;
/usr/local/bin/ffsrv ポート 通信タイムアウト
(サンプルクライアントは、データの取得にRCPを使ってます。rsh-serverやその他設定は適切に
行っておいてください。)
簡単な設定は
yum install rsh*
chkconfig rsh on
/etc/init.d/xinetd restart
echo rsh >> /etc/securetty
echo 192.168.10.10 root >> /root/.rhosts
↑接続元IP↑
こんな感じでしょう。
セキュリティは各々で設定してください。
カーネルコンパイル
CentOS5.2 X86_64及びi686
CentOS5.2Xen(DomU) X86_64及びi686
Intel(R) Xeon(R) 5130 2.00GHz デュアルコア
Intel(R) Celeron(R) CPU 2.00GHz
での確認をしています。(Linuxであればほぼ動くと思います。)
一応カーネルのバージョンも記載しておきます。(今お使いのカーネルのバージョンは「uname_-r」や「arch」で確認できます。)
2.6.18-92.1.13.el5
2.6.18-92.1.13.el5xen
2.6.18-92.1.17.el5
2.6.18-92.1.17.el5xen
2.6.18-92.1.18.el5
2.6.18-92.1.18.el5xen
CentOS5.2を普通にインストールした場合のカーネルコンパイルの仕方をかいておきますが、ご自分でいろんな変更を加えている方、もっと良い方法を知っている方はどうぞご自分のやり方で変更して下さい。
重要なことはシステムコールをフック出来るようにする事です。
「Write Protect kernel read-only date structures」のチェックをはずす事に注意してください。
デフォルトではチェックがついている意味を理解した上で作業をお願いします。
(http://www.ubuntulinux.jp/products/JA-Localized/vmware)ここで配布しているUbuntuのVMwareイメージは、Write Protectはされていませんでした。)
作業ディレクトリへ移動
cd /usr/src/
この中に「redhat」ディレクトリがない場合は作成しておく(mkdir redhat)
カーネルソースの取得
wget http://ftp.riken.jp/Linux/centos/5.2/updates/SRPMS/
\kernel-2.6.18-92.1.18.el5.src.rpm
バージョンはお使いのものに合わせて下さい。
展開
rpm -ivh ./kernel-2.6.18-92.1.18.el5.src.rpm
コンパイルの準備
cd /usr/src/redhat/SPECS
rpmbuild -bp –target x86_64 kernel-2.6.spec
cd /usr/src/redhat/BUILD/kernel-2.6.18/linux-2.6.18.x86_64
ターゲットはお使いのものに合わせて下さい。
インストールされている.configをコピー
cp /boot/config-2.6.18-92.1.18.el5 ./.config
/bootの中に、現在動いているカーネルのコンパイルオプションが入っています。
コンパイルオプションをそのまま引継ぎ、再コンパイルします。
xenで動かしている場合は
cp /boot/config-2.6.18-92.1.18.el5xen ./.config
の様になります。
システムコールをフックする準備
vi /usr/src/redhat/BUILD/kernel-2.6.18/linux-2.6.18.x86_64/kernel/kallsyms.c
の一番下に以下の2行を追加。
extern void* sys_call_table[];
EXPORT_SYMBOL(sys_call_table);
※このまま進めていくと、出来上がるカーネルの名前が「2.6.18-prep」になります。
それがいやな場合は「Makefile」以下の部分を変更して下さい。
EXTRAVERSION = -prep
例えば EXTRAVERSION =-92.1.18.el5-ffsrv の様に。
コンパイルオプションの引継ぎ
make oldconfig
コンパイルオプションの変更
make menuconfig
ツールが足りずにエラーが出る場合がありますが、適時yum等でインストールしてください。
メニューの中の「Kernel Hacking」を選択。
下のほうに「Write Protect kernel read-only date structures」のチェックをはずす。
コンパイル
make
モジュールインストール
make modules_install
カーネルインストール
installkernel 2.6.18-prep arch/x86_64/boot/bzImage System.map
(installkernel 2.6.18-prep vmlinuz System.map)
モジュールの設定
配布READMEにも書いてあります。
現在の設定確認。
cat /proc/ffsrvmod
モジュールを組み込む際に「base_path」を与えることで、同期対象の場所を変更できます。(デフォルトは/usr/local/apache/htdocs)
insmod ffsrvmod.ko base_path=/var/www/html
サーバーの追加
echo aadr 接続先IP ポート 自分のIP です。
echo aadr 192.168.10.11 3103 192.168.10.10 > /proc/ffsrvmod
台数が多いときは、接続用のスクリプトを書いたほうが楽でしょう。
PHPならば support/phptest.php のようになります。
1台ずつ接続
echo conn 0 > /proc/ffsrvmod
echo conn 1 > /proc/ffsrvmod
・
・
一斉に接続
echo conn 99 > /proc/ffsrvmod
切断(addで追加した情報もすべて消されます。)
echo close > /proc/ffsrvmod
サンプルプログラム
注意!守られたネットワーク内で使用してください。
ffsrvmod だけでは何にもならないので、配布ファイルの中にユーザー空間で動かすプログラム ffsrv を入れました。
ffsrvは利用方法の一つの例として作ったサンプルです。
ffsrvmod から受け取ったメッセージをstrcmpで比較して、その内容を実行するだけの機能ですが、1台で起こったファイル操作がネットワークでつながった全台に反映されることになります。
例えば「mv /usr/local/apache/htdocs/sample.txt /usr/local/apache/htdocs/des.txt」というオペレーションを行った場合はまったく同じ文が流れます。
元々データの同期が取れていれば、流れてきたコマンドを実行するだけで同期が取れることになります。
chmodやchown、touch -t などの場合は、それぞれ必要とするユーザーIDや時間情報が一緒に流れます。
しかし、「rsync -av 192.168.1.20:/usr/local/apche/htdocs/sample.txt /usr/local/apche/htdocs/」とオペレーションした場合は「copy /usr/local/apche/htdocs/sample.txt /usr/local/apche/htdocs/」といった文が流れるだけで、データそのものがありません。
そのため、全ての文の一番最後にIPアドレスをつけてあります。
このIPアドレスはオペレーションを行ったサーバーのアドレスが入りますので、このサーバーのファイルを何かの方法で取得できれば同期を取ることが出来ます。
サンプルプログラムのffsrvでは「rcp」か「rsync」を使って解決できるようにしてみました。その他色々な方法があると思います。(サンプルクライアントをデーモンとして動かすようにしてみましたが、その際「close(STDIN_FILENO);」こんな感じでクローズしてます。おそらくRsyncはPipeを使って処理するところがあるためだと思うのですが、vforkでrsyncが動きません。もっとも、ほとんどはrcpをつかってるので問題はありませんが・・)
この手法の問題点は、その都度プログラムが起動するためのオーバーヘッドが非常に大きなコストになっています。
そのため、このサンプルプログラムで構成を組む場合は、台数が増えるほど同期完了までの時間が増えていく欠点があります。
カスタマイズ
専用にカスタマイズをかければ、かなり高速に動作させることも可能だと思います。
また、例えばApacheを使ってクライアントを作ることも可能です。やっていることはとても簡単なので、いろんなカスタマイズをかけてみてください。