NBD + Device Mapper + OCFS2 + 動的にノードを追加
最近のトレンドであるクラスタファイルシステムの一つ「OCFS2」を、4+1台のPCで動かしてみました。(1台は後から追加)
ディスクの共有には今流行の「iSCSI」ではなく、Linuxの知られざる古参機能「NBD」(Network Block Device)を使用。NBDを4台のマシンで動かして、それをDevice Mapperを使ってRAID 0アレイにして、それをOCFS2で共有します。(mdadm RAID1はうまくいかず)
NBDはiSCSIと似た感じのもので、サーバーにあるファイルやブロックデバイスをクライアント側でブロックデバイスとして認識できます。V-FIELDを開発する前はVIVERで使っていました。RAID 0にするには素直にmdadmを使えばいいのですが、普通だと普通なので。
ディストリビューションはMandriva Linux 2007.1、カーネルはディストリビューションに付いてきた2.6.17-13mdvです。4台のPCのうち1台だけが何故かx86_64で、他は全部x86です。
カーネルの準備
NBDとDevice MapperとOCFS2が必要ですが、NBDはLinux 2.2からの機能で、Device MapperはLVM2のバックエンドで、OCFS2は最近のトレンドですから、先端を行くLinuxディストリビューションのカーネルであればそのまま使えると思います。Mandriva Linux 2007.1ではそのまま使えました。
NBDは、modprobe nbd で使えるようになります。udevがあれば/dev/にmajorが43のnbd0, nbd1, ...というブロックデバイスが現れます。
ユーザーランドツールのインストール
NBDのユーザーランドツール(nbd-serverとnbd-client)はSourceForgeのプロジェクトページからダウンロードできます。./configure && makeでOKです。昔のバージョンは非常に単純なものだったのですが、最近GLibに依存していたりと多機能化の様相を呈しています。ここで使ったバージョンは2.6.9です。
Device Mapperのユーザーランドツール(dmsetup)は、LVM2のコマンド群をapt/yum/yast/urpmi等でインストールすれば付いてきます。
OCFS2はどこぞからダウンロードしてきてソースからコンパイルするか、apt/yum等で。Mandrivaにはパッケージがあったので、urpmiでインストールできました。バージョンはocfs2-tools-1.2.3-2mdv2007.1です。
NBD
さて、すべてのマシンで同じサイズのディスクイメージを作り、NBDでエクスポートします。4台のPCのホスト名は、それぞれvix0.local., vix1.local., …です。
[root@vix0 work]# dd if=/dev/zero of=disk.img bs=1M count=1024 [root@vix0 work]# ./nbd-server 4300 `pwd`/disk.img
[root@vix1 work]# dd if=/dev/zero of=disk.img bs=1M count=1024 [root@vix1 work]# ./nbd-server 4300 `pwd`/disk.img
[root@vix2 work]# dd if=/dev/zero of=disk.img bs=1M count=1024 [root@vix2 work]# ./nbd-server 4300 `pwd`/disk.img
[root@vix3 work]# dd if=/dev/zero of=disk.img bs=1M count=1024 [root@vix3 work]# ./nbd-server 4300 `pwd`/disk.img
nbd-serverの起動時に何やらWARNINGが出ますが、まぁ動いているので気にしないことに。
すべてのホストで、他のホストからエクスポートされているNBDを/dev/nbd[0123]に取り込みます。
[root@vix0 work]# for n in `seq 0 3`; do ./nbd-client vix${n}.local. 4300 /dev/nbd${n}; done Negotiation: ..size = 1048576KB bs=1024, sz=1048576 Negotiation: ..size = 1048576KB bs=1024, sz=1048576 Negotiation: ..size = 1048576KB bs=1024, sz=1048576 Negotiation: ..size = 1048576KB bs=1024, sz=1048576
[root@vix1 work]# for n in `seq 0 3`; do ./nbd-client vix${n}.local. 4300 /dev/nbd${n}; done Negotiation: ..size = 1048576KB bs=1024, sz=1048576 Negotiation: ..size = 1048576KB bs=1024, sz=1048576 Negotiation: ..size = 1048576KB bs=1024, sz=1048576 Negotiation: ..size = 1048576KB bs=1024, sz=1048576
…以下vix2、vix3で同様に。
Device Mapper
/dev/nbd[0123]をDevice Mapperを使ってストライピングします。
dmsetupコマンドは標準入力からマッピングテーブルを読み込んで、それに従って新しいブロックデバイスを作ります。詳しくはman dmsetup参照。
以下のようなスクリプトを作って、マッピングテーブルを作りました。
#!/bin/bash size=0 num=0 devs="" for dev in $* ;do [ ! -b "$dev" ] && continue s=$(blockdev --getsize $1) size=$(expr $size + $s) num=$(expr $num + 1) devs="$devs $dev 0" done echo "0 $size striped $num 32 $devs"
↓このような出力になります。
[root@vix0 work]# ./tabling-striped /dev/nbd[0123] 0 8388608 striped 4 32 /dev/nbd0 0 /dev/nbd1 0 /dev/nbd2 0 /dev/nbd3 0
このテーブルを読み込ませて、nbdsanという名前のブロックデバイスを作ります。
[root@vix0 work]# ./tabling-striped /dev/nbd[0123] | dmsetup create nbdsan
[root@vix1 work]# ./tabling-striped /dev/nbd[0123] | dmsetup create nbdsan
[root@vix2 work]# ./tabling-striped /dev/nbd[0123] | dmsetup create nbdsan
[root@vix3 work]# ./tabling-striped /dev/nbd[0123] | dmsetup create nbdsan
これで/dev/mapper/nbdsanというブロックデバイスができます。
[root@vix0 work]# blockdev --getsize /dev/mapper/nbdsan 8388608
ちなみにtabling-stripedの代わりに以下のスクリプトを使うと、ストライピングではなく単純な接続(linear)ができます。(VIVER 0.2で使っていました)
#!/bin/bash offset=0 for dev in $* ;do [ ! -b "$dev" ] && continue size=$(blockdev --getsize $dev) echo $offset $size linear $dev 0 offset=$(expr $offset + $size) done
OCFS2
/etc/ocfs2/cluster.confを編集します。GFS2のような複雑なものではないので、手で簡単に書けます。
node: ip_port = 7777 ip_address = 192.168.0.38 number = 0 name = vix0 cluster = nbdsan node: ip_port = 7777 ip_address = 192.168.0.24 number = 1 name = vix1 cluster = nbdsan node: ip_port = 7777 ip_address = 192.168.0.11 number = 2 name = vix2 cluster = nbdsan node: ip_port = 7777 ip_address = 192.168.0.7 number = 3 name = vix3 cluster = nbdsan cluster: node_count = 4 name = nbdsan
IPアドレスがバラバラなのはDHCPで割り振っているせいです。「name =」パラメータは、それぞれのホストのショートホスト名 と合わせておく必要があるようです。
すべてのホストで同じ設定にします。
続いて、ディストリビューションによってパスは異なると思いますが、/etc/sysconfig/o2cbを編集します。これもすべてのホストで同じ設定にします。
-O2CB_ENABLED=false -O2CB_BOOTCLUSTER=ocfs2 +O2CB_ENABLED=true +O2CB_BOOTCLUSTER=nbdsan
おそらくO2CB_BOOTCLUSTER=は/etc/ocfs2/cluster.confのcluster:ディレクティブのname=パラメータと一致させる必要があります。
そしてo2cbサービスを起動します。
[root@vix0 work]# /etc/init.d/o2cb start Loading module "configfs": OK Mounting configfs filesystem at /sys/kernel/config: OK Loading module "ocfs2_nodemanager": OK Loading module "ocfs2_dlm": OK Loading module "ocfs2_dlmfs": OK Creating directory '/dlm': OK Mounting ocfs2_dlmfs filesystem at /dlm: OK Starting O2CB cluster nbdsan: OK
[root@vix1 work]# /etc/init.d/o2cb start Loading module "configfs": OK Mounting configfs filesystem at /sys/kernel/config: OK Loading module "ocfs2_nodemanager": OK Loading module "ocfs2_dlm": OK Loading module "ocfs2_dlmfs": OK Creating directory '/dlm': OK Mounting ocfs2_dlmfs filesystem at /dlm: OK Starting O2CB cluster nbdsan: OK
以下他のホストでも同様に。
mkfs、mount
o2cbの設定の後に、mkfs.ocfs2を実行します。
[root@vix0 work]# mkfs.ocfs2 -N 5 /dev/mapper/nbdsan mkfs.ocfs2 1.2.3 Filesystem label= Block size=4096 (bits=12) Cluster size=4096 (bits=12) Volume size=4294967296 (1048576 clusters) (1048576 blocks) 33 cluster groups (tail covers 16384 clusters, rest cover 32256 clusters) Journal size=67108864 Initial number of node slots: 4 Creating bitmaps: done Initializing superblock: done Writing system files: done Writing superblock: done Writing backup superblock: 1 block(s) Formatting Journals: done Writing lost+found: done mkfs.ocfs2 successful
これは1台でやればOKです。
-N 5オプションは、スロット数(おそらくそのデバイスを同時にマウントできるノード数)です。後で1台追加するので5にしておきました。このオプションを指定しないとその時点での必要最低限の数(ここでは4)になって、後で足りなくなってマウントできなくなります。tunefs.ocfs2で後から増やすこともできるようですが、一度全部アンマウントする必要があるようです。
いざmount
[root@vix0 work]# mount -t ocfs2 /dev/mapper/nbdsan /mnt/nbdsan
[root@vix1 work]# mount -t ocfs2 /dev/mapper/nbdsan /mnt/nbdsan
[root@vix2 work]# mount -t ocfs2 /dev/mapper/nbdsan /mnt/nbdsan
[root@vix3 work]# mount -t ocfs2 /dev/mapper/nbdsan /mnt/nbdsan
mountに少し時間がかかるのでどきっとしますが、問題なしです。
後は自由に/mnt/nbdsanに書き込みができます。
動的にノードを追加する
別のホスト「vc.local.」をクラスタに追加して、vc.local.からでも書き込みができるようにしてみます。
まずはvc.local.でNBDをインポートして、dmsetupします。
[root@vc work]# modprobe nbd [root@vc work]# for n in `seq 0 3`;do ./nbd-client 4300 vix${n}.local. /dev/nbd${n}; done Negotiation: ..size = 1048576KB bs=1024, sz=1048576 Negotiation: ..size = 1048576KB bs=1024, sz=1048576 Negotiation: ..size = 1048576KB bs=1024, sz=1048576 Negotiation: ..size = 1048576KB bs=1024, sz=1048576 [root@vc work]# modprobe dm-mod [root@vc work]# ./tabling-striped /dev/nbd[0123] | dmsetup create nbdsan
vc.local.の/etc/sysconfig/o2cbを編集します。
-O2CB_ENABLED=false -O2CB_BOOTCLUSTER=ocfs2 +O2CB_ENABLED=true +O2CB_BOOTCLUSTER=nbdsan
vc.local.の/etc/ocfs2/cluster.confを書きます。他のノードのcluster.confをコピーしきて、vc.local.のエントリを追加します。
node: ip_port = 7777 ip_address = 192.168.0.38 number = 0 name = vix0 cluster = nbdsan node: ip_port = 7777 ip_address = 192.168.0.24 number = 1 name = vix1 cluster = nbdsan node: ip_port = 7777 ip_address = 192.168.0.11 number = 2 name = vix2 cluster = nbdsan node: ip_port = 7777 ip_address = 192.168.0.7 number = 3 name = vix3 cluster = nbdsan node: ip_port = 7777 ip_address = 192.168.0.8 number = 4 name = vc cluster = nbdsan cluster: node_count = 4 name = nbdsan
まだo2cbサービスは起動しません。
vc.local.以外のホストで以下のコマンドを実行します。
[root@vix0 work]# o2cb_ctl -C -n vc -t node -i \ -a ip_port=7777 \ -a ip_address=192.168.0.8 \ -a number=4 \ -a cluster=nbdsan Node vc created
[root@vix1 work]# o2cb_ctl -C -n vc -t node -i \ -a ip_port=7777 \ -a ip_address=192.168.0.8 \ -a number=4 \ -a cluster=nbdsan Node vc created
同様にvix2.local, vix3.local. でも実行します。
ここでvc.local.のo2cbサービスを起動します。
[root@vc work]# /etc/init.d/o2cb start Loading module "configfs": OK Mounting configfs filesystem at /sys/kernel/config: OK Loading module "ocfs2_nodemanager": OK Loading module "ocfs2_dlm": OK Loading module "ocfs2_dlmfs": OK Mounting ocfs2_dlmfs filesystem at /dlm: OK Starting O2CB cluster nbdsan: OK
いざmount!
[root@vc work]# mount -t ocfs2 /dev/mapper/nbdsan /mnt/nbdsan
試しにvc.local.から/mnt/nbdsanに書き込んでみます。
[root@vc work]# dd if=/dev/zero of=/mnt/nbdsan/test.img bs=1M count=400 400+0 records in 400+0 records out 419430400 bytes (419 MB) copied, 6.65249 seconds, 63.0 MB/s
vix0.local.から書き込んでみます。
[root@vix2 work]# dd if=/dev/zero of=/mnt/nbdsan/test2.img bs=1M count=400 400+0 records in 400+0 records out 419430400 bytes (419 MB) copied, 2.57737 seconds, 163 MB/s
ちなみにvix[0123].local.はAMD Athlon64 X2 4800+, メモリ2GB, Intel PRO/1000の実機で、vc.local.はVMware上の仮想マシンです(ホストはAMD Athlon64 X2 5000+, メモリ2GB, Intel PRO/1000, ゲストでエミュレーションされているNICはGigabitEthernet)。
これで終わりです。