OCFS2を使った共有storage

Oracle社の OCFS2 を使ったstorageの共有方法についての説明です。

OCFS2はRed Hat社のGFS2 と同様に、1つのblock device を複数の計算機から同時に読み書きすることができる clustered file systemです。 高可用性cluster(serviceが止まらないためのcluster) で使われることが多いようですが、複数の計算機で storage を共有できるため HPC cluster の /home として使うこともできます。

NFSとの違い

まず、clustered file system の紹介として特徴がわかるように、 似たような機能を提供するNFSと比較して違いをみていきます。

NFSの場合は NFS server が複数の NFS client からの読み書き要求をまとめて1つの local file system (ext4, XFS, etc.) へ読み書きします。 すべての読み書きは NFS server を経由するため、 file system の一貫性は自然と保たれます。

それに対してOCFS2などの clustered file system では NFS server にあたるものはありません。 各計算nodeがそれぞれ file system層の処理を行い、 storageに対して個別に読み書きを実施します。 ただし、そのまま各計算nodeが好き勝手に読み書きを行うと file が壊れてしまいますので、一貫性をもった読み書きを実現するための機構として Distributed Lock Manager (DLM) が用いられます。 DLM で他の計算nodeと矛盾しないように調整しながらそれぞれの計算node が並行して storage への読み書きを行うことで、全体として一貫性のある file system を実現しています。

大雑把な理解としては、clustered file system では file system の処理が複数の計算node に分散されて並列処理されていると考えてください。 分散memoryでの並列計算でnode間のデータ交換をMPIが行っているように、 clustered file system では DLM が仲介を行って並列読み書きが実現されると理解してもらえれば良いと思います。

Clustered file system の利点としては、storage device 以外のすべての部分を各計算nodeが持っているという点になります。 可用性の観点からは、NFS の場合は NFS server が止まるとすべてが止まりますが、 clustered file system では NFS server に相当する部分がないので、 1箇所が壊れたためにすべてが止まるということを避けられます。 (高可用性 cluster では storageに冗長構成の RAID controller などが使われ、通信経路も複数用意されたりする)。
性能面をみると、NFS では計算nodeが増えても NFS server の性能が上がるわけではないため、規模が大きくなってくると NFS server の性能で全体の性能が制限されるようになってしまいます。 Clustered file system の場合は file system 層が各計算node で並列処理されるため、台数が増えてきた場合でも NFS よりも高い性能を期待できます。 HPC用途でclustered file systemを採用する場合、この点が NFS に対する大きな利点ということになります。

ちなみに、NFS よりマシな性能が期待できるとしても共有している storage device の性能以上はどうあがいても出せません。 それ以上を要求する場合は、storage deviceも複数用意して Lustre のような分散 file system を検討しましょう。

NFS

User Application User Application
/mnt/data /mnt/data
File System (NFS Client) File System (NFS Client)
UDP or TCP/IP
NFS Server
File System (ext3, ext4, XFS, etc.)
Block Storage Device (/dev/sda)

OCFS2, GFS2

User Application User Application
/mnt/data /mnt/data
File System (OCFS2, GFS2) ← DLM → File System (OCFS2, GFS2)
SAN (SRP, iSCSI, FC, etc.)
Block Storage Device (/dev/sda)

SAS共有 storage

最近、SASで複数台接続できる disk storage 製品がでています。

このあたりの機種だと4台をSASで直結できるため、 小規模なPC cluster(≤8 node)であれば SAN switch なしで安価に高性能な共有 storage を構成することができます。 また、それ以上の台数になる場合にはSAS switch (LSI 6160など) 経由で接続することができます。

安価な PC に NFS serverをやらせるのもありですが、こういった storage 製品の上にOCFS2やGFS2を載せて /home を共有して使うというのも良いでしょう。 この手の storage 製品は複数の論理 drive を作ることができ、 root fs 用の論理 drive を計算 node の台数分用意しておけば boot disk としても使うことができます。 こういう使い方をすれば、計算node を disk less にすることができるので、使い勝手のよい HPC cluster を構成することができます。


参考

ここからはOCFS2を実際に使う方法について説明していきます。 まずは参考文献のlinkです。

Oracle OCFS2
OCFS2の本家
OCFS2 Document
OCFS2のdocument。 OCFS2は設定が簡単なのでこのdocumentにそって設定していけば 15分ぐらいで設定できてしまうはず。 (RHEL除く)
Oracle Public Yum Server
Oracle LinuxのRPM packageが公開されている場所。

Linux kernel選び (RHEL & RHEL clone の場合のみ)

