分散ファイルシステム glusterfs を試してみた
- http://www.gluster.org/download/
- http://www.gluster.org/wp-content/uploads/2012/05/Gluster_File_System-3.3.0-Administration_Guide-en-US.pdf
レッドハットに買収されたとかで、RHEVやovirtとも絡んできそうなので試してみた。実験用に仮想化環境で動かしたので真面目にパフォーマンスは調べてないけど、簡単に設定できる割にちゃんと動くので良い感じだと思いました。
drbdと適当に比較すると、drbdは2台のサーバでのnetwork raid1 で基本的にprimary側のサーバでしかmountできないのに対して、glusterfs は複数台のサーバでのnetwork raid(volume次第でraid0 , raid1, raid10, raid5 or 6 のような冗長性有り) で、複数のサーバからmount可能 (fuseを使ったglusterfs native client, nfs , cifs)。
defaultはtcpで、rdmaライブラリをインストールして、オプションを指定すればインフィニバンドも使用可能。
以下、用語は間違っている可能性あり。
install
サーバはCentOS6.3を使ったけど、RHEL系6.1以上だったらたぶん何でもいい。
公式からrpm取ってきてinstall。
# yum -y install fuse fuse-libs # rpm -ivh ./glusterfs-3.3.0-1.el6.x86_64.rpm ./glusterfs-server-3.3.0-1.el6.x86_64.rpm \ ./glusterfs-fuse-3.3.0-1.el6.x86_64.rpm \ ./glusterfs-geo-replication-3.3.0-1.el6.x86_64.rpm
peer
- 追加
host sv01 で実行するとする。
# gluster peer probe sv02 # gluster peer probe sv03
外すときはprobeの代わりにdetachで。
- 確認
# gluster peer info
仮想化などでサーバをclone する際の注意
glusterd を起動すると/var/lib/glusterd にlocalhostやpeerのUUID等が保存されるので、glusterd install後にclone すると、UUIDが重複してpeer statusがおかしくなる。その場合は、一旦/var/lib/glusterd を削除した後、再度glusterd を起動すると良い。
volume
sv01 ~ sv03 の3台のbrickで3つのvolume 作ってみるテスト
vol1 | destributed (default) |
vol2 | replicated |
vol3 | stripted |
- volume 作成
# gluster volume create vol1 sv01:/vol/vol1 sv02:/vol/vol1 sv03:/vol/vol1 # gluster volume info
- volume 削除
# gluster volume delete vol1
- volume 起動
作成しただけではmountできないのでstartする。
# gluster volume start vol1
distributed volume
raid0 like?(ちょっと違う) ファイルごとに複数のサーバに分けて分散する。とあるサーバが死ぬと、そのサーバに配置したファイルにはアクセスできなくなるが、他のサーバ上にあるファイルにはアクセス可能。
gluster voluem create でオプションを指定しない場合、distributed volumeになる。
# gluster volume create vol1 sv01:/vol/vol1 sv02:/vol/vol1 sv03:/vol/vol1 # gluster volume info vol1 Volume Name: vol1 Type: Distribute Volume ID: 47f9d050-fb59-44cf-8fd2-166593598cd7 Status: Started Number of Bricks: 3 Transport-type: tcp Bricks: Brick1: sv01:/vol/vol1 Brick2: sv02:/vol/vol1 Brick3: sv03:/vol/vol1
replicated volume
raid1 like? ファイルを複数のサーバに複製する。create volume-name replica N のようにreplica keywordとレプリカの数を指定する。
# gluster volume create vol2 replica 3 sv01:/vol/vol2 sv02:/vol/vol2 sv03:/vol/vol2 # gluster volume info vol2 Volume Name: vol2 Type: Replicate Volume ID: ca0b4c10-c440-4413-8a39-dc89fc7ff5fa Status: Started Number of Bricks: 1 x 3 = 3 Transport-type: tcp Bricks: Brick1: sv01:/vol/vol2 Brick2: sv02:/vol/vol2 Brick3: sv03:/vol/vol2
striped
raid0 like ? ファイルを細切れに分割して複数のサーバに配置する。(扱うファイル次第では)他のモードと比較して最も高速になるけど、どれか1つのサーバが死ぬと全てのファイルにアクセスできなくなる。
# gluster volume create vol3 strip 3 sv01:/vol/vol3 sv02:/vol/vol3 sv03:/vol/vol3 # gluster volume info vol3 Volume Name: vol3 Type: Stripe Volume ID: ffd67330-270e-4529-8090-46e81e4f46f9 Status: Started Number of Bricks: 1 x 3 = 3 Transport-type: tcp Bricks: Brick1: sv01:/vol/vol3 Brick2: sv02:/vol/vol3 Brick3: sv03:/vol/vol3
mount
mountする前にgluster volume start volume_name しておくのを忘れずに。
Glustefs Native Client
FUSEが必要なのでなければインストールして有効にしておく。
# yum -y install fuse fuse-libs # modprobe fuse # dmesg | grep -i fuse # modinfo fuse
native clientからのアクセスの場合、見た目のmountは mount sv01:/vol1 のように1サーバしか指定しないが、どのファイルがどこにあるか(ファイル名のハッシュ値で計算)を知っているので、直接sv02, sv03などのサーバにもアクセスする。
- mount
fstabに追記(or mountコマンドでもいいけど)。
mount pointのpathはvolumeへのfullpath ではなくて、volume名なことに注意。この例だとgluster volume create vol1 sv01:/vol/vol1 .... で作成したので、sv01:/vol/vol1 ではなく、sv01:/vol1 が正解。
document にはdefaults,_netdev と書いてあったけど、unknown option と言われて警告出たので_netdevは外した。
sv01:/vol1 /mnt/vol1 glusterfs defaults 0 0 sv01:/vol2 /mnt/vol2 glusterfs defaults 0 0 sv01:/vol3 /mnt/vol3 glusterfs defaults 0 0
# mount -a # df -h -t fuse.glusterfs Filesystem Size Used Avail Use% マウント位置 sv01:/vol1 80G 6.7G 69G 9% /mnt/vol1 sv01:/vol2 27G 2.3G 23G 9% /mnt/vol2 sv01:/vol3 80G 6.7G 69G 9% /mnt/vol3
vol2 はreplica 3 で作成したため、他のvolumeの1/3の容量になってるのもわかる。
- mountコマンド
# gluster volume start vol1 # mount -t glusterfs sv01:/volume-name /mnt/vol1
NFS
なんと。defaultのままでNFSでもアクセスできるようだ。すごいね。fstabには普通にNFS利用するときの内容を記述する。
ただ、NFSの場合、clientはsv01にしかアクセスしないので、ファイルがその他のbrickにある場合、sv01がproxyのように動作する。(のでnative clientより遅いはず)
sv01:/vol1 /mnt/vol1 nfs defaults,vers=3 0 0
CIFS
CIFSでもmountできるようだけど試してない。
volume typeの組み合わせ
ここからが本番。上で説明したように、
- distributed の特定ノードで障害が発生した場合、clientからのマウント自体は正常に行えているまま、そのノード上に配置されているファイルが見えなくなる
- striped のノードで障害が発生した場合、マウント自体にエラーが発生して全てのファイルへアクセス出来なくなる
- distributed と striped はファイルを配置するサーバを分散させるため高速になるけど冗長性がなくなる
- replicated は冗長性はあるけど全サーバへ複製をしているだけなので速くならない(read は速くなる?)
ということで実際に利用する場合、これらを組み合わせたvolumeを作成すると幸せになれる。
raid10 のようなことをするわけですね。
Distributed Replicated であれば、ファイルごとに複数のサーバに複製する。この場合、ノード(bricks)の数はreplicaの整数倍にする必要がある。
Striped Replicated Volumes であれば、ファイルをstriped して複数のサーバに分散して配置したものを複製する。
Distributed Replicated
# gluster volume create dist-replica-volume replica 2 sv01:/vol1 sv02:/vol1 sv03:/vol1 sv04:/vol1 Creation of volume dist-replica-volume has been successful. Please start the volume to access data. # gluster volume start dist-replica-volume Starting volume dist-replica-volume has been successful # gluster volume info Volume Name: dist-replica-volume Type: Distributed-Replicate Volume ID: ca98e18a-4890-449d-98aa-038e1ed7ecff Status: Started Number of Bricks: 2 x 2 = 4 Transport-type: tcp Bricks: Brick1: sv01:/vol1 Brick2: sv02:/vol1 Brick3: sv03:/vol1 Brick4: sv04:/vol1
mount
# mount -t glusterfs server:/dist-replica-volume /mnt/vol1
試しに10Mのファイルを10個作ってみる。
# for i in {00..09}; do dd if=/dev/zero of=./$i.dat bs=1M count=10; done # ls -lsh 合計 101M 11M -rw-r--r-- 1 root root 10M 9月 3 22:28 2012 00.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:28 2012 01.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:28 2012 02.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:28 2012 03.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:28 2012 04.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:28 2012 05.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:28 2012 06.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:28 2012 07.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:28 2012 08.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:28 2012 09.dat
各サーバのvolumeのディレクトリ見てみる。sv01 と sv02、sv03とsv04 でreplicatedされていて、 それぞれにファイルが分散しているのがわかる。また左端の実際のファイルサイズ(ls -s) も10Mになっているのがわかる。
$ for i in {01..04}; do ssh root@sv$i 'hostname && ls -lsh /vol1' ; done sv01 合計 41M 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 00.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 05.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 08.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 09.dat sv02 合計 41M 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 00.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 05.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 08.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 09.dat sv03 合計 61M 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 01.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 02.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 03.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 04.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 06.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 07.dat sv04 合計 61M 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 01.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 02.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 03.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 04.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 06.dat 11M -rw-r--r-- 2 root root 10M 9月 3 22:28 2012 07.dat
Striped Replicated
# gluster volume create striped-replica-volume \ stripe 2 replica 2 sv01:/vol2 sv02:/vol2 sv03:/vol2 sv04:/vol2 Creation of volume striped-replica-volume has been successful. Please start the volume to access data. # gluster volume start striped-replica-volume Starting volume striped-replica-volume has been successful # gluster volume info striped-replica-volume Volume Name: striped-replica-volume Type: Striped-Replicate Volume ID: 76b46b15-d801-4e93-916a-b0df840af7bf Status: Started Number of Bricks: 1 x 2 x 2 = 4 Transport-type: tcp Bricks: Brick1: sv01:/vol2 Brick2: sv02:/vol2 Brick3: sv03:/vol2 Brick4: sv04:/vol2
mount
先ほどと同様に、mountして10個のファイル作ってみる。
# mount -t glusterfs server:/striped-replica-volume /mnt/vol2 # cd /mnt/vol2 # for i in {00..09}; do dd if=/dev/zero of=./$i.dat bs=1M count=10; done # ls -lsh 合計 101M 11M -rw-r--r-- 1 root root 10M 9月 3 22:38 2012 00.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:38 2012 01.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:38 2012 02.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:38 2012 03.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:38 2012 04.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:38 2012 05.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:38 2012 06.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:38 2012 07.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:38 2012 08.dat 11M -rw-r--r-- 1 root root 10M 9月 3 22:38 2012 09.dat
各サーバのvolumeのディレクトリ見てみる。striped モードなので、全サーバにファイルが配置されていて、かつ実際に割り当てられている左端のサイズは半分の5Mになっているのもわかる。
$ for i in {01..04}; do ssh root@sv$i 'hostname && ls -lsh /vol2' ; done sv01 合計 51M 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 00.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 01.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 02.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 03.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 04.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 05.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 06.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 07.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 08.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 09.dat sv02 合計 51M 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 00.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 01.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 02.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 03.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 04.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 05.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 06.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 07.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 08.dat 5.1M -rw-r--r-- 2 root root 9.9M 9月 3 22:38 2012 09.dat sv03 合計 51M 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 00.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 01.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 02.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 03.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 04.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 05.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 06.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 07.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 08.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 09.dat sv04 合計 51M 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 00.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 01.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 02.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 03.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 04.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 05.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 06.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 07.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 08.dat 5.1M -rw-r--r-- 2 root root 10M 9月 3 22:38 2012 09.dat
Distributed Striped Replicated Volume
8台のサーバ(2 * 2 * 2 ) にするのでgluster peer probe でsv01 ~ sv08まで追加しておく。
# gluster volume create dist-striped-replica-volume stripe 2 replica 2 \ sv01:/vol3 sv02:/vol3 sv03:/vol3 sv04:/vol3 \ sv05:/vol3 sv06:/vol3 sv07:/vol3 sv08:/vol3 Creation of volume dist-striped-replica-volume has been successful. Please start the volume to access data. # gluster volume start dist-striped-replica-volume Starting volume dist-striped-replica-volume has been successful # gluster volume info dist-striped-replica-volume Volume Name: dist-striped-replica-volume Type: Distributed-Striped-Replicate Volume ID: 8aa1c1da-3d5c-49d3-b045-ba15a7b2f01f Status: Started Number of Bricks: 2 x 2 x 2 = 8 Transport-type: tcp Bricks: Brick1: sv01:/vol3 Brick2: sv02:/vol3 Brick3: sv03:/vol3 Brick4: sv04:/vol3 Brick5: sv05:/vol3 Brick6: sv06:/vol3 Brick7: sv07:/vol3 Brick8: sv08:/vol3
コマンド出力結果は省略。
今までと同様に01~09の10個のファイルを作成して、各サーバの/vol3 の中を見ると、
- まずファイルごとにグループがわかれていて(distributed)
- かつ、ファイルサイズは半分になってて(striped)
- 同じファイルが複製されている(replicated)
- sv01 ~ sv04
- 00.dat 05.dat 08.dat 09.dat
- sv05 ~ sv08
- 01.dat 02.dat 03.dat 04.dat 06.dat 07.dat
補足
ddで空のファイルを作ったから本当にstripedされているのかわからないけど、中身のあるデータを作ってみると、ファイルが細切れになって別々のサーバに分散されてるのがわかる。ファイルサイズ、md5sum値などを調べること。
brick (サーバ) の追加
# gluster volume add-brick volume_name new_brick
ファイルの再配置について (rebalance)
新規に追加されたサーバは既存のファイル情報を持っていないため、add-brick以前に作成されたファイルについては既存のサーバ群だけで処理することになる。(add-brick以後に作成されるファイルは、追加されたサーバを含めてハッシュで分散されて保存されるので何もしなくて良い)
手動で再配置を行う場合は、gluster volume rebalance volume_name start を実行する。
# gluster volume rebalance vol1 start # gluster volume rebalance vol1 status # gluster volume rebalance vol1 status Node Rebalanced-files size scanned failures status --------- ----------- ----------- ----------- ----------- ------------ localhost 8 1.4GB 25 0 in progress sv02 0 0Bytes 93 0 completed # gluster volume rebalance vol1 status Node Rebalanced-files size scanned failures status --------- ----------- ----------- ----------- ----------- ------------ localhost 42 7.0GB 135 0 completed sv02 0 0Bytes 93 0 completed
その他
- geo replication
- quota
- profile
# gluster volume profile vol1 start # gluster volume profile vol1 info
- status
# gluster volume status vol1 # gluster volume status vol1 detail
サーバ障害時のmount failover
データについてはreplicaを組み合わせればいいけど、特定のサーバが死んだ場合にそれをmountしているclientは接続が切れてしまう。どうしましょう。
対策
- localhostをmountするのでサーバ障害は気にしない
- keepalive, heartbeat などで仮想IPを設定して、そこをmountしておく
- myDNS などを使って、名前でmountしておき、サーバが死んだらDNS Aレコードを変更する
localhostをmount
恐らくovirtがそのうちこういう構成になりそうだけど、特別なストレージを利用せず、仮想化ホストサーバ上でglusterfs を利用して仮想イメージ置き場を作る場合、gusterd == glusterfs client になる。この場合はlocalhostのglusterdをmountするようにすれば、そもそも障害を気にしなくていい。(glusterdが死ぬ==自分も死んでる)
補足: ここではglusterd プロセス障害は考えてない
keepalivedの実験
実際keepalived を使ってvipをmountするようにしてみた。まずサーバ障害時にvip はすぐ引き継がれる(keepalivedのvrrpが早い)。icmp ロス1秒程度で。
その後、clientからmountしているデータにアクセスできるのには30秒程度の時間が必要だった。
おまけ : keepavlived.conf
! Configuration File for keepalived global_defs { notification_email { root@localhost } notification_email_from from@example.com smtp_server localhost smtp_connect_timeout 30 router_id sv02 } vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 110 priority 100 advert_int 1 nopreempt authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.122.110/24 dev eth0 } }