分散プログラミングモデルおよびデザインパターンの考察

分散システムバトンが回ってきていないので、僕も書いてみることにしました。が、先生方とは違い、私は全くの素人なので、俺俺分散論で行きたいと思います。

はじめに(予防線)

私は分散ファイルシステムを開発している部門で働いていますが、幸か不幸かあまり詳しいことは知りません。実際のシステムは私より10倍から100倍頭のいい人達が書いていて、私はそれをトントン叩いてチェックしているだけです。なので、この記事は特定の製品について語ったものではありません。

じこはおこるさ

事故がほら起きるよ 突然さ

運がない時はしょうがない

なんとかしよう

事故がもし起きたら

落ち込まないで

うまくやれるようにがんばろうよ

事故は起きるものさ

神歌ですね。これだけでこのエントリー終わりでいいんじゃないかって思ってきましたが、一応続けますね。

事故と言うとあまり聞こえが良くないので、エラーに変えますか。

エラーがほら起きるよ 突然さ

運がない時はしょうがない

なんとかしよう

エラーがもし起きたら

落ち込まないで

うまくやれるようにがんばろうよ

エラーは起きるものさ

と、いうわけで、トーマスで言えば、大事なのは死人が出ず、ソドー鉄道が倒産もせず、トップハムハット卿に怒られるくらいでいこう、ということですね。(たしかあまりにも悪くてコンクリートで固められた汽車が居た覚えがあるけど)

分散システムも、大体の場合は、「エラーが起きてもがんばろうよ」というスタンスです。いついかなるハードウェアエラー、ソフトウェアが起きても、なんとかしないといけません。処理が冪等であればリトライすればいいですし、そうじゃなくても、データ不整合を起こさない範囲でできるだけ頑張る。パニックを起こしていいのは、「やばい、今俺が死なないとデータが壊れる。メガザル!」という時だけです。

限界はある

設計上考慮する限界というのはあります。そして、設計上考慮しない限界というのもあります。昔「N+4構成なら4ノード同時に壊れてもデータを守れます」と説明したら、嬉々とした表情で「じゃあ、5台同時に壊れたら?」と聞いてきた見込み客がいましたが、「はあ、データは消えますね。それがなにか」というのをもう少しソフトに答えた記憶があります。まあ、そういう論外なのは脇に置くとしても、開発リソース、テストリソース、そしてなにより起こる可能性、起きた場合の対象方法を考慮して、どこまでやる必要があるかは商用システムの場合(そして、本来はOSSだったとしても)考える必要があります。また昔話になりますが、他社のエンジニアが「ここでSHA1をindexにしてデータを書いて」といったので「ぶつかった場合は?」と聞いたら、「え?ぶつかんないよ多分」と答えられたことがあり、「いや、それはうちの会社だと無理」と思ったことがありますが、まあ、例が悪いですね。

ビサンチンとか知らんけど。

別に論文の査読をしているわけではないので、実システムを組む上でビサンチン問題への対処を問われてもこまる、といえば困るのですが、現実問題として、アーキテクチャでどうにかするべきところと、実装上の工夫で緩和すべきところと、コンポーネント側のテストで何とかするべきところがあります。一番困るのは、ディスクに書いたら「ちゃんと書いたよー」と言ってきたのに、書いてない、とかですね。「歯磨きしたよー」といってるのに磨いてなくて、虫歯になった、みたいなやつ。定期的に親がちゃんと磨いてるかチェックするか?でも100万回に1回だけ磨いてなかったらどうする?それとも、それも障害として扱えるようにするか、もしくは嘘つきかどうか売る前にテストするか。アプライアンスの場合、「それは部品が嘘ついてました」じゃ済まないから、できるだけテスト。で、その結果どうなるかというと。。みんな、パソコンを買って、ドライブファームウェアのアップデートってしたことあります?無い?そうですか。それはラッキーですね。バグがないドライブを買ったんですね、多分。

現実的な分散システムを考えると、ビサンチン障害というのは概ね周辺ハードのファームウェア問題といってよいです。なぜなら、ノードXとノードYが異なるソフトウェアで動いていて、一人が嘘をつく、というのはあまりないから。(例外は、バージョンアップ時のミックスバージョンの挙動。少々趣が異なるのでここでは見なかったことにする)同じソフトウェアの中で一つのインスタンスが嘘をついてるケースは、どちらかというと「ソフトウェアのバグ」で片付く気がする。これは単なる気持ちの問題なので技術的な分類ではありませんが。

で、NICとか、Switchとか、ドライブとか、そのへんになるんだよね。いやー、辛いね。

一貫性とか

用途によって、実システムに必要な一貫性というのは変わってきます。入出金管理では1円単位であわないと困るかもしれません。適当でいいよ、という用途もあるでしょう。そして、その間も。クオータ(容量制限)システムにおいて、もしユーザーがその制限に対してお金を払っていたら、常に正確な容量を把握していないといけないです。が、全ユーザに追加で1GB余分に設定しておけば、一貫性がズブズブなシステムでもユーザが文句を言ってくることは無いです。が、もしそのユーザAが他のユーザBにシステムを提供していたら、余分な追加はユーザAにとって嬉しくないので文句が出ます。そういう微妙なバリエーションが色々出てきます。なので、誰も文句が出ないところはうまくやりましょう、と。それによって実装の複雑さや速度が変わってきたりします。

分散プログラミングモデル

分散してプログラミングするの?github便利だよ。