分散ファイルシステムで中間プロトコルに9pを使うアイディア
9pは非常にシンプルで素晴らしい。
LinuxのDocument/filesystems/9p.txtを読むと、マウントオプションにrfdno=nとwfdno=nというのがある。
rfdno=n the file descriptor for reading with proto=fd wfdno=n the file descriptor for writing with proto=fd
proto=というのもある。
proto=name select an alternative transport. Valid options are currently: unix - specifying a named pipe mount point tcp - specifying a normal TCP/IP connection fd - used passed file descriptors for connection (see rfdno and wfdno)
rfdnoとwfdnoを指定すれば、通信につかうファイルディスクリプタは、任意のものが使えるようだ。pipeも使えるはず。
そこで、ローカルで9pサーバーを動かし、そこから他のマシンへと通信を中継することは、それほど難しくないはず。
kernel -> local 9p server -> ネットワーク -> 9p server kernel <- local 9p server <- ネットワーク <- 9p server
これができれば、レプリケーションは簡単にできるはず。書き込みを複製すればいい。読み込みは好きなホストから読み込む。
(実際のところ、サーバーがクライアントの情報を保持するようなプロトコルだと、これはマズイ。そこのところ未調査)
-> 9p server 1 kernel -> local 9p server -> ネットワーク -> 9p server 2 -> 9p server 3 kernel <- local 9p server <- ネットワーク <- 9p server 3
↓こう書いてもいい。
-> node1 node0 -> node2 -> node3 node0 <- node3
これの問題は、複数のノードが同じファイル(またはディレクトリ)に同時に書き込みを行うと、どちらの状態になるか分からないこと。分散トランザクションが必要になってしまう。
分散ロック(DLM)だのという話はここから出てくるのだけど、その実装は限りなくやってられない。おそらく効率(パフォーマンス)も良くない。
そこで、数珠つなぎ型を考える。
node0 -> node1 -> node2 -> node3
書き込みを行う際は、必ず node1 -> node2 -> node3 という順番で書き込まなければならず、前の書き込みを追い抜いてはいけない。これなら分散ロックは要らない。
さらに利点として、数珠つなぎ型の方がスループットが出る。1台->複数台だと、1本の回線の帯域が台数分の1に制限されてしまうが、数珠つなぎ型ならフルに使える。全二重の場合。
逆に、レイテンシは大きくなってしまう。そこはトレードオフ。でも良い買い物だと思う。
しかし数珠つなぎ型にも問題はある。node1とnode2の2台で冗長化にしているときに↓
node1 -> node2
node2がファイルを書き込もうとすると、
node2 -> node1 -> node2
↑こうなってしまう。ムダが多い。
この問題は、書き込む順序が決まっていることに起因する。でもそこは譲れない。書き込む順序を順不同にしてしまうと、同時に書き込まれたときに、状態が不定になる。
この解決案はまだ浮かんでいない。
しかし実際のところは、ファイルサーバーの役割をするノードは、データを書き込むことはあまりないと思われる。それならこのムダは発生しない。
別の問題として、新しいノードが加わるときにどうするか、という問題がある。
第1案として、「新しいノードは必ず数珠の一番後ろにつく」ことにする。たとえばnode2とnode3で冗長化しているときに、node1が加わると、
node2 -> node3 -> node1
になる。
この方式の良い点は、書き込みが行われている真っ最中にノードが追加されたときでも、問題なく追従できる点。書き込みは前の書き込みを追い抜かないので、ノードの追加情報は、それより後の書き込みに追い抜かれることはない。逆にノードの追加情報は、それより前の書き込みを追い抜かない。
つまり、ノードの追加中にデータが変更されることはない。同時にノードが追加されても問題ない。これは素晴らしい。
しかしこの案では、数珠を維持するために、どのノードがどの順番で繋がっているのか、ずっと覚えておかないといけない。各ノードが知らなくてはならない情報が多ければ多いほど、分散システムの実装は難しくなる。
では第2案として、「数珠のノードはIPアドレスの順に繋がる」ことにする。
node1, node2, node3のIPアドレスの大きさが、node1 < node2 < node3だとする。IPアドレスなので、同じになることはない。
そうすると、node2とnode3で冗長化されているときに、node1が加わると、↓このようになる。
node1 -> node2 -> node3
node1はIPアドレスが最小なので、先頭につく。
この方法の良い点は、数珠に繋がっているメンバーだけを覚えていれば済む点。繋がっている順番を覚えておく必要はない。
もし忘れてしまっても、「数珠Aに参加しているノードは返事してくれ!」と聞けばいい。(←実際のところ、信頼性のあるブロードキャストは実現困難なので、これは役に立たない)
なにやら現実味を帯びてきた。
さらに素晴らしいことに、9pを実装するためのライブラリというものが存在する。と言っても実装されていない部分が非常に多いが…。しかしそこは自分で実装したっていいと思う。なんと言ってもカーネルモードじゃないし、プロトコルはとてもシンプル。
そしてクライアント機能はLinuxカーネルに組み込まれていると来ている。そろそろ実装を始めてもいいかもしれない。
…一方で、次期RUNESの案も固まってきている。mDNS+DNS-SDでサービス発見 + dRuby + DIの案。
さぁ、どっちからやるんだ!