めもめも

このブログに記載の内容は個人の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

RHS2.0/Gluster3.3の分散ファイルロック機能

表題の機能を動作確認したので、結果を残しておきます。

概要

node01, node02の2台のクライアントで、同じボリュームをNativeプロトコル、もしくはNFSでマウントします。この状態で、一方のクライアントがボリューム上のファイルにflock()(Linux独自のAdvisory Lock)、もしくはlockf()(POSIX File Lock)を取得すると、もう一方のクライアントからもロックが認識されます。

特にNFSロックは、GlusterFS3.2.xでは未対応でしたので、NFSロックが必要なアプリケーションを利用する際は、RHS2.0/GlusterFS3.3以降をご使用ください。

※ GlusterFSが稼働するストレージノード自身をNFSクライアントとして使用することはできませんのでご注意下さい。

flock()の動作確認(Nativeマウント編)

flock()は、Linux独自の実装で、Write Lock(Exclusive Lock)/Read Lock(Shared Lock)があって、さらにファイル以外にディレクトリにもロックが取得できます。

次のシェルスクリプトで、いろいろな組み合わせをテストしてみます。簡単のためにLinuxのflockコマンドを使用しています。

flocktest.sh

#!/bin/sh

NODE_A=node01
NODE_B=node02

function linuxlock {
	node=$1
	opt=$2
	lockfile=$3
	echo $node ": Trying to take an $opt lock on " $lockfile

	ssh $node "flock $opt $lockfile -c \" 
		echo -n $node \\\": Succeeded at \\\"; date +%T;
		sleep 10;
       		echo -n $node \\\": Releasing the lock at \\\"; date +%T;
	\""
}

echo "=== Write-Write file lock test."
linuxlock $NODE_A -x /mnt/dir01/file01 &
sleep 1
linuxlock $NODE_B -x /mnt/dir01/file01 &
wait
 
echo "=== Write-Read file lock test."
linuxlock $NODE_A -x /mnt/dir01/file01 &
sleep 1
linuxlock $NODE_B -s /mnt/dir01/file01 &
wait
 
echo "=== Read-Write file lock test."
linuxlock $NODE_A -s /mnt/dir01/file01 &
sleep 1
linuxlock $NODE_B -x /mnt/dir01/file01 &
wait
 
echo "=== Read-Read file lock test."
linuxlock $NODE_A -s /mnt/dir01/file01 &
sleep 1
linuxlock $NODE_B -s /mnt/dir01/file01 &
wait
 
echo "=== Write-Write dir lock test."
linuxlock $NODE_A -x /mnt/dir01 &
sleep 1
linuxlock $NODE_B -x /mnt/dir01 &
wait
 
echo "=== Write-Read dir lock test."
linuxlock $NODE_A -x /mnt/dir01 &
sleep 1
linuxlock $NODE_B -s /mnt/dir01 &
wait
 
echo "=== Read-Write dir lock test."
linuxlock $NODE_A -s /mnt/dir01 &
sleep 1
linuxlock $NODE_B -x /mnt/dir01 &
wait
 
echo "=== Read-Read dir lock test."
linuxlock $NODE_A -s /mnt/dir01 &
sleep 1
linuxlock $NODE_B -s /mnt/dir01 &
wait

各ノードの/mntにボリュームをNatvieマウントして、ファイル「/mnt/dir01/file01」を作成しておきます。

# ssh node01 mount | grep mnt
rhs20-01:/vol01 on /mnt type fuse.glusterfs (rw,default_permissions,allow_other,max_read=131072)
# ssh node02 mount | grep mnt
rhs20-01:/vol01 on /mnt type fuse.glusterfs (rw,default_permissions,allow_other,max_read=131072)

この状態で上記のシェルを実行します。

