読者です 読者をやめる 読者になる 読者になる

Roma、Fairyについてひとことふたこと

大規模分散処理向けの国産“ウェブOS”をRubyで開発中 - @ITより。

これはマズイことになった。WikiFormeを作っている内に、VIVER構想の一部が先に実現されてしまいそうだ。


以下、私はこのカンファレンスに行ってもいませんし、とっても浅薄な頭で書いてますので、あまり信用してはいけません。


まずRomaについて。

Romaは、メモリ上にデータを保持した多数のマシンを組み合わせることで、高速で信頼性が高いストレージを実現することを狙う。具体的には、巨大なオンメモリのハッシュ・テーブルをネットワーク上に分散した多数のサーバ上に構築する。P2P(peer-to-peer)ネットワークのルーティング技術として注目されている分散ハッシュ・テーブル(DHT)と似た動作モデルに基づくという。

どうやら、私が作ろうとしていて全然できてない分散ファイルシステムの考えと少し近い。
オンメモリということだから、分散ファイルシステムと言うよりは、分散高可用memchachedと言えるのだろうか。ストレージ容量はそれほど大きくならない。


DHTと似た動作モデルに基づくというところについて、分散ストレージを作ろうとすればDHTに行き着くのは自然だと思う。信頼性の高い「配列」を提供されても使いにくくて困るので、信頼性の高い「マップ」を作ろうとしているに違いない。マップを実装するのにハッシュを使うことには不思議はない。

しかしDHTは「検索」の技術で、多数のノードに散らばったデータをどうやって探し出すかという技術(探し出したノードが実は落ちていた時にどうするか、というところまで含んでいたりもする)。しかし実際に重要なのは、「どうやってデータを多数のノードに散らばらせるか」にあると思う。


インターネットレベルで使われるP2Pファイル共有ソフトだと、

  • ファイルの共有を開始したノードが、最初に必ずファイルを持っている
  • 各ノードの記憶容量はたぶん大きい
  • ファイルが無くなっても許容できる
  • ファイルを見つけるのに時間がかかってもいい

という前提があるので、データの分散でがんばらなくても何とかなる。それよりも、広大なネットの中からどこぞの誰かが作った特定のデータを探し出さないといけないので、検索技術の方が重要になる。


LANで使うオンメモリの分散ストレージになると、まったく事情が異なる。

  • 最初にデータを作ったノードがデータを保持できるとは限らない
    • クライアントはデータを投げるだけで、データ保持するのはサーバー群の方だったり
  • 各ノードの記憶容量は小さい
  • データが無くなったら困る
  • データを見つけるのに時間がかかるとパフォーマンスがガタ落ちする
    • オンメモリ => 一つ一つのデータの大きさは小さい => スループットより遅延の方が重要

こうなると、検索技術の方はおのずとやり方が決まってくるはず。


まず、1ホップ(データを持っているノードにアクセス)か2ホップ(データを持っているノードを知っているノードにアクセス)くらいでファイルにアクセスできないと、パフォーマンス的に困る。これを実現するには、誰がどのデータを持っているかをある程度詳しく知っていないといけない。となると、データを作ったら他のノードに「このデータを持っているのはアイツだよ」と知らせてあげないと厳しい。あるいは、データを探すたびに「このデータを持っているノードは誰ですか」とブロードキャストするくらいしか方法が無い(無いと言うか、私は思いつかない)。
ブロードキャストするのは信頼性的にもスケーラビリティ的にも良くないので、前者の方法を採ると思う。そうなれば誰がどのデータを持っているかある程度詳しく知っているのだから、目的のデータを探し出す方法は自然に決まってくるハズ。


問題はデータの散らばらせ方にある。これは間違いない。
個々のデータのサイズがある程度均一で、個々のデータに対するアクセスがある程度均一で、ノードの数よりデータの数の方がずっと多いなら、「ランダムにばらまく」で均等に分散(容量と負荷の分散)ができる。具体的な実装に踏み込めば、データのキー名をハッシュ関数に掛けて、ハッシュ結果に一番近いIDを持つノードと、その次のノードにデータを持たせればいい。3重化するなら、そのまた次のノードにも持たせる。実際、この方法を使うのではないかと思う。

