GlusterFS スプリットブレインの解消方法
スプリットブレインとは
例えば、レプリケーション構成のボリュームにおいて次のような操作をすると、レプリカされたファイルの内容にノード間で矛盾が生じて、GlusterFSは、どちらの内容が正しいかを判断することができなくなります。
※ここでは、「ボリューム構成手順」で作成したボリューム「vol02」を想定します。これは、gluster01とgluster02でレプリケーションされた構成のボリュームです。
-
gluster01を停止
↓
クライアントからファイルを更新(gluster02のみに書き込まれる)
↓
gluster02を停止後、gluster01を再起動
↓
クライアントからファイルを更新(gluster01のみに書き込まれる)
↓
gluster02を再起動
このような状況を「スプリットブレイン」と呼びます。この時、これ以上ファイルの内容が破壊されないように、GlusterFSはクライアントから該当ファイルへのアクセスを禁止します。クライアントから該当ファイルにアクセスすると「I/Oエラー」になります。
スプリットブレイン状態のファイルを回復するには、管理者が各ノードのファイルの内容を直接確認して、不要と判断した方のファイルを手動で削除した上で再レプリケーションを行う必要があります。
スプリットブレインの発生例
意図的にスプリットブレイン状態のファイルを作り出してみます。
「ボリューム構成手順」で作成したボリューム「vol02」を/mntにマウントしたクライアントで下記のシェルスクリプトを実行します。(クライントからglsuter01、gluster02のrootユーザにssh公開鍵認証を設定した後に実行します。)
#!/bin/sh -v echo "volume is healthy." > /mnt/file01.txt ssh gluster01 "pkill glusterfs" sleep 10 echo "gluster01 is dead." >> /mnt/file01.txt ssh gluster02 "pkill glusterfs" ssh gluster01 "service glusterd restart" sleep 10 echo "gluster02 is dead." >> /mnt/file01.txt ssh gluster02 "service glusterd restart" sleep 10 cat /mnt/file01.txt
実行の様子は次のようになります。
$ sudo ./splitbrain.sh #!/bin/sh -v $ echo "volume is healthy." > /mnt/file01.txt $ ssh gluster01 "pkill glusterfs" sleep 10 echo "gluster01 is dead." >> /mnt/file01.txt $ ssh gluster02 "pkill glusterfs" $ ssh gluster01 "service glusterd restart" Stopping glusterd:[ OK ] Starting glusterd:[ OK ] sleep 10 echo "gluster02 is dead." >> /mnt/file01.txt $ ssh gluster02 "service glusterd restart" Stopping glusterd:[ OK ] Starting glusterd:[ OK ] sleep 10 $ cat /mnt/file01.txt cat: /mnt/file01.txt: 入力/出力エラーです 最後に「file01.txt」へのアクセスがI/Oエラーになっていることが分かります。次のように、gluster01とgluster02のブリック内のファイルの内容が相互に異なることが分かります。
$ ssh gluster01 cat /data/brick02/file01.txt volume is healthy. gluster02 is dead.
ssh gluster02 cat /data/brick02/file01.txt
volume is healthy. gluster01 is dead.
この状態でSelf-heal daemonによる再レプリケーションを行なっても次のように「split-brain」を検出してfile01.txtの再レプリケーションに失敗します。
$ sudo gluster vol heal vol02 full Heal operation on volume vol02 has been successful
$ sudo tail /var/log/glusterfs/glustershd.log ・・・ [2012-09-09 16:40:05.086235] W [afr-self-heal-data.c:831:afr_lookup_select_read_child_by_txn_type] 0-vol02-replicate-0: /file01.txt: Possible split-brain [2012-09-09 16:40:05.086273] W [afr-common.c:1226:afr_detect_self_heal_by_lookup_status] 0-vol02-replicate-0: split brain detected during lookup of /file01.txt. [2012-09-09 16:40:05.086286] I [afr-common.c:1340:afr_launch_self_heal] 0-vol02-replicate-0: background data gfid self-heal triggered. path: /file01.txt, reason: lookup detected pending operations [2012-09-09 16:40:05.086887] I [afr-self-heal-common.c:1318:afr_sh_missing_entries_lookup_done] 0-vol02-replicate-0: No sources for dir of /file01.txt, in missing entry self-heal, continuing with the rest of the self-heals [2012-09-09 16:40:05.087138] I [afr-self-heal-common.c:994:afr_sh_missing_entries_done] 0-vol02-replicate-0: split brain found, aborting selfheal of /file01.txt [2012-09-09 16:40:05.087155] E [afr-self-heal-common.c:2156:afr_self_heal_completion_cbk] 0-vol02-replicate-0: background data gfid self-heal failed on /file01.txt
## スプリットブレインの解消手順 上述のfile01.txtのスプリットブレイン状態を解消します。ここでは、gluster01のブリック内のファイルを削除して、gluster02のブリック内のファイルを再レプリケーションします。 gluster01において、次の手順でブリック内のfile01.txtを削除します。
$ sudo gluster vol stop vol02 Stopping volume will make its data inaccessible. Do you want to continue? (y/n) y Stopping volume vol02 has been successful
$ sudo getfattr -d -m trusted.gfid -e hex /data/brick02/file01.txt getfattr: Removing leading '/' from absolute path names
file: data/brick02/file01.txt
trusted.gfid=0xc53b6eef92974d928dcb48744aa0231e
$ sudo rm -f /data/brick02/file01.txt $ sudo rm -f /data/brick02/.glusterfs/c5/3b/c53b6eef-9297-4d92-8dcb-48744aa0231e
$ sudo gluster vol start vol02 Starting volume vol02 has been successful
はじめに、vol02を停止しています。次の「getfattr」コマンドでは、削除対象ファイルのGFID(GlusterFSが内部的に割り当てるID番号)を確認しています。その上で、該当ファイルと、隠しディレクトリ「.glusterfs」の下にある、対応するGFIDファイル(実態は、file01.txtへのハードリンクです)を削除しています。最後にvol02を再度、開始しています。 この後、vol02の再レプリケーションを行うと、次のようにfile01.txtが正常に再レプリケーションされます。
$ sudo gluster vol heal vol02 full Heal operation on volume vol02 has been successful
$ sudo tail /var/log/glusterfs/glustershd.log ・・・ [2012-09-09 16:48:05.873435] I [afr-common.c:1340:afr_launch_self_heal] 0-vol02-replicate-0: entry self-heal triggered. path: /, reason: checksums of directory differ [2012-09-09 16:48:05.878198] E [afr-self-heal-common.c:1087:afr_sh_common_lookup_resp_handler] 0-vol02-replicate-0: path /file01.txt on subvolume vol02-client-0 => -1 (No such file or directory) [2012-09-09 16:48:05.879628] I [afr-self-heal-common.c:2159:afr_self_heal_completion_cbk] 0-vol02-replicate-0: background entry self-heal completed on / [2012-09-09 16:48:05.880925] I [afr-common.c:1189:afr_detect_self_heal_by_iatt] 0-vol02-replicate-0: size differs for /file01.txt [2012-09-09 16:48:05.880943] I [afr-common.c:1340:afr_launch_self_heal] 0-vol02-replicate-0: background meta-data data self-heal triggered. path: /file01.txt, reason: lookup detected pending operations [2012-09-09 16:48:05.885937] I [afr-self-heal-algorithm.c:116:sh_loop_driver_done] 0-vol02-replicate-0: full self-heal completed on /file01.txt [2012-09-09 16:48:05.887655] I [afr-self-heal-common.c:2159:afr_self_heal_completion_cbk] 0-vol02-replicate-0: background meta-data data self-heal completed on /file01.txt
クライアントからfile01.txtに正常にアクセスするには、ファイルシステムの再マウントが必要になります。
$ sudo umount /mnt $ sudo mount -t glusterfs gluster01:/vol02 /mnt $ sudo cat /mnt/file01.txt volume is healthy. gluster01 is dead.
参考までに、下記はブリック内のファイルとハードリンクをまとめて削除するスクリプトです。
!/bin/sh
#
delfile.sh - Delete file and hardlink in bricks
#
function usage {
echo "Usage: $0
-z $1 || -z $2 && usage
brick=$1 file=$2
if ! -f ${file} ; then echo "File ${file} is not found." usage fi
gfid=$(getfattr -n trusted.gfid --absolute-names -e hex ${file} | grep 0x | cut -d'x' -f2) hlink=${brick}/.glusterfs/${gfid:0:2}/${gfid:2:2}/${gfid:0:8}-${gfid:8:4}-${gfid:12:4}-${gfid:16:4}-${gfid:20:12}
if ! -f ${hlink} ; then echo "Hardlink ${hlink} is not found." usage fi
echo "Delete file: ${file}" echo "Delete hardlink: ${hlink}" rm -f ${file} ${hlink}
次のようにブリックのディレクトリとファイルを指定して実行します。
$ sudo ./delfile.sh
Usage: ./delfile.sh
$ sudo ./delfile.sh /data/brick01 /data/brick01/dir01/file01.txt Delete file: /data/brick01/dir01/file01.txt Delete hardlink: /data/brick01/.glusterfs/14/bb/14bb8bab-5e79-4413-a7c0-adf2994b9634