GlusterFSで分散ファイルシステム

研究室には,8台のクラスタノードと,それらを統括するノードが別に1台あるので,試しにGlusterFSを導入してみた.

クラスタのディスクは,2TBを3台ハードウェアRAID0で繋いで,ReiserFSでフォーマットしてある.OSはUbuntu 11.10 (AMD64)である.

まず,パッケージをインストールする.

# aptitude install glusterfs-server glusterfs-common gluster-client

glusterfs-commonは必須として,serverはGlusterFSの構築に参加するサーバの全てにインストールする必要があり,clientはGlusterFSをマウントする場合にのみ必要.Ubuntu 11.10では,3.2.1がインストールされる.

今回は,統括ノードを設定に用いて,ディスクの実体はクラスタノードに置くように設定した.統括ノードがない場合は,クラスタノードのうちの1台で操作しても良い.設定に用いたノードからマウントすることになる.そのノードを仮にserverAとすると,クライアントからは,# mount.glusterfs serverA:gvol /mnt でマウントすることになる.

ノード名は仮に以下のようにする.

  • 統括ノード:serverA
  • 分散ノード:server01~server08

設定は,以下の手順で行う.

  1. 分散対象となるノードを順番に登録.1台ずつ追加していかないといけないようだ.
    # gluster peer probe server01
    ...
    # gluster peer probe server08
    
  2. 分散ノード全てに,分散FSに使うディレクトリを作る./export/brick0 とする.
  3. ファイルシステムを構築(分散設定はreplica 2で,ボリューム名はgvol0とする)
    # gluster volume create gvol0 replica 2 server01:/export/brick0 ... server08:/export/brick0
    
  4. ファイルシステムをスタート
    # gluster volume start gvol0
    
  5. クライアントでマウント
    # mount.glusterfs serverA:gvol0 /mnt
    

設定は/etc/glusterdに保存されており,各ノードに自動的にコピーされるようだ.後は状態の確認コマンドが重要.

  • 分散対象となるノードの確認
    # gluster peer status
    gluster peer status
    Number of Peers: 8
    
    Hostname: server0
    Uuid: ...
    State: Peer in Cluster (Connected)
    
    Hostname: server1
    ...
    
  • GlusterFSの状態の確認
    # gluster volume info gvol0
    
    Volume Name: gvol0
    Type: Distributed-Replicate
    Status: Started
    Number of Bricks: 4 x 2 = 8
    Transport-type: tcp
    Bricks:
    Brick1: server0:/export/brick0
    Brick2: server1:/export/brick0
    ...
    

分散設定のreplicaは,一つのファイルを何台のサーバに同時に保存するか,という設定.他にstripeがあり,こちらは一つのファイルを複数台のサーバに保存する.replica 2にすると使える容量は半分になるが数台のサーバが壊れても平気,stripeにすると全ての容量が使えるが1台でも壊れると動かない,ということだと思う.

replicaとstripeを同時に使える,distributeなる設定があるという情報もあったが,3.2.1では,stripeかreplicaのどちらか一方だけを使うことができる.

後はパフォーマンスが気になるところだが,それはまた今度.

Pythonのクラス

Pythonでクラスを作っていて、クラス変数が恐ろしいことに気づいた。

例えば、以下のようなクラスを作ってみる。

class Hoge:
    def __init__(self):
        self.a = 1
    def foo(self):
        self.b = 2

これのインスタンスを作ると、aやbの読み書きができるのは理解できる。

>>> hoge = Hoge()
>>> hoge.a
1
>>> hoge.b
AttributeError: Hoge instance has no attribute 'b'
>>> hoge.foo()
>>> hoge.b
2

このあと、hoge.aやhoge.bを書き換えられるのも(ややセキュアではないが)分からなくはない。問題はこの後だ。

>>> hoge.c = 3
>>> hoge.c
3

クラスを定義した時には作っていなかった変数であるcをいとも簡単に追加でき、読み書き可能なのである。「便利じゃん」という意見もあるだろうが、何かしら代入するときに変数名を打ち間違えても(上のコードではbと間違えてcと打った時)、エラーも出さずに進んでしまうという恐怖

さらに問題はこのあとで、

>>> hoge.foo = 4
>>> hoge.foo
4
>>> hoge.foo()
TypeError: 'int' object is not callable

お分かりいただけるだろうか、クラス内で定義されていた関数名と同じ名前の変数を定義でき、あろうことか上書きしてしまった。上書き自由にもほどがある

以上のコードはUbuntu11.10上のPython 2.7.1での動作だが、Python 3系列ではどうなっているのか大変気になる。

ちなみにRubyでは、クラス内の変数にアクセするためにはattr_accessorやattr_readerに登録しなければならないので上記のようなことは起こり得ないし、関数を変数で上書きするなんてこともできない。

追記

Python3.2で試しても同じ結果でした。どういう思想でこうなっているんだろう?