Redhat Enterprise Linux以外のSUSEやDebianなどであれば、 OCFS2のkernel module (ocfs2.ko)が提供されていると思いますので、 この章は読む必要はありません。 User landの用意から読み進めてください。
Oracle Linuxの場合はRHEL互換ですが、kernel部分だけ独自の Oracle Unbreakable Enterprise Kernel (以下UEK)が提供されますのでOCFS2を使いたい場合はUEKを選んでください。

Redhat Enterprise Linux (& そのcloneであるCent OS、Scientific Linuxなど) を使っている場合は少々厄介で、標準ではOCFS2が組み込まれていません。 Redhatとしては自社のGFS2を使えということなのでしょう。 RHELでOCFS2を使うためにはkernelを入れ替える必要があります。 選択としては、

  1. OracleのUnbreakable Enterprise Kernelを使う
  2. OracleからOCFS2 kernel moduleだけを入手する
  3. kernel.orgのvanilla kernelを自分でcompileして使う
  4. RHEL6のkernelに自分でpatch当てして使う

ぐらいから考えますが、どれも一長一短だったりします。 どれも選べないという場合、OCFS2ではなくRedhatのGFS2を使うか、 RHEL以外のOracle LinuxやSUSEなどに移行してしまう選択を考えてください。

Oracle UEKを使う場合

Oracle UEKを使う方法はRPMをinstallするだけなので一番簡単で確実な方法です。 ただし、Oracle Unbreakable Linuxサポートプログラムの契約をしないと updateの提供が行われません。 また、RHELが提供する機能の一部はOracle UEKには含まれません。 (UEKにTransparent Hugepageが含まれないのがHPC用途としては痛いところ)

Firewallの内側で使っていてupdateを諦めることができる場合は UEKを選択するのが良いでしょう。 Redhatに比べてOracle Linuxの方がかなり安価なので いっそのこと乗り換えてしまうというのもアリです。

Installはとても簡単です。 Oracle Public Yum Server から辿っていって、 Oracle Enterprise Linux 5.6 Oracle Linux 6.1 以下にあるkernel-uek-*.rpmを拾ってきてinstallすればokです。

Kernel moduleだけ入手して使う

Oracle OCFS2 にある、RHEL向けの OCFS2 kernel module を使う方法です。
この方法もRPMをinstallするだけなので簡単ですが、 RHEL5までしか提供されませんので、RHEL6以降では他の方法をとる必要があります。 また、Oracle UEKではOCFS2 version 1.6ですが、 こちらはversion 1.4までになります。 1.4から1.6への変更はかなり大きくて、Reflink, ACL, Quota といった機能が1.4では使えません。

RHEL<6 && RHELのkernelを使いたい(UEKはNG) && OCFS2-1.4までの機能でよい、 という条件がそろうならこの方法が良いでしょう。

Vanilla kernelを使う

昔からLinuxを使っているような人は自分でkernel compile をしてしまった方が早いと思います。 Oracle UEK 2.6.32-100.28.5とvanilla kernelでfs/ocfs2以下を比較すると、 Linux-2.6.36がだいたいOracle UEKと同等の内容になっているようです。 ですのでLinux-2.6.36以降であればOCFS2 version 1.6 の機能もたぶん動くでしょう(表示はversion 1.5のままだが)。 手元ではLinux-2.6.38で試していますが、ちゃんと動いているようにみえます。

この方法の最大の問題はRHELのサポート対象外ということです。 でもどうせRHELでOCFS2を使う時点でサポート対象外だしね。

RHEL6のkernelにpatch当てしてocfs2.koを作る

RHEL6でどうしてもRedhat提供のkernelを使いたいという場合ですが、 自分で(or 誰かに頼んで)OCFS2部分にpatchあてする必要があります。 Redhatのkernel sourceにもfs/ocfs2以下は存在していて、 CONFIG_OCFS2_FS=mにすればocfs2.koもできますが、 これを使おうとしても負荷をかけるとkernel panicしてしまい、 そのままでは使い物になりません。

Linux-2.6.32のchangelogを追いかけてみると OCFS2に関してもいくつもbug fixが行われています。 (2.6.32.10, 2.6.32.12, 2.6.32.13, 2.6.32.19, 2.6.32.21, 2.6.32.22, 2.6.32.25, 2.6.32.30, 2.6.32.32, 2.6.32.37で変更が入っている)
これらをRedhatのkernelに対して適用してやれば良いのですが、 RHEL6のkernelはVFS層にも手が入っていてそのまま patchを適用することができません。 多少の手作業でcompileして動くものを作ることはできますが、 本当にその変更で正しいのか私には確証がもてません。 そこまでするなら新しめのvanilla kernelを使った方が精神衛生上も良いでしょう。