# ./flocktest.sh 
=== Write-Write file lock test.
node01 : Trying to take a -x lock on  /mnt/dir01/file01
node01 : Succeeded at 01:11:26
node02 : Trying to take a -x lock on  /mnt/dir01/file01
node01 : Releasing the lock at 01:11:36
node02 : Succeeded at 01:11:37
node02 : Releasing the lock at 01:11:47
=== Write-Read file lock test.
node01 : Trying to take a -x lock on  /mnt/dir01/file01
node01 : Succeeded at 01:11:46
node02 : Trying to take a -s lock on  /mnt/dir01/file01
node01 : Releasing the lock at 01:11:56
node02 : Succeeded at 01:11:57
node02 : Releasing the lock at 01:12:07
=== Read-Write file lock test.
node01 : Trying to take a -s lock on  /mnt/dir01/file01
node01 : Succeeded at 01:12:06
node02 : Trying to take a -x lock on  /mnt/dir01/file01
node01 : Releasing the lock at 01:12:16
node02 : Succeeded at 01:12:17
node02 : Releasing the lock at 01:12:27
=== Read-Read file lock test.
node01 : Trying to take a -s lock on  /mnt/dir01/file01
node01 : Succeeded at 01:12:26
node02 : Trying to take a -s lock on  /mnt/dir01/file01
node02 : Succeeded at 01:12:28
node01 : Releasing the lock at 01:12:36
node02 : Releasing the lock at 01:12:38
=== Write-Write dir lock test.
node01 : Trying to take a -x lock on  /mnt/dir01
node01 : Succeeded at 01:12:37
node02 : Trying to take a -x lock on  /mnt/dir01
node02 : Succeeded at 01:12:39
node01 : Releasing the lock at 01:12:47
node02 : Releasing the lock at 01:12:49
=== Write-Read dir lock test.
node01 : Trying to take a -x lock on  /mnt/dir01
node01 : Succeeded at 01:12:49
node02 : Trying to take a -s lock on  /mnt/dir01
node02 : Succeeded at 01:12:50
node01 : Releasing the lock at 01:12:59
node02 : Releasing the lock at 01:13:00
=== Read-Write dir lock test.
node01 : Trying to take a -s lock on  /mnt/dir01
node01 : Succeeded at 01:13:00
node02 : Trying to take a -x lock on  /mnt/dir01
node02 : Succeeded at 01:13:02
node01 : Releasing the lock at 01:13:10
node02 : Releasing the lock at 01:13:12
=== Read-Read dir lock test.
node01 : Trying to take a -s lock on  /mnt/dir01
node01 : Succeeded at 01:13:11
node02 : Trying to take a -s lock on  /mnt/dir01
node02 : Succeeded at 01:13:13
node01 : Releasing the lock at 01:13:21
node02 : Releasing the lock at 01:13:23

地味ですが、すべて期待通りの結果です。Read-Readのロックは同時に取得できる点に注意してください。

flock()の動作確認(NFSマウント編)

先と同じことを/mntにボリュームをNFSマウントした状態で行います。

# ssh node01 mount | grep mnt
rhs20-01:/vol01 on /mnt type nfs (rw,vers=3,addr=192.168.122.21)
# ssh node02 mount | grep mnt
rhs20-01:/vol01 on /mnt type nfs (rw,vers=3,addr=192.168.122.21)

この例ではマウント先のGlusterFSサーバは同一ですが、同じクラスタ内の異なるサーバを指定してNFSマウントした場合でも、NFS Lockは機能します。

# ./flocktest.sh 
=== Write-Write file lock test.
node01 : Trying to take a -x lock on  /mnt/dir01/file01
node01 : Succeeded at 01:15:35
node02 : Trying to take a -x lock on  /mnt/dir01/file01
node01 : Releasing the lock at 01:15:45
node02 : Succeeded at 01:15:46
node02 : Releasing the lock at 01:15:56
=== Write-Read file lock test.
node01 : Trying to take a -x lock on  /mnt/dir01/file01
node01 : Succeeded at 01:15:55
node02 : Trying to take a -s lock on  /mnt/dir01/file01
node01 : Releasing the lock at 01:16:05
node02 : Succeeded at 01:16:06
node02 : Releasing the lock at 01:16:16
=== Read-Write file lock test.
node01 : Trying to take a -s lock on  /mnt/dir01/file01
node01 : Succeeded at 01:16:15
node02 : Trying to take a -x lock on  /mnt/dir01/file01
node01 : Releasing the lock at 01:16:25
node02 : Succeeded at 01:16:26
node02 : Releasing the lock at 01:16:36
=== Read-Read file lock test.
node01 : Trying to take a -s lock on  /mnt/dir01/file01
node01 : Succeeded at 01:16:35
node02 : Trying to take a -s lock on  /mnt/dir01/file01
node02 : Succeeded at 01:16:37
node01 : Releasing the lock at 01:16:45
node02 : Releasing the lock at 01:16:47
=== Write-Write dir lock test.
node01 : Trying to take a -x lock on  /mnt/dir01
node01 : Succeeded at 01:16:46
node02 : Trying to take a -x lock on  /mnt/dir01
node02 : Succeeded at 01:16:48
node01 : Releasing the lock at 01:16:56
node02 : Releasing the lock at 01:16:58
=== Write-Read dir lock test.
node01 : Trying to take a -x lock on  /mnt/dir01
node01 : Succeeded at 01:16:57
node02 : Trying to take a -s lock on  /mnt/dir01
node02 : Succeeded at 01:16:59
node01 : Releasing the lock at 01:17:07
node02 : Releasing the lock at 01:17:09
=== Read-Write dir lock test.
node01 : Trying to take a -s lock on  /mnt/dir01
node01 : Succeeded at 01:17:09
node02 : Trying to take a -x lock on  /mnt/dir01
node02 : Succeeded at 01:17:10
node01 : Releasing the lock at 01:17:19
node02 : Releasing the lock at 01:17:20
=== Read-Read dir lock test.
node01 : Trying to take a -s lock on  /mnt/dir01
node01 : Succeeded at 01:17:20
node02 : Trying to take a -s lock on  /mnt/dir01
node02 : Succeeded at 01:17:22
node01 : Releasing the lock at 01:17:30
node02 : Releasing the lock at 01:17:32

