著作一覧 |
以前、acmqueueのBASEに関する記事の前半だけを勝手翻訳したが、続きをwinplusさんが翻訳してくれた。
実のところ、2フェーズコミットという技術は早すぎた自動化だと思う。えらく大層なことと複雑な仕組みではあるけれど、さっきまでオンラインだったシステムは直後もオンラインだろうという程度のあやふやな確信に頼って自動化しているだけのものだ。
よく似たシステムに、同時期にでてきたRPC(ORPCもそうだ)がある。
前提が高信頼性が確保できるクリーンルーム内の複数のノードから構成された分散システムだとしか思えない。それにしてもマシンは落ちるしネットワークは切れる。2フェーズコミットは、絶対に通信が可能だということと相手のプロセス(マシン)が落ちないことを前提としたシステムだという矛盾がある。SYNに対するACKを2時間待ってしまえばすでに成り立たないのだ。
早すぎた自動化は、妄想のシステムを生む。その幻想のインフラの上に大伽藍を建ててしまえば、実運用が始まってそれが文字通り砂上の楼閣と知って、ときどき水を掻き出す羽目に陥ることになる。それに対してはきちんとシンプルな手作りシステムを対峙させる必要がある。そのようなシンプルな手作り石鹸がいつのまにかご大層なWS-*になってしまうこともあるわけだが。
より固く分散させるのであれば、データを手元にコミットして、分散の相手がこちらに来る(ポールする)方法を取れば良い。相手にキューするためにデータを持って飛んでいけば相手が死んでいるときに厄介なことになる。それよりは同じマシン内にコミットしておけば、まだ直接の対話の相手(DBMSになる)が死んでいる可能性は少ない。そうやって少ない機能でシンプルな仕組みを作る代わりにインフラによる複雑な自動化を利用しようとすることが結果的には災厄を招く。
確かにポール(プル)はオーバーヘッドで、プッシュのほうが良いと考えていたことはあるのだが、また、実際ポールのオーバーヘッドはかってはばかにならなかった。しかし今となってはそうではない。それにプッシュとプルの併用という手もある。コミットしたら通知する。通知の成否は問う必要はない。通知を受けたらプルしに来る。プルしたときにまだデータが残っていればマークを真にし、残っていなければ偽にする。プル側はプロセスの起動時に必ずポールする。コミットする側はマークが偽の時のみ通知する。仮にプル側がマークを真にしたまま死んだとしても放置でよい。なぜならばプル側が復活すればポールから始めるからだ。
考えてみれば単純な話なのだが、どうも、メッセージの伝播は、下位ノードから上位ノードへ進み、それはクライアントから中間サーバ、中間サーバからより上位のサーバ、という道筋で、かつ、通信を受けるために口をあけておくのはサーバの役割という固定観念に捕らわれていたようだ。そんなものは無視して、口を開けておくのは下位ノードとしておけば、すべて恙無くメッセージの伝播が可能だったのだな。
そういえば、クラウドの技術が届いたのでぱらぱら眺めたり読んだりした。その中で首藤さんの『スケールアウトの技術』が扱っているドメインがおれには一番おもしろかった(直近で具体的な製品を利用する必要がないからだろう)。
あるいは、CAPのPのパーティションって、まさにOracleのパーティション(エントリの保持や各種処理に責任を持つ単位)と考えてよいのか。と佐藤さんの『分散インメモリキャッシュとデータグリッド』を読んでなんとなく納得したり。
ジェズイットを見習え |
「SYNに対するACKを2時間待ってしまえばすでに成り立たない」。そうか、2フェーズコミットは Hard State だったんだ。気づいてなかった。
初回のコミットがオンラインであれば2回目もオンラインだという前提や、オフラインの判定が適切なタイミング(処理にも依存すると思いますがきれいにポートが閉じていてRSTが瞬時(1ミリ秒以内)に返ってくる状態)で可能だという前提を抜きにすると、あまり役に立たないですね。特にオフラインの判定というのが厄介過ぎ。
実態はどうかは別にして、Prepareを受け取ったノードはログに書いていると認識しています。なので、commitを投げた段階で失敗することはないという前提に立っていたかと。もちろん、ノードが生きているという前提にたっていて、この前提がないとどうにもならないんですが...