# Cent OSの中の人とかpatch適用kernel作ってくれないかな

RHELでOCFS2を使いたい場合、結局なにが問題なのか?

RHEL6のkernelではOCFS2のbugが放置されています。 RHEL 6.1 betaのchangelogも眺めて見ましたがOCFS2の変更は皆無なので、 今後もRedhatからOCFS2のbug fixが提供されることはないと思います。 (RHELではOCFS2はサポート対象外だから当然)
一方、OracleはUnbreakable Enterprise Kernelに組み込みで OCFS2を提供するという方針になったのか、 RHEL6用のOCFS2 kernel moduleを出さなくなってしまいました。
ということで、RHEL6でOCFS2を使おうと思うと、 どちらからもそっぽを向かれた状態になってしまっているわけです。

これはもうちょっと背景があって、、、
RHELならGFS2を使えばいいじゃないかという話もあるのですが、 RHEL6からRedhatのsubscription体系が変わって GFS2を(正規に)使おうとするとResilient Storage addonの契約も必要になりました。 必要なものだけ契約できるようになって安価になったのなら歓迎ですが、これまで Advanced Serverにまとめて入っていたものが小分けにされて値上げされています。 (大幅な値上げだよ、、、4 socketだと2倍以上の値上げじゃないか)
既に買ってしまった3年分のRHEL subscriptionがあるので Oracle LinuxやSUSE SLESに乗り換えにくい、 と言っても計算機追加をする場合は値上げされたsubscriptionを買うのか? と思うと悩ましいわけです。

技術的な視点であれば、open sourceなので好きなkernelを compileして使えば良いだけなのですが。

User landの用意

OCFS2の場合、user landで必要なものはocfs2-toolsだけです。 SUSEやDebianなどであれば標準で入っているはずです。 RHEL (と、そのcloneたち)の場合は、Oracle Linux のものを流用させていただきましょう。 Oracle Public Yum Server から辿っていって、 Oracle Enterprise Linux 5.6 Oracle Linux 6.1 にあるocfs2-tools-1.6.*.rpmをinstallすればokです。

設定

OCFS2の設定はかなり簡単です。 OCFS2 DocumentにあるUser's GuideのV. Getting Started (23頁から)に沿って設定していけば特に難しいところはないと思います。

設定fileは2つだけで、 /etc/ocfs2/cluster.confと/etc/sysconfig/o2cbです。 同じstorageを共有するすべてのhostで同じ設定fileを用意します。 User's Guideではocfs2consoleを使って/etc/ocfs2/cluster.conf を作るような説明になっていますが、text editor で書いてしまった方が早くて楽じゃないでしょうか。

この2つの設定fileに加えて、iptablesによるfirewallが onになっている場合はその設定を変更する必要があります。

/etc/ocfs2/cluster.conf

Storageを共有する計算機の名前とIP、Distributed Lock Managerが使う port番号を書くだけです。 "cluster:"以下のname = My_HPC_Clusterと "node:"以下のcluster = My_HPC_Clusterは名前を合わせる必要があります。 また、後ほどでてくる/etc/sysconfig/o2cbでも同じ名前を使います。 あとはhost名とIPを書いていくだけです。 ちなみに、計算nodeが増える予定があるならあらかじめ余分に"node:" を書いておいた方が後々楽だと思います (書き換えてrebootする手間が省ける)。 存在しない計算nodeとIPが余分に書いてあっても問題なく動きます。

cluster:
        node_count = 5
        name = My_HPC_Cluster

node:
        ip_port = 7777
        ip_address = 192.168.122.1
        number = 1
        name = manage_host
        cluster = My_HPC_Cluster

node:
        ip_port = 7777
        ip_address = 192.168.122.101
        number = 2
        name = compute01
        cluster = My_HPC_Cluster

node:
        ip_port = 7777
        ip_address = 192.168.122.102
        number = 3
        name = compute02
        cluster = My_HPC_Cluster

node:
        ip_port = 7777
        ip_address = 192.168.122.103
        number = 4
        name = compute03
        cluster = My_HPC_Cluster

node:
        ip_port = 7777
        ip_address = 192.168.122.104
        number = 5
        name = compute04
        cluster = My_HPC_Cluster

/etc/sysconfig/o2cb

続いて/etc/sysconfig/o2cbを作成します。 OCFS2のdocumentにしたがって以下のようにして質問に答えていきます。 提示された標準値のままで問題ないと思います。

# service o2cb configure
Configureing the O2CB driver.
...

