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)。



これで終わりです。