ただしこの方法だと、一つのデータがどんどん大きくなっていくと、あるノードは空き容量がたくさんあるのに、あるノードだけが容量不足になってしまったりする。それに加えてその大きなデータへのアクセスが集中すると、特定のノードにだけアクセスが集中してしまう。そこのところはどうするのだろうか。各ノードの負荷に応じてデータの移動させたりするのだろうか。
予想としては、データのサイズもアクセスも均一で、ノードの数よりデータの数の方がずっと多いことを前提として(と言うか、それが前提とできる環境で使うためのシステムを作る)、最適化は実装しないという方向だと思うが、どうだろう。ぜひオープンに開発していただきたい限りである。




分散ストレージに関して、もう一つ思うところがある。トランザクションはどうするのだろう。
2つの互いに関連性を持ったデータを書き込もうとして、片方を書き込んだ段階で読み込みが発生したりする。このときに、両方の書き込みが終わるまで読み込みを待たせたり、両方とも書き終わるまではどちらも書き込んでいないデータを読み込ませたりしたい。分散環境だと複数のノードが同じデータを持っていたりするから、どのノードから読み込んでも同じデータが読み出せるようにしたい。これを可能にするのか否か。
これを可能にしようとする(トランザクションを実装する)と、書き込みや読み込みがとても遅くなる。書き込みが遅くなるなら許せるかもしれないが、読み込みも「今読み込んじゃってもOKですか?」と聞かないといけなかったりして、やっぱり遅くなる。トランザクションができなくても良いなら、ずっと速くできる。


それから、分散したデータでトランザクションするのは、実装が難しいらしい(私はやらない…)
Romaはトランザクションを実装するのだろうか。勝手な予想としては、単一のデータが中途半端に読み込まれることはないけど、複数のデータ間の整合性は保証しないよということで、トランザクションは実装しないと思う。テータの分散方法と合わせて要注目。





もう一つのFairyについて。

一方のFairyは並列処理向けの技術で、MapReduce(注:グーグルが分散処理の基盤技術として利用することで知られる並列処理向けアルゴリズム)のRuby実装として検討を始めたもの。大規模並列処理の負荷分散への適用を狙う。

ぶっちゃけMapReduceの実装にもっとも必要なのは分散ストレージだと思う。Romaが無いとFairyは作れないし、RomaがあればFairyが作れる!ということではなかろうか。

その前に、分散システムを作ろうとすると必ず分散ストレージが必要で、その分散ストレージが、誰でも使いやすい分散ストレージが無かったから、みんな(かどうかは知らないが私は)困っているのである。(そこのところを分散ストレージの代わりに高度なメッセージングで実現してしまうかもしれないErlangはちょっと感動したりもする)


Fairyはパフォーマンスやアルゴリズムよりも、Romaとの連携や使いやすさの方が気になる。Fairyでデータを処理する = Romaにデータを保存する というのはほぼ間違いないと思うので、そこのところをどう使えるようにしてくれるのだろう。Romaオブジェクトに対して map{|data| hogehoge}.reduce{|hash| fugafuga} なんてできたら嬉しい。
Romaをセットアップすると、FairyはRomaがどのように設定されているかを読み取って、設定無しで自動的に使えるようになったり。
Fairyにジョブを投入する方法は、ローカルにFairyデーモンを立ててプロセス間通信で投げるのか、それともFairyライブラリをリンクするとデーモンを経由せずにRomaを読みに行ったりするのか。Romaに特定の命名規則でデータを保存すると、自動的に処理されてデータが帰ってくるというCoC的なのも面白い。
予想としては、FairyはRubyでしか使えなくて、Fairyライブラリをrequireすると、これまたRubyのRomaクライアントライブラリを使って、分散ストレージに直にアクセする方針だろうと勝手に考えている。




…こんな事を書いている暇があったら分散ファイルシステムを実装すればいいのにな、と。