全部の計算nodeでこれをやっても良いですが、 /etc/sysconfig/o2cbに以下を貼り付けるだけも問題ありません。 My_HPC_Clusterの部分だけ先のcluster.confに合わせて書き換えてください。

O2CB_ENABLED=true
O2CB_STACK=o2cb
O2CB_BOOTCLUSTER=My_HPC_Cluster
O2CB_HEARTBEAT_THRESHOLD=31
O2CB_IDLE_TIMEOUT_MS=30000
O2CB_KEEPALIVE_DELAY_MS=2000
O2CB_RECONNECT_DELAY_MS=2000

/etc/sysconfig/iptables

以下の様に追加部分を1行書き足します。 これで192.168.122.0/24から7777のTCP portへの接続が許可されます。 手書きせずにsystem-config-firewallを使えと書いてあるので、行儀の良い方は system-config-firewallを使ってください。

# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp -s 192.168.122.0/24 --dport 7777 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

設定の反映

以下のようにしてiptables、o2cbをrestartしてください。

# service iptables restart
iptables: Flushing firewall rules:                         [  OK  ]
iptables: Setting chains to policy ACCEPT: filter          [  OK  ]
iptables: Unloading modules:                               [  OK  ]
iptables: Applying firewall rules:                         [  OK  ]
# service o2cb restart
Stopping O2CB cluster My_HPC_Cluster: OK
Unloading module "ocfs2": OK
Unmounting ocfs2_dlmfs filesystem: OK
Unloading module "ocfs2_dlmfs": OK
Unloading module "ocfs2_stack_o2cb": OK
Unmounting configfs filesystem: OK
Unloading module "configfs": OK
Loading filesystem "configfs": OK
Mounting configfs filesystem at /sys/kernel/config: OK
Loading stack plugin "o2cb": OK
Loading filesystem "ocfs2_dlmfs": OK
Mounting ocfs2_dlmfs filesystem at /dlm: OK
Setting cluster stack "o2cb": OK
Starting O2CB cluster My_HPC_Cluster: OK
#

上記のようにOKであれば設定は完了です。

自動起動の確認

ocfs2-toolsをinstallするとOS起動時にo2cb などの必要なものが勝手に起動するようになるはずですが、 念のため確認しましょう。

# chkconfig --list o2cb
o2cb            0:off   1:off   2:on    3:on    4:on    5:on    6:off
# chkconfig --list ocfs2
ocfs2           0:off   1:off   2:on    3:on    4:on    5:on    6:off

Runlevel 2から5がonになっていればokです。 もしonになっていなければ以下の様にしてください。

# chkconfig o2cb on
# chkconfig ocfs2 on

Filesystemの作成 (mkfs.ocfs2)

共有file systemなので、どれか1台のhostからmkfs.ocfs2を実行して file systemを作成します。

# mkfs.ocfs2 -L shared_volume /dev/sdb1
mkfs.ocfs2 1.6.4
Cluster stack: classic o2cb
Label: shared_volume
Features: sparse backup-super unwritten inline-data strict-journal-super xattr
Block size: 4096 (12 bits)
Cluster size: 4096 (12 bits)
Volume size: 34480373760 (8418060 clusters) (8418060 blocks)
Cluster groups: 261 (tail covers 31500 clusters, rest cover 32256 clusters)
Extent allocator size: 8388608 (2 groups)
Journal size: 215498752
Node slots: 8
Creating bitmaps: done
Initializing superblock: done
Writing system files: done
Writing superblock: done
Writing backup superblock: 3 block(s)
Formatting Journals: done
Growing extent allocator: done
Formatting slot map: done
Formatting quota files: done
Writing lost+found: done
mkfs.ocfs2 successful
#

標準設定のままであれば上記のような感じでfile systemが作成されます。 いろいろoptionを指定できますが、以下のoptionは必要があれば指定してください。

-N number-of-node-slots
同時にmountできる最大node数になります。 何も指定しないと8になりますが、後からnodeが 8台よりも増える予定があるのならその分を見越して多めの数を設定しておくべきです。
-L volume-label
File systemの名前になります。 /etc/fstabに"LABLE="などでかけるようになるため、 わかりやすい名前をつけておくことを推奨します。
-T filesystem-type
-Tを指定すると、file systemの使われ方にあった設定で file systemを作ってくれます。 たいていのHPC用途の場合は大きめのfileができることが多いでしょうから、 標準の"-T datafiles"で良いはずです(-T指定なしと等価)。 もし細かなfileが多数できるような使い方をするのであれば、 "-T mail"を指定してやると良いでしょう。
--fs-feature-level=feature-level
OCFS2の機能をどの程度有効にするか選択するoptionです。 OCFS2は徐々に機能が追加されてきたので、古い kernel で読み書きする必要がある場合は "max-compat"を指定しないと読み書きできなくなってしまいます。 OCFS2-1.6対応のkernelからしか読み書きしないのであれば "max-features"にしてしまって良いと思います。 Reflink(snapshotを取る機能)やQuotaなどの最近導入された機能は "max-features"にしないと使えません。
--fs-features=features
個別に機能をon/offする場合に指定します。 OCFS2 Document の User's Guide IV. FILE SYSTEM FEATURES を見ながら以下のような感じで設定できます。
--fs-features=indexed-dirs,metaecc,refcount,discontig-bg,nousrquota,nogrpquota

