何をするかというと。
共有ディスクを使わずにDRBDでローカルディスクのデータを同期させて、HAクラスタを組むというテクニックがあります。それはそれでありなのですが、障害発生後の再同期に時間がかかるなど、なかなか運用が大変なのも事実です。
で、DRBDの代わりに、GlusterFSのレプリケーション機能を使ってローカルディスクのファイルを同期させたらどうだろう、と思って試してみました。
GlusterFSについては、下記の資料を参照ください。
GlusterFSと組み合わせるHAは、RHEL6 High Availability Add-Onです。High Availability Add-Onについては、下記を参照。
構成
物理サーバを用意するのが面倒なので、KVM仮想マシンで組みました。
High Availability Add-Onの基本セットアップ手順は下記を参照。今回は、共有ディスクは使わないので、iSCSIのセットアップは不要です。
GlusterFSの導入・設定
Glusterの導入:両ノードで実施
# yum groupinstall "Development tools" # wget http://download.gluster.com/pub/gluster/glusterfs/qa-releases/3.3-beta-2/glusterfs-3.3beta2.tar.gz # tar -xvzf glusterfs-3.3beta2.tar.gz # cd glusterfs-3.3beta2 # ./configure && make # make install # chkconfig glusterd on # service glusterd start
ディレクトリの準備:両ノードで実施
# mkdir /glvol00 # mkdir /gldata00
/glvol00は、この後で定義するボリュームのバックエンド領域(Brick)として使います。本来はルートファイルシステムとは別に専用のファイルシステムをマウントしておくのがよいでしょう。/gldata00は共有ファイルシステムのマウントポイントです。
PeerとVolumeの定義:node01のみで実施
# gluster peer probe node02h # gluster volume create data00 replica 2 transport tcp node01m:/glvol00 node02m:/glvol00 # gluster volume start data00 # gluster volume info data00 Volume Name: data00 Type: Replicate Status: Started Number of Bricks: 2 Transport-type: tcp Bricks: Brick1: node01m:/glvol00 Brick2: node02m:/glvol00
共有ファイルシステムをマウントするためのスクリプトを用意します。両ノードに共通で配置してください。
/etc/init.d/glmount
#!/bin/bash MOUNTPOINT=/gldata00 # Mount Point GLVOL=localhost:data00 # Gluster Volume start() { status rc=$? if [[ $rc -eq 0 ]]; then RETVAL=0 else mount -t glusterfs -o log-level=WARNING,log-file=/var/log/gluster.log $GLVOL $MOUNTPOINT RETVAL=$? fi } stop() { status rc=$? if [[ $rc -eq 0 ]]; then umount $MOUNTPOINT # RETVAL=$? RETVAL=0 # ignore umount failure else RETVAL=0 fi } status() { mount | grep $MOUNTPOINT >/dev/null 2>&1 return $? } restart() { stop start } selfheal() { status rc=$? if [[ $rc -eq 0 ]]; then echo "You should unmount the shared fs first." RETVAL=1 else start find $MOUNTPOINT -noleaf -print0 | xargs --null stat stop RETVAL=0 fi } case "$1" in start) start ;; stop) stop ;; restart) restart ;; status) status ;; selfheal) selfheal ;; *) echo $"Usage: $0 {start|stop|restart|status|selfheal}" RETVAL=2 esac exit $RETVAL
オプションは次の通り
オプション | 説明 |
---|---|
start | マウントする |
stop | アンマウントする |
status | マウントしてたら0を返す。マウントしてなかったら1を返す |
selfheal | 障害回復後にレプリケーションを再同期する。アンマウントした状態で実行する |
PostgreSQLの導入
サンプルアプリケーションとして PostgreSQL を使用します。
node01で実施
# yum install postgresql-server # echo "PGDATA=/gldata00/pgsql" > /etc/sysconfig/pgsql/postgresql # chkconfig postgresql off # /etc/init.d/glmount start # service postgresql initdb #### /gldata00/pgsql/pg_hba.conf, postgresql.confを適宜編集後、起動確認 # service postgresql start postgresql サービスを開始中: [ OK ] # service postgresql stop postgresql サービスを停止中: [ OK ] # /etc/init.d/glmount stop
node02で実施
# yum install postgresql-server # chkconfig postgresql off # echo "PGDATA=/gldata00/pgsql" > /etc/sysconfig/pgsql/postgresql #### node01でinitdbしたもので、PostgreSQLが起動することを確認 # /etc/init.d/glmount start # service postgresql start postgresql サービスを開始中: [ OK ] # service postgresql stop postgresql サービスを停止中: [ OK ] # /etc/init.d/glmount stop
HAクラスタの構成
/etc/cluster/cluster.conf
<?xml version="1.0"?> <cluster config_version="1" name="cluster01"> <cman expected_votes="1" two_node="1"/> <clusternodes> <clusternode name="node01h" nodeid="1" votes="1"> <fence> <method name="virsh_reboot"> <device name="kvmhost01" port="RHCSvm01-gluster"/> </method> </fence> </clusternode> <clusternode name="node02h" nodeid="2" votes="1"> <fence> <method name="virsh_reboot"> <device name="kvmhost01" port="RHCSvm02-gluster"/> </method> </fence> </clusternode> </clusternodes> <totem token="20000"/> <fencedevices> <fencedevice agent="fence_virsh" identity_file="/etc/cluster/fence_virsh_key" ipaddr="192.168.8.1" login="root" name="kvmhost01" option="reboot"/> </fencedevices> <rm> <failoverdomains> <failoverdomain name="dom01" ordered="0" restricted="1"> <failoverdomainnode name="node01h" priority="1"/> <failoverdomainnode name="node02h" priority="2"/> </failoverdomain> </failoverdomains> <service autostart="0" domain="dom01" name="service01"> <ip address="192.168.7.99" monitor_link="on"/> <script file="/etc/init.d/glmount" name="glmount"> <script file="/etc/init.d/postgresql" name="pgsql"/> </script> </service> </rm> </cluster>
注目点は、サービスリソースの定義部分で、下記の3種類のリソースを定義しています。
<service autostart="0" domain="dom01" name="service01"> # サービスIPアドレス <ip address="192.168.7.99" monitor_link="on"/> # 共有ファイルシステムのマウント <script file="/etc/init.d/glmount" name="glmount"> # PostgreSQLの起動 <script file="/etc/init.d/postgresql" name="pgsql"/> </script> </service>
動作テスト
クラスタの起動とサービスの開始:node01で実施
# clstart_all Starting cluster: Checking if cluster has been disabled at boot... [ OK ] Checking Network Manager... Starting cluster: Checking if cluster has been disabled at boot... [ OK ] Checking Network Manager... [ OK ] Global setup... [ OK ] Loading kernel modules... [ OK ] Global setup... [ OK ] Loading kernel modules... [ OK ] Mounting configfs... [ OK ] Mounting configfs... [ OK ] Starting cman... [ OK ] Starting cman... [ OK ] [ OK ] Waiting for quorum... Waiting for quorum... [ OK ] [ OK ] Starting fenced... Starting fenced... [ OK ] Starting dlm_controld... [ OK ] Starting dlm_controld... [ OK ] Starting gfs_controld... [ OK ] Starting gfs_controld... [ OK ] Unfencing self... [ OK ] Unfencing self... [ OK ] Joining fence domain... [ OK ] Joining fence domain... [ OK ] [ OK ] Starting Cluster Service Manager: Starting Cluster Service Manager: [ OK ] [ OK ] # clustat Cluster Status for cluster01 @ Thu Sep 15 14:36:40 2011 Member Status: Quorate Member Name ID Status ------ ---- ---- ------ node01h 1 Online, Local, rgmanager node02h 2 Online, rgmanager Service Name Owner (Last) State ------- ---- ----- ------ ----- service:service01 (none) disabled # clusvcadm -e service01 Local machine trying to enable service:service01...Success service:service01 is now running on node01h # clustat Cluster Status for cluster01 @ Thu Sep 15 14:37:15 2011 Member Status: Quorate Member Name ID Status ------ ---- ---- ------ node01h 1 Online, Local, rgmanager node02h 2 Online, rgmanager Service Name Owner (Last) State ------- ---- ----- ------ ----- service:service01 node01h started # df Filesystem 1K-ブロック 使用 使用可 使用% マウント位置 /dev/vda2 6047492 3318144 2422148 58% / tmpfs 510788 22556 488232 5% /dev/shm /dev/vda1 198337 62649 125448 34% /boot localhost:data00 6047488 3318144 2422144 58% /gldata00 # su - postgres -c "psql -l" データベース一覧 名前 | 所有者 | エンコーディング | 照合順序 | Ctype(変換演算子) | アクセス権 -----------+----------+------------------+-------------+-------------------+----------------------- postgres | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | template0 | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres : postgres=CTc/postgres template1 | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres : postgres=CTc/postgres (3 行)
成功。ちゃんと共有ファイルシステムもマウントされて、PostgreSQLも起動しています。
node01で擬似障害発生:node01で実施
# pkill -9 corosync
node02で引継ぎ確認:node02で実施
# clustat Cluster Status for cluster01 @ Thu Sep 15 14:42:48 2011 Member Status: Quorate Member Name ID Status ------ ---- ---- ------ node01h 1 Offline node02h 2 Online, Local, rgmanager Service Name Owner (Last) State ------- ---- ----- ------ ----- service:service01 node02h started # df Filesystem 1K-ブロック 使用 使用可 使用% マウント位置 /dev/vda2 6047492 3306196 2434096 58% / tmpfs 510788 22556 488232 5% /dev/shm /dev/vda1 198337 47989 140108 26% /boot localhost:data00 6047488 3306240 2434048 58% /gldata00 # su - postgres $ createdb testdb $ psql -l データベース一覧 名前 | 所有者 | エンコーディング | 照合順序 | Ctype(変換演算子) | アクセス権 -----------+----------+------------------+-------------+-------------------+----------------------- postgres | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | template0 | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres : postgres=CTc/postgres template1 | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres : postgres=CTc/postgres testdb | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | (4 行)
オッケーです。最後に、node01へのresyncがうまくいくかみるために新しいDB(testdb)を作成してます。
node01の再起動後に回復処理実施:node01で実施
### まずはGlusterdの稼働を確認 # gluster peer status Number of Peers: 1 Hostname: node02m Uuid: a4b9d549-5c0f-498d-b33a-426ba50f8bf7 State: Peer in Cluster (Connected) # gluster volume info data00 Volume Name: data00 Type: Replicate Status: Started Number of Bricks: 2 Transport-type: tcp Bricks: Brick1: node01m:/glvol00 Brick2: node02m:/glvol00 ###レプリケーションの再同期を実施 # /etc/init.d/glmount selfheal (中略) File: `/gldata00/pgsql/global/1260_fsm' Size: 24576 Blocks: 56 IO Block: 131072 通常ファイル Device: 14h/20d Inode: 18446744073076288545 Links: 1 Access: (0600/-rw-------) Uid: ( 26/postgres) Gid: ( 26/postgres) Access: 2011-09-15 14:47:24.686158005 +0900 Modify: 2011-09-15 14:26:33.050339178 +0900 Change: 2011-09-15 14:26:33.050339178 +0900 File: `/gldata00/pgsql/pg_ident.conf' Size: 1631 Blocks: 16 IO Block: 131072 通常ファイル Device: 14h/20d Inode: 18446744072504937921 Links: 1 Access: (0600/-rw-------) Uid: ( 26/postgres) Gid: ( 26/postgres) Access: 2011-09-15 14:28:36.965551698 +0900 Modify: 2011-09-15 14:26:22.529132482 +0900 Change: 2011-09-15 14:26:22.532127898 +0900 ### HAクラスタの起動とサービスのTake Back # clstart Starting cluster: Checking if cluster has been disabled at boot... [ OK ] Checking Network Manager... [ OK ] Global setup... [ OK ] Loading kernel modules... [ OK ] Mounting configfs... [ OK ] Starting cman... [ OK ] Waiting for quorum... [ OK ] Starting fenced... [ OK ] Starting dlm_controld... [ OK ] Starting gfs_controld... [ OK ] Unfencing self... [ OK ] Joining fence domain... [ OK ] Starting Cluster Service Manager: [ OK ] # clustat Cluster Status for cluster01 @ Thu Sep 15 14:58:34 2011 Member Status: Quorate Member Name ID Status ------ ---- ---- ------ node01h 1 Online, Local, rgmanager node02h 2 Online, rgmanager Service Name Owner (Last) State ------- ---- ----- ------ ----- service:service01 node02h started # clusvcadm -r service01 -m node01h Trying to relocate service:service01 to node01h...Success service:service01 is now running on node01h # clustat Cluster Status for cluster01 @ Thu Sep 15 14:59:10 2011 Member Status: Quorate Member Name ID Status ------ ---- ---- ------ node01h 1 Online, Local, rgmanager node02h 2 Online, rgmanager Service Name Owner (Last) State ------- ---- ----- ------ ----- service:service01 node01h started # su - postgres -c "psql -l" データベース一覧 名前 | 所有者 | エンコーディング | 照合順序 | Ctype(変換演算子) | アクセス権 -----------+----------+------------------+-------------+-------------------+----------------------- postgres | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | template0 | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres : postgres=CTc/postgres template1 | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres : postgres=CTc/postgres testdb | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | (4 行)
オッケーです。
まとめ
まずは普通に構成できることは確認できました。あと、GlusterFSのアクセスタイムアウト時間などに合わせて、障害検知時間のチューニングなどが必要になると思います。
あとは、みんな気になるパフォーマンスですが、こちらは、別環境でじっくりと確認する予定です。