Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Raft 文献調査

koyamaso
February 04, 2021
160

Raft 文献調査

koyamaso

February 04, 2021
Tweet

Transcript

  1. Raft とは (2) 有名な実装Best 2 1. https://etcd.io/ - Goで実装されている -

    性能を向上させるために実装が工夫されている (=分かりづらい) - 代表的なユーザ: https://kubernetes.io/ 2. https://github.com/willemt/raft - Cで実装されている - シンプルな実装 - 代表的なユーザ: https://daos-stack.github.io/
  2. Raft 概要(2) Raftでは「Leader」になったサーバは主に - クライアントからのクエリに応答 - エントリを作成 - 他のサーバにエントリを複製 を行う

    Leaderではないサーバがクライアントからクエリを受け取っても、 Leaderサー バを教えること以外何もしない Leaderはあるエントリまで過半数のサーバに複製されたことを確認できれば、 そこまでcommitする commitするにあたって実際にはもう少し制約があるが詳細は後述
  3. Raft 概要(3) ここまでで説明していないこと - どのようにLeaderを選出するか - Leaderは今までcommitされた全てのエントリを保存していなければならない - でなければ、新しいエントリで commitされたエントリを上書きしてしまう可能性がある

    - いつLeaderが死んでも次のリーダーが選出されなければならない - また、2台以上のLeaderが同時にいる状況を (なるべく)作らない - Leaderは各サーバにどのエントリを送るか - 極論エントリが追加されるたびに今までのログを全て送れば整合性はとれるが非効率 - 各サーバがどこまで Leaderのログと一致しているか、確かめる必要がある
  4. Raftが保証する性質 - 各termにおいて選出されるLeaderは最大1つ - Leaderは自身のログに保存されたエントリを上書きしたり消したりせず、 appendのみ行う - 2つのログが同一のindexとtermをもつエントリを持っていた時、そのエントリまで同一 - エントリがterm

    Tでcommitされたとき、term U (>T) のLeaderのログにそのエントリは含まれる - あるエントリをステートマシンに applyしたとき、同一indexで異なるエントリを他サーバは applyしない
  5. Leader選出 ログa,bのどちらがより「進んでいる」か調べるには最後のエントリ Last(a),Last(b)を比べればよい 比較関数は以下のようにかける ここではあるエントリeのindex,termを取得する関数をindex(e),term(e)と表す - もしterm(Last(a)) != term(Last(b)) であるなら

    term(Last(a)) < term(Last(b)) - もしterm(Last(a)) == term(Last(b))であるならindex(Last(a)) < index(Last(b)) 各サーバは以下の条件が満たされる相手にのみ投票する - 相手のtermが自分より大きい、または同じ termかつまだ今term中に投票していない - 相手のログが自分より進んでいる(同一含む)
  6. Leader選出 (2) 前ページのLeader選出条件が満たされていれば Leaderは今までcommitされたエントリを全て含んでいることを背理法で証明出来る 1. termTにLeaderTがあるエントリをcommitし、termU(>T)に LeaderUがそのエントリを保存していないことを仮定 2. LeaderTはcommitに過半数のサーバに合意をとっており、 LeaderUはLeaderになるために過半数のサーバに合意をとって

    いる よってLeaderTのcommitに参加しかつLeaderUの選出に参加し たサーバが少なくとも一台存在する(以降 voterと呼ぶ) 3. voterはLeaderUの選出に参加する前に LeaderTのcommitに参 加している LeaderUの選出に参加したvoterのtermはUになり、その後には LeaderTのcommitに参加できない FollowerはLeaderのエントリと衝突した時のみエントリを上書きするため、 voterはLeaderUの選出に参加するまで LeaderTのcommitしたエントリを 保存している 仮定よりvoterはLeaderUの選出に参加している。選出条件より LeaderU のログはvoterのログより進んでいる必要がある LeaderUの選出にあたり、最後のエントリの比較で 2通りが考えられ、どち らも矛盾を起こす voterとLeaderUの最後のエントリの termが等しい場合、最後のエントリの indexはvoterの方が小さいと投票されないことから、 voterのエントリはUに 全て含まれる。よって矛盾が起こる LeaderUの最後のエントリの termの方が大きい場合、それは Tよりも大きく なる。LeaderUの最後のエントリを追加した LeaderXは今までcommitされ たエントリを持っているので Uにも今までcommitされたエントリが複製さ れ、ここにTがcommitしたエントリも含まれる。よって矛盾が起こる(循環し ているがT<X<Uより6-1に収束する) 4. 5. 6-1. 6-2.
  7. 各サーバの状態 Persistent stateはストレージに保存する Volatile(揮発性) stateはサーバ開始/再開時に初期化される nextIndex[]: 各サーバに次にどのエントリを送るか 選挙後にリーダーの最後のエントリのindex+1に初期化され、 一致するまで-1していく matchIndex[]:

    各サーバがどこまでリーダーのログと一致しているか 選挙後に0で初期化され、ログが一致すれば更新される このときnextIndex[]のデクリメントは止まり、 その後matchIndexとnextIndexは同じペースで進んでいく
  8. クラスタMembership変更 クラスタを構成するサーバを追加または削除したいとき、全体を止めずに変更できる仕組み 提案されている手法は 2種類ある - 旧構成と新構成の中間構成を作成する joint consensus法(https://raft.github.io/raft.pdf Section 6)

    - 1ノードずつ追加または削除する single server法 (https://github.com/ongardie/dissertation/blob/master/book.pdf Section 4) 以降はsingle server法を説明する クラスタを変更することはめったになく、サーバ台数も多くないので 1台ずつの変更でも十分実用的