mountして使ってみる

あとは普通のfile systemと同じようにmountして使えます。 一般のfile systemでは複数のhostから同時に mountすると壊れてしまいますが、OCFS2は共有 file systemであるので複数のhostが同時にmountして使っても問題ありません。

# mkdir /mnt/share
# mount /dev/sdb1 /mnt/share
# umount /mnt/share

/etc/fstab

ちゃんとmountして使えることが確認できたら、 OS起動時に自動でmountさせるために、/etc/fstabに書き込みます。

...
/dev/sdb1  /mnt/share  ocfs2  _netdev,barrier=0,relatime  0 0
...

_netdevを必ずつけてください。 でないと、network interfaceが使えるようになる前にmountしようとして失敗します。

また、battery backupのついていないRAID cacheを使っている場合は "barrier=1"にしてください。 "barrier=0"の方が性能は高くなりますが、 battery backupなしで停電した場合にはfile systemが壊れます。 これはOCFS2にかぎらず他のext4やXFSでも同様で、barrier=1にすると journalの書き込み順を保証するようにして停電などから保護するようになります。

あとはrelatimeでしょう。これも他のfilesystemと同じで不要な access timeの更新を減らして性能が向上する様になります。 特にRAID-5やRAID-6などの書き込み単位が大きくて書き込みが遅い RAID levelを使っている場合には効果があるはずです。 まったくaccess timeの更新が必要なければ、 noatimeの方がさらに不要な書き込みが減ります。

実用に耐えるか?

Webで検索するとうまく動いているところと、 うまく動かないという結果とマチマチのようです。 OCFS2-1.4の頃はinodeが足りなくてdisk-fullになってしまい、 HDDに空きがあるにもかかわらずこれ以上書き込みできないなどの 不具合があったようです。 Release noteを読む限り、OCFS2-1.6でそのあたりは改善されているはずです。

手元の環境でHDD benchmarkのbonnie++とiozoneの繰り返しをを4台の hostから同時に走らせて高負荷試験をやってみました。 とりあえず3日ほど問題なく動き続けていました (UEKではなくて、自分でcompileしたLinux-2.6.38)。 今のところ、難あり、と評価するような結果にはなっていません。 まあExperimentalでなくなってからだいぶ経つので、 ちゃんと動いてくれないと困るわけですが。

この手の共有filesystemを安定して動かすためには、 Distributed Lock Manager(DLM) の通信が安定してかつ遅延なく継続できることが必須です。 HPC用途で使う場合は並列計算用の通信などと DLMの通信は分けて使った方が良さそうな気はします。 DLMの通信だけであればせいぜい10Mbps程度なので、 100Base-TX Ethernetで十分なので専用networkを奢ってやりましょう。 あとはDLM用のnetworkではDHCPでなく固定IP を設定して使うことに注意するぐらいでしょうか。

仮想環境(kvmなど)で使う時の注意

仮想環境のguest同士でOCFS2を使ったstorage共有を行う場合、 disk cache設定に注意してください。 すべてのguestでdisk cache offに設定をそろえないと、 kernel panicしたりfilesystemが壊れたりします。
(Hostのdisk cacheに入っていてまだ物理diskには書かれていない部分を cache offのguestから読みに行くと違ったものが見えてしまうため)

Disk cacheの設定がどうなっているかはRHELなら以下のようにvirshで確認できます。 <shareable/>がついていなければ、virsh editで変更するようにしてください。

# virsh dumpxml guest01
...
 <disk type='block' device='disk'>
  <driver name='qemu' type='raw'/>
  <source dev='/dev/sdb'/>
  <target dev='vdb' bus='virtio'/>
  <shareable/>
  <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
 </disk>
...

# まず仮想環境で実験しようと試したらdisk cacheのせいでまともに動かず、 丸1日ほど悩んでしまった、、、


更新 : 2011-04-30
ご意見、ご感想は、花房 真広 <webmaster@hanabusa.net>まで。メールする前にtop pageの注意書を読んでください。