Oracle社の OCFS2 を使ったstorageの共有方法についての説明です。
OCFS2はRed Hat社のGFS2 と同様に、1つのblock device を複数の計算機から同時に読み書きすることができる clustered file systemです。 高可用性cluster(serviceが止まらないためのcluster) で使われることが多いようですが、複数の計算機で storage を共有できるため HPC cluster の /home として使うこともできます。
まず、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 を検討しましょう。
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) |
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で複数台接続できる 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です。
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を入れ替える必要があります。 選択としては、
ぐらいから考えますが、どれも一長一短だったりします。 どれも選べないという場合、OCFS2ではなくRedhatのGFS2を使うか、 RHEL以外のOracle LinuxやSUSEなどに移行してしまう選択を考えてください。
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です。
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までの機能でよい、 という条件がそろうならこの方法が良いでしょう。
昔から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でどうしても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作ってくれないかな
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して使えば良いだけなのですが。
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になっている場合はその設定を変更する必要があります。
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を作成します。 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
以下の様に追加部分を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
共有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は必要があれば指定してください。
あとは普通のfile systemと同じようにmountして使えます。 一般のfile systemでは複数のhostから同時に mountすると壊れてしまいますが、OCFS2は共有 file systemであるので複数のhostが同時にmountして使っても問題ありません。
# mkdir /mnt/share # mount /dev/sdb1 /mnt/share
# umount /mnt/share
ちゃんと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 を設定して使うことに注意するぐらいでしょうか。
仮想環境の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日ほど悩んでしまった、、、