普通の人でもわかる paxos
TRANSCRIPT
普通の人でもわかるPaxos
@tyonekura
前提
• 一番シンプルなPaxosプロトコル(PaxosMadeSimple)を紹介します。
Paxosとは
• ある値を、過半数のノードに書き込むプロトコル。もうちょっと正確には、過半数のノードに書き込まれた時点で合意したとみなせるプロトコル。
• 途中でネットワークが途切れたり、ノードが死んだり、生き返ったり、色々しても大丈夫。
登場人物• クライアント– プロポーザに、書き込みをお願いする人– 登場人物といっておきながら、話はプロポーザが値を持ってから始めればいいので、以下登場しません。
• プロポーザ– アクセプタの過半数に同じ値を書き込むよう頑張る
• アクセプタ– プロポーザから来た値をよきにはからう(後述)
• リスナ– 最後に、過半数のアクセプタから値をゲット。
基本的な動き(フェーズ1)
• フェーズ1a(プロポーザ側)– アクセプタにお伺いをたてる。その際、メッセージIDを添える。
• フェーズ1b(アクセプタ側)– 初めてのお伺いや、これまで約束したお伺いより高いIDだったら、約束を返す。もし今までアクセプトをしていたら、その値も返す。
– これまで約束したお伺いより低いIDは無視する。
オレンジのキーワードは、送られるメッセージの種類を指しています。
基本的な動き(フェーズ2)
• フェーズ2a(プロポーザ側)– 過半数のアクセプタから約束が返ってこなかったら、どこかで諦めて、メッセージIDを増やして最初からやりなおし。
– 過半数のアクセプタから約束が返ってきたら、メッセージIDと値を添えてアクセプタにプロポーズを送る。
– プロポーズを送る際に、もしも約束に(ID,値)の組がついて返ってきたら、自分の値を、返ってきた約束の中で一番高いIDの値で書き換えてプロポーズを送る。(IDは自分の。なぜなら、約束が返ってきたということは、その時点で自分のIDが一番高い。)
基本的な動き(フェーズ2)
• フェーズ2b(アクセプタ側)– プロポーズのIDが最後に約束したIDか、それより大きい場合、アクセプトする。
– プロポーズのIDが最後に約束したIDより小さい場合、お断りする。
基本的な動き(終わり)
• フェーズ2c?(プロポーザ側)– 過半数からアクセプトが返ってきたら終了– 過半数に達せずタイムアウトするか、過半数からお断りされたらメッセージIDを増やして最初に戻る。
• リスナーは、アクセプタに聞いて回って、過半数のアクセプタが同じ値を持っていたらその値を信じる。
と、こう書くと
• よくわからなくなる。• たぶん、例が少ないのでわからないのだと思う。
• なので、以下パラパラ漫画
一番単純なケース
アクセプタ1
アクセプタ2
アクセプタ3
プロポーズしていいですか?(1)
プロポーズしていいですか?(1)
プロポーズしていいですか?(1)
お伺い
お伺い
お伺い
0
0
0
プロポーザ
一番単純なケース
アクセプタ1
アクセプタ2
アクセプタ3
いいですよ(1)
いいですよ(1)
いいですよ(1)
約束
約束
約束
1
1
1
プロポーザ
一番単純なケース
アクセプタ1
アクセプタ2
アクセプタ3
鈴木です。(1)
鈴木です(1)
鈴木です(1)
プロポーズ
プロポーズ
プロポーズ
1
1
1
プロポーザ
一番単純なケース
アクセプタ1
アクセプタ2
アクセプタ3
プロポーザ
アクセプト(1)
アクセプト(1)
アクセプト(1)
1
1
1
鈴木
鈴木
鈴木
一番単純なケース
アクセプタ1
アクセプタ2
アクセプタ3
リスナー
1
1
1
鈴木
鈴木
鈴木
鈴木ね
アクセプタ一台故障
アクセプタ1
アクセプタ2
アクセプタ3
プロポーズしていいですか?(1)
プロポーズしていいですか?(1)
プロポーズしていいですか?(1)
お伺い
お伺い
お伺い
0
0
0
プロポーザ
アクセプタ一台故障
アクセプタ1
アクセプタ2
アクセプタ3
いいですよ(1)
いいですよ(1)
約束
約束
1
0
1
プロポーザ
アクセプタ一台故障
アクセプタ1
アクセプタ2
アクセプタ3
鈴木です。(1)
鈴木です(1)
プロポーズ
プロポーズ
1
0
1
プロポーザ
アクセプタ一台故障
アクセプタ1
アクセプタ2
アクセプタ3
プロポーザ
アクセプト(1)
アクセプト(1)
1
0
1
鈴木
鈴木
アクセプタ一台故障
アクセプタ1
アクセプタ2
アクセプタ3
リスナー
1
0
1
鈴木
鈴木
鈴木ね
アクセプタ一台故障と思ったら生き返った
アクセプタ1
アクセプタ2
アクセプタ3
プロポーズしていいですか?(1)
プロポーズしていいですか?(1)
プロポーズしていいですか?(1)
お伺い
お伺い
お伺い
0
0
0
プロポーザ
アクセプタ一台故障と思ったら生き返った
アクセプタ1
アクセプタ2
アクセプタ3
いいですよ(1)
いいですよ(1)
約束
約束
1
1
1
プロポーザ
アクセプタ一台故障と思ったら生き返った
アクセプタ1
アクセプタ2
アクセプタ3
鈴木です。(1)
鈴木です(1)
プロポーズ
プロポーズ
1
1
1
プロポーザ
プロポーズ
鈴木です(1)
約束返ってきてなくてもとりあえずプロポーズする。
アクセプタ一台故障と思ったら生き返った
アクセプタ1
アクセプタ2
アクセプタ3
プロポーザ
アクセプト(1)
アクセプト(1)
1
1
1
鈴木
鈴木
アクセプト(1)
いままでで一番IDが大きいのでアクセプトする。鈴木
アクセプタ一台故障と思ったら生き返った
アクセプタ1
アクセプタ2
アクセプタ3
リスナー
1
1
1
鈴木
鈴木
鈴木ね
鈴木
プロポーザ2人
アクセプタ1
アクセプタ2
アクセプタ3
プロポーズしていいですか?(1)
プロポーズしていいですか?(1)
プロポーズしていいですか?(1)
お伺い
お伺い
お伺い
0
0
0
プロポーザ
プロポーザ2人
アクセプタ1
アクセプタ2
アクセプタ3
いいですよ(1)
いいですよ(1)
約束
約束
1
1
1
プロポーザ
いいですよ(1)約束
プロポーザ2人
アクセプタ1
アクセプタ2
アクセプタ3
プロポーズしていいですか?(2)
プロポーズしていいですか?(2)
プロポーズしていいですか?(2)
お伺い
お伺い
お伺い
1
1
1
プロポーザ2人
アクセプタ1
アクセプタ2
アクセプタ3
いいですよ(2)
いいですよ(2)
約束
約束
2
2
2
いいですよ(2)約束
プロポーザ2人
アクセプタ1
アクセプタ2
アクセプタ3
鈴木です。(1)
鈴木です(1)
プロポーズ
プロポーズ
2
2
2
プロポーザ
プロポーズ
鈴木です(1)
プロポーザ2人
アクセプタ1
アクセプタ2
アクセプタ3
プロポーザ
リジェクト(2)
リジェクト(2)
2
2
2
リジェクト(2)
プロポーザ2人
アクセプタ1
アクセプタ2
アクセプタ3
佐藤です。(2)
佐藤です(2)
プロポーズ
プロポーズ
2
2
2
プロポーズ
佐藤です(2)
プロポーザ2人
アクセプタ1
アクセプタ2
アクセプタ3
プロポーザ
アクセプト(2)
アクセプト(2)
2
2
2
佐藤
佐藤
アクセプト(2)
佐藤
プロポーザ2人
アクセプタ1
アクセプタ2
アクセプタ3
リスナー
2
2
2
佐藤
佐藤
佐藤ね
佐藤
もしリスナーが選ぶ前にリトライしたら敗者復活?
アクセプタ1
アクセプタ2
アクセプタ3
プロポーズしていいですか?(3)
プロポーズしていいですか?(3)
プロポーズしていいですか?(3)
お伺い
お伺い
お伺い
2
2
2
佐藤
佐藤
佐藤
おや?約束に、他人の名前が。。
アクセプタ1
アクセプタ2
アクセプタ3
いいですよ(佐藤、2)
いいですよ(佐藤、2)
約束
約束
いいですよ(佐藤、2)約束
3
3
3
佐藤
佐藤
佐藤
なぜ他人の名前で。。せつない。。
アクセプタ1
アクセプタ2
アクセプタ3
佐藤です。(3)
佐藤です(3)
プロポーズ
プロポーズ
2
2
2
プロポーズ
佐藤です(3)
2
2
2
佐藤
佐藤
佐藤この後の処理は結果が変わらないので、実装依存
プロポーザ3人
アクセプタ1
アクセプタ2
アクセプタ3
プロポーズしていいですか?(1)
プロポーズしていいですか?(1)
プロポーズしていいですか?(1)
お伺い
お伺い
お伺い
0
0
0
プロポーザ
プロポーザ3人
アクセプタ1
アクセプタ2
アクセプタ3
いいですよ(1)
いいですよ(1)
約束
約束
1
1
1
プロポーザ
いいですよ(1)約束
プロポーザ3人
アクセプタ1
アクセプタ2
アクセプタ3
プロポーズしていいですか?(2)
プロポーズしていいですか?(2)
お伺い
お伺い
1
1
1
二人目の時、1台不調
プロポーザ3人
アクセプタ1
アクセプタ2
アクセプタ3
いいですよ(2)
約束
1
2
2
いいですよ(2)約束
プロポーザ3人(1台目復活)
アクセプタ1
アクセプタ2
アクセプタ3
鈴木です。(1)
鈴木です(1)
プロポーズ
プロポーズ
1
2
2
プロポーザ
プロポーズ
鈴木です(1)
プロポーザ3人
アクセプタ1
アクセプタ2
アクセプタ3
プロポーザ
アクセプト(1)
リジェクト(2)
1鈴木
2
2
リジェクト(2)
2人目がアクセプタ2にプロポーズしたところで。。
アクセプタ1
アクセプタ2
アクセプタ3
佐藤です(2)プロポーズ
1鈴木
2
2佐藤
まだとどいてない。
まだとどいてない。
アクセプト(2)
3人目が登場。
アクセプタ1
アクセプタ2
アクセプタ3
1鈴木
2
2佐藤
プロポーズしていいですか?(3)
プロポーズしていいですか?(3)
お伺い
お伺い
プロポーズしていいですか?(3)
お伺い
3人目が登場。
アクセプタ1
アクセプタ2
アクセプタ3
3鈴木
3
3佐藤
いいですよ(1,鈴木)約束
いいですよ(3)約束
いいですよ(2,佐藤)約束
3人目は佐藤を推す。
アクセプタ1
アクセプタ2
アクセプタ3
3鈴木
3
3佐藤
佐藤です。(3)プロポーズ
プロポーズ
プロポーズ
佐藤です(3)
佐藤です(3)
もしこの前に佐藤さんのプロポーズが届いたら、それはID2なので無視される。
プロポーザ3人
アクセプタ1
アクセプタ2
アクセプタ3
プロポーザ
アクセプト(3)
アクセプト(3)
3
3
3
佐藤
佐藤
アクセプト(3)
佐藤
プロポーザ3人
アクセプタ1
アクセプタ2
アクセプタ3
リスナー
3
3
3
佐藤
佐藤
佐藤ね
佐藤
その他
• 色んなパターンを試しても、過半数のアクセプタといずれかのプロポーザが生きているなら、いずれは合意が取れるようになっています。
• よくできてますね。。
ライブロック
アクセプタ1
アクセプタ2
アクセプタ3
プロポーズしていいですか?(1)
プロポーズしていいですか?(1)
プロポーズしていいですか?(1)
お伺い
お伺い
お伺い
0
0
0
プロポーザ
ライブロック
アクセプタ1
アクセプタ2
アクセプタ3
いいですよ(1)
いいですよ(1)
約束
約束
1
1
1
プロポーザ
いいですよ(1)約束
ライブロック
アクセプタ1
アクセプタ2
アクセプタ3
プロポーズしていいですか?(2)
プロポーズしていいですか?(2)
プロポーズしていいですか?(2)
お伺い
お伺い
お伺い
1
1
1
ライブロック
アクセプタ1
アクセプタ2
アクセプタ3
いいですよ(2)
いいですよ(2)
約束
約束
2
2
2
いいですよ(2)約束
ライブロック
アクセプタ1
アクセプタ2
アクセプタ3
鈴木です。(1)
鈴木です(1)
プロポーズ
プロポーズ
2
2
2
プロポーザ
プロポーズ
鈴木です(1)
ライブロック
アクセプタ1
アクセプタ2
アクセプタ3
プロポーザ
リジェクト(2)
リジェクト(2)
2
2
2
リジェクト(2)
ライブロック
アクセプタ1
アクセプタ2
アクセプタ3
プロポーズしていいですか?(3)
プロポーズしていいですか?(3)
プロポーズしていいですか?(3)
お伺い
お伺い
お伺い
2
2
2
プロポーザ
ライブロック
アクセプタ1
アクセプタ2
アクセプタ3
いいですよ(3)
いいですよ(3)
約束
約束
3
3
3
プロポーザ
いいですよ(3)約束
ライブロック
アクセプタ1
アクセプタ2
アクセプタ3
佐藤です。(2)
佐藤です(2)
プロポーズ
プロポーズ
3
3
3
プロポーズ
佐藤です(2)
ライブロック
アクセプタ1
アクセプタ2
アクセプタ3
プロポーザ
リジェクト(3)
リジェクト(3)
3
3
3
リジェクト(3)
以下、永遠につづくかも。(ランダムでsleep入れるとか、工夫する。)
以下、混乱しやすい点を
これらはPaxosの範疇じゃない
• トランザクション– Paxosは、過半数にある値を届けて合意を取るものであって、広い意味での(DB的な)トランザクションではない。
• クラスタメンバーシップ– とりあえず、メンバーは固定。アクセプタが増えたり減ったりする場合は実装側で。(メンバーシップ情報をPaxosで同期したりとか。)
これらはPaxosの範疇じゃない
• プロポーザ選択– 適当にどれか1台をプロポーザにする。– クライアントが複数のプロポーザを選んで同時に別々の提案をしても、大丈夫。
• 過半数に達した後の少数側の扱い– 実装上はデータ同期させたほうがいいと思うけど、それはPaxosの範疇外
これらはPaxosの範疇じゃない• ビザンチン障害
– 具体的には、– メッセージID偽装
• 約束されてないIDでプロポーズを投げる• 一意じゃないIDというのも、これに含まれると思う。
– アクセプタがアクセプトしてない値を捏造– アクセプタが約束してないIDを返す– 等等
• 過半数を超える障害– 例:9台5台のアクセプタがアクセプトした、と思ったら、その5台のうち1台が壊れた。
– 実用上は過半数、というところを変えてあげればOK.– 例:9台中5台に書き込めたらOKではなく、9台中7台に書き込めたらOKにして、アクセプトまでは2台障害に耐え、リスナーがチェックするときは5台でOKにするとか。
これらはPaxosの範疇じゃない
• メッセージIDをどうやって一意にするか• Macアドレス+シーケンス番号とか。• ノードID+シーケンス番号とか。– シーケンス番号同士を比べて、同じだったらノードIDを比べる。
– ノード番号同士を比べて、同じだったらシーケンス番号を比べる。
– 普通は前者。後者は、複数プロポーザケースに必ず1台が勝つことになるが、別にそれでもPaxos的には問題ない。