NFSの場合は、ディレクトリに対するロックは取得できないので注意してください。

※結果は記載しませんが、面白いことに、一方がNativeマウントで、一方がNFSマウントの場合でもファイルに対しては、分散flock()が機能しました。

lockf()の動作確認

続いて、POSIXロックの確認です。POSIXロックは、Writeロック(Exclusiveロック)のみで、ディレクトリに対しては取得できないので、テストケースは1つですみます。

・・・と、ここで、POSIXロックを取得するlockfコマンドは、Linuxにも無いことに気づきました。Cのlockf()システムコールで一からテストを書くのも悔しいので、flockコマンドのソースをQuick Hackして、lockfコマンドを用意しました。

ここで見つけたflock.cに下記の修正を加えて、コンパイルして、lockfコマンドを作ります。

# diff -uprN flock.c lockf.c
--- flock.c	2012-04-19 07:41:34.000000000 +0900
+++ lockf.c	2012-04-19 07:56:19.000000000 +0900
@@ -205,7 +205,7 @@ int main(int argc, char *argv[])
     }
 
     filename = argv[optind];
-    fd = open(filename, O_RDONLY|O_NOCTTY|O_CREAT, 0666);
+    fd = open(filename, O_RDWR|O_NOCTTY|O_CREAT, 0666);
     /* Linux doesn't like O_CREAT on a directory, even though it should be a
        no-op */
     if (fd < 0 && errno == EISDIR)
@@ -257,7 +257,7 @@ int main(int argc, char *argv[])
     }
   }
 
-  while ( flock(fd, type|block) ) {
+  while ( lockf(fd, F_LOCK, 0) ) {
     switch( (err = errno) ) {
     case EWOULDBLOCK:		/* -n option set and failed to lock */
       exit(1);

できたものを/root/work/lockfにおいて、次のスクリプトでテストします。

lockftest.sh

#!/bin/sh

NODE_A=node01
NODE_B=node02

function posixlock {
	node=$1
	opt=$2
	lockfile=$3
	echo $node ": Trying to take an $opt lock on " $lockfile

	ssh $node "/root/work/lockf $opt $lockfile -c \" 
		echo -n $node \\\": Succeeded at \\\"; date +%T;
		sleep 10;
       		echo -n $node \\\": Releasing the lock at \\\"; date +%T;
	\""
}

echo "=== Write-Write file lock test."
posixlock $NODE_A -x /mnt/dir01/file01 &
sleep 1
posixlock $NODE_B -x /mnt/dir01/file01 &
wait

ここでは、代表的な結果のみを記載しますが、Nativeマウント同士、NFSマウント同士、NativeマウントとNFSマウントの組み合わせ、すべて同じ結果です。

# ./lockftest.sh 
=== Write-Write file lock test.
node01 : Trying to take an -x lock on  /mnt/dir01/file01
node01 : Succeeded at 01:33:28
node02 : Trying to take an -x lock on  /mnt/dir01/file01
node01 : Releasing the lock at 01:33:38
node02 : Succeeded at 01:33:39
node02 : Releasing the lock at 01:33:49