Slide 1

Slide 1 text

1 hashicorp/raftからraftを学ぶ mercari.go #22 @toshinao

Slide 2

Slide 2 text

2 ● twitter ○ toshinao ● Backend Engineer at Mercoin ○ 主に外部システム連携を担当 自己紹介

Slide 3

Slide 3 text

3 ● https://www.oreilly.co.jp/books/97848731199 77/ ● Go言語による分散サービスの中でraftを使ったシ ステムのハンズオンが記載されている ● hashicorp/raftを使った分散ログ保存サービスの コードが載っている raftについて調べたきっかけ

Slide 4

Slide 4 text

4 ● ログや設定を保存するための分散合意アルゴリズム ● etcd(KVS)やcunsul(サービスディスカバリー)の中で使わ れている ● Leaderの権限が強い ○ シンプルで分かりやすいメカニズムを目指して作られた ○ clientの応答は全てLeaderが返す(と論文には書かれている) ○ ログの送信(レプリケーション)はLeaderから送る ○ 過半数に書き込みが成功すると確定したことになる raftについて

Slide 5

Slide 5 text

5 ● 論文は2つある ○ 最初に博論として書かれた ■ https://github.com/ongardie/dissertation#readme ○ よく読まれている論文は元の論文からコンセンサスアルゴリズム部 分を抽出している ■ https://raft.github.io/raft.pdf ● 博論には下記について詳細に書かれている ○ 構成変更 ○ ログのコンパクション ○ clientとのやり取り 論文

Slide 6

Slide 6 text

6 ● ログはどのノードも同じ状態になるような仕組み ○ 有限状態機械(Finite State Machine; FSM)として同じ順序でロ グを適応することで実現している ● Leaderからheartbeatを送る ○ leaderから一定期間heartbeatが送られないと選挙が始まる ● 論理時計を持つことでクラスターの一貫性を保つ ○ hashicorp/raftではlamport clockを使用している ○ term(Leaderの期間)、index(単調増加する値)を保存・送信する 特徴

Slide 7

Slide 7 text

7 ● Followerから始まる ● 選挙が始まると(timeoutを検知すると)Candidateになる ● 選挙で選ばれるとLeaderになる ● Leaderの時に自分より大きいtermのログが届くとFollower になる サーバーの状態

Slide 8

Slide 8 text

8 ● コンセンサス ○ AppendEntries RPC ■ ログの追加 ■ heartbeat(空で送るとheartbeatになる) ○ RequestVote RPC ■ 選挙 ● 構成変更(博論にだけ載っている) ○ AddServer RPC ■ 新しいサーバー追加 ○ RemoveServer RPC ■ サーバーの削除 論文に載っているRPC1

Slide 9

Slide 9 text

9 ● Snapshotの連携(博論にだけ載っている) ○ InstallSnapshot RPC ■ ログの連携が遅いフォロワーに対してSnapshotを送る ● クライアント(博論にだけ載っている) ○ ClientRequest RPC ■ PRCのリクエスト ○ ClientQuery RPC ■ Read Onlyのリクエスト ○ RegisterClient RPC ■ client毎にidを発行する(重複リクエストを識別出来るようにす るため) 論文に載っているRPC2

Slide 10

Slide 10 text

10 ● Leaderからのheartbeatが途切れたら選挙がはじまる ● FollowerからCandidateに変更 ● 立候補はランダムな時間をおいてからリクエストする ○ 立候補とはRequestVote RPCを他のサーバーに送ること ○ 票が割れてLeaderが決まらないケースを減らす ● RequestVote RPC受信側は自分の持っているterm、indexの方が 大きい場合、投票しない 選挙

Slide 11

Slide 11 text

11 ● Leaderが変わるとtermが変わる ● Leaderが決まらなかった場合、termが変わる ○ 票が割れた場合など ○ Lederがいないtermが存在する termと選挙の関係

Slide 12

Slide 12 text

12 // 下記の関数でraftインスタンスを生成・起動 func NewRaft(*Config, FSM, LogStore, StableStore, SnapshotStore,Transport) ( *Raft, error) // FSMは下記のメソッドを実装している必要がある type FSM interface { Apply(*Log) interface{} Snapshot() (FSMSnapshot, error) Restore(snapshot io.ReadCloser) error } // LogStoreはAppendEntries RPCで追加するログの保存 // StableStoreは設定を保存 // LogStoreとStableStoreで使えるraft-mdbやraft-boltdbがある // SnapshotStoreはLogStoreのSpanpshot // Transportはサーバー間で通信する為のロジック hashicorp/raftの使い方・生成

Slide 13

Slide 13 text

13 // Leaderとして起動(BootstrapClusterしないサーバーはFollowerとして起動) func (r *Raft) BootstrapCluster(configuration Configuration) Future // Logの追加 func (r *Raft) Apply(cmd []byte, timeout time.Duration) ApplyFuture // clusterに参加 func (r *Raft) AddVoter(id ServerID, address ServerAddress, prevIndex uint64, timeout time.Duration) IndexFuture // clusterから抜ける func (r *Raft) RemoveServer(id ServerID, prevIndex uint64, timeout time.Duration) IndexFuture // Leaderを他のサーバーに委譲する func (r *Raft) LeadershipTransfer() Future // restoreを強制的に呼ぶ raft.Restore(meta *SnapshotMeta, reader io.Reader, timeout time.Duration) Leaderで呼ぶ必要があるメソッド

Slide 14

Slide 14 text

14 // Leaderサーバーのアドレスを取得 func (r *Raft) Leader() ServerAddress // 設定の取得 func (r *Raft) GetConfiguration() ConfigurationFuture // 自サーバーがどの状態(Leader、Follower、Candidate)か取得 func (r *Raft) State() RaftState // snapshotを強制的に呼ぶ func (r *Raft) Snapshot() SnapshotFuture // サーバーをshutdownするときに呼ぶ func (r *Raft) Shutdown() Future Leader以外でも良いメソッド

Slide 15

Slide 15 text

15 ● AppendEntries ○ logをFollowerに送る ○ 構成変更もAppendEntriesで送られる ● RequestVote ○ Leaderになるときに他のサーバーに送る ■ last_log_indexやlast_log_termも送る ○ responseのGrantedをtrueで返すと投票したことになる ● TimeoutNow ○ Leaderを委譲するサーバーに選挙開始を伝える ● InstallSnapshot ○ コンパクション済みでAppendEntriesで遅れない場合にspanshotを送る hashicorp/raftの内部API

Slide 16

Slide 16 text

16 ● 論文と実装ではことなることがある ● Client APIは存在しない ○ Leader以外で更新系処理を実行するとエラーになる ○ Leaderが誰か把握している必要がある ○ 取得系の処理はLeader以外が返しても良い ● Configurationの更新もAppendEntriesで伝える ○ AddServer RPC やRemoveServer RPCは存在しない ● TimeoutNowというAPIが存在する ○ Leaderの委譲時に使う ■ 移譲先が早くRequestVoteを送るために使用する まとめ