Top Banner
Akka Cluster の ののののの のののの Scala の西 2016 のののののののの https://github.com/TanUkkii007/blog/blob/master/akka_cluster_resilience.
37

Akka Clusterの耐障害設計

Jan 06, 2017

Download

Engineering

TanUkkii
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Akka Clusterの耐障害設計

Akka Cluster の耐障害設計安田裕介

Scala 関西 2016

スピーカーノートhttps://github.com/TanUkkii007/blog/blob/master/akka_cluster_resilience.md

Page 2: Akka Clusterの耐障害設計

自己紹介• 安田裕介• @TanUkkii007

• 東京で Scala の仕事をしています• Akka 好き

Page 3: Akka Clusterの耐障害設計

Akka Cluster の適用領域Basically

Soft state

Eventually consistent

Available

client-facing で

な分散システム

Page 4: Akka Clusterの耐障害設計

Akka Cluster を使う利点• 位置透過性

• サービスの成長に合わせてスケール戦略を切り替えられる• スケール戦略が変わってもコードが変わらない

• エコシステム• シャーディングやレプリケーションなど、分散システムでよく用いるアルゴリズムを実装した拡張がある

Page 5: Akka Clusterの耐障害設計

Akka Cluster の基本

Page 6: Akka Clusterの耐障害設計

Akka Cluster とは?• クラスターのメンバーシップ管理を行う Akka 拡張• Amazon Dynamo や riak に影響を受けている• gossip プロトコルによるメンバーの状態伝播と、 failure detector による障害検知を可能にする

Page 7: Akka Clusterの耐障害設計

failure detector• クラスターのメンバーは互いにハートビートを送り合っている• failure detector はハートビートをもとにメンバーの生死を推測する• 生きているメンバーは

reachable 、死んでいるメンバーはunreachable とマークする

Page 8: Akka Clusterの耐障害設計

gossip プロトコルとメンバーシップライフサイクル• メンバーには状態があり、 gossip プロトコルで他のメンバーと状態を同期する• gossip 収束時に一意に決まるリーダーという役割がある• リーダーがメンバーの状態を変える行為をリーダーアクションという• クラスターに参加するメンバーは joining 状態から始まる• リーダーは joining 状態のメンバーを up 状態にし、クラスターに参加させる• down 状態になったメンバーは、リーダーによってremoved 状態にされ、クラスターから取り除かれる

doc.akka.io

Page 9: Akka Clusterの耐障害設計

Akka Cluster の耐障害性設計

Page 10: Akka Clusterの耐障害設計

故障の単位:プロセス• 故障の単位をプロセスという• アクタープログラミングではプロセスはアクター• この発表では Akka Cluster の1ノードをプロセスとする• つまり Akka Cluster の UNIX プロセスと同義

Page 11: Akka Clusterの耐障害設計

故障の種類クラッシュストップ故障

オミッション(切り捨て)故障クラッシュ・リカバリー故障

ビザンチン(任意)故障Reliable and secure distributed programming, Ch.2

Page 12: Akka Clusterの耐障害設計

クラッシュストップ故障オミッション(切り捨て)故障

クラッシュ・リカバリー故障ビザンチン(任意)故障

Reliable and secure distributed programming, Ch.2

クラッシュストップ故障

Page 13: Akka Clusterの耐障害設計

クラッシュストップ故障• 正常に処理を実行していたプロセスがある時刻以降処理を停止して2度と戻らない故障• 故障のなかでもっとも単純• Akka Cluster のレイヤーで考えなければならない故障のほぼ全てはこれ

Page 14: Akka Clusterの耐障害設計

クラッシュストップ故障で停止する処理• unreachable なメンバーがいると、 gossip プロトコルで状態を完全に同期できない( gissip 非収束状態)• クラスターの状態を変えるリーダーアクションが行えなくなる• → メンバーの追加ができない

Page 15: Akka Clusterの耐障害設計

gossip 非収束状態の解決

• unreachable なメンバーのハートビートが回復して failure detector によって再び reachable になる• unreachable なメンバーを down 状態にする

クラスターのメンバーがクラッシュストップ故障を起こすと、そのメンバーに gossip プロトコルによってクラスターの状態を伝播できなくなる。このとき gossip は収束しない。

gossip の非収束を解決する方法

doc.akka.io

Page 16: Akka Clusterの耐障害設計

Auto-downing• デフォルトでは unreachable なメンバーを自動的に down 状態にはしない• リーダーが unreachable なメンバーを指定時間後に自動的に down する機能に auto-down がある• auto-down は使ってはならない

_人人人人人人人人_>    < ̄ Y^Y^Y^Y^Y^Y^Y  ̄

doc.akka.io

Page 17: Akka Clusterの耐障害設計

なぜ auto-down を使ってはならないのかを考える根本的な問題は、 failure detector がメンバーを

unreachable と判定したとき、そのメンバーは本当に死んでいるのか、ネットワーク遅延や分断なのか、 GCや負荷による遅延なのかが分からないということ。この問題が分散システムを難しくしている理由の1つ。down したメンバーが実は生きていた場合、 split

brain 問題がおきる。

Page 18: Akka Clusterの耐障害設計

split brain 問題• failure detector がメンバーを死と推定したとしても、実際には生きている場合がある• 生きているメンバーをクラスターから分離すると、結果的にクラスターが分裂する問題を split brain 問題という• 分離したクラスターの状態は同期出来ず、誤った情報をクライアントや

DB に伝える

Page 19: Akka Clusterの耐障害設計

リーダーの決定• リーダー選出という過程はない• 各メンバーが gossip プロトコルで同期されたメンバーリストから独立に決める• リーダーは unreachable でないメンバーのうち Up と Leaving状態のものを優先的に選択し、アドレス順に並べて先頭のもの

/** * Up|Leaving, Joining, Exiting, Down の順に並べ先頭のものがリーダー。同じ状態の場合最小のアドバイスのものを選ぶ。コードは以下を参照。 * https://github.com/akka/akka/blob/v2.4.10/akka-cluster/src/main/scala/akka/cluster/Gossip.scala#L190-L196 */val leader = reachableMembers.min(Ordering.fromLessThan[Member] { (a, b) ⇒ (a.status, b.status) match { case (as, bs) if as == bs ⇒ Member.addressOrdering.compare(a.address, b.address) <= 0 case (Down, _) ⇒ false case (_, Down) ⇒ true case (Exiting, _) ⇒ false case (_, Exiting) ⇒ true case (Joining, _) ⇒ false case (_, Joining) ⇒ true case _ ⇒ Member.addressOrdering.compare(a.address, b.address) <= 0 }})

Page 20: Akka Clusterの耐障害設計

auto-down が引き起こす split brain

Page 21: Akka Clusterの耐障害設計

split brain 問題を解決するには• リーダーよりも整合性の高い方法で決定でき、 down を果たせる役割は何か?• 2つ以上に分割される場合、どれが正しいクラスターなのか?• 正しくないクラスターを決めたとして、そのメンバーをどうすべきか?

Page 22: Akka Clusterの耐障害設計

split brain resolver

• Keep Reference• Keep Oldest• Static Quorum• Keep Majority

• Lightbend Reactive Platform

• TanUkkii007/akka-cluster-custom-downing

split-brain-resolver のストラテジ

Page 23: Akka Clusterの耐障害設計

Keep Oldest• 最古のメンバーがいる側を正のクラスターとする• 最古のメンバーとは起動時のタイムスタンプがもっとも小さいもの

• そうでない側のメンバーは自らシャットダウンする• unreachable なメンバーを down する役割は最古メンバーが担う• 最古のメンバーは gossip 非収束時にも一意に決まる(※例外あり)• 可用性の点で問題あり。最古のメンバーが故障した場合、全クラスターがシャットダウンする。(オプションで回避可能)

val oldest = members.filterNot(_.status == Removed).min(Member.ageOrdering)

Page 24: Akka Clusterの耐障害設計

Keep Oldest

Page 25: Akka Clusterの耐障害設計

Static Quorum• 残存メンバーが quorum size に満たない場合、そのメンバーを

down しする• 他のメンバーを down する役割はリーダーが担う• quorum-size * 2 - 1 を超えるメンバーを追加しない限り split

brain はおきない• quorum-size と総ノード数で可用性を調節可能• メンバーの数を固定しなければならない点が弱点。 quorum を適用するロールを限定して他のロールのメンバー数を動的にすると良い。

Page 26: Akka Clusterの耐障害設計

Static Quorum

Page 27: Akka Clusterの耐障害設計

FLP Impossibility “非同期なシステムにおいては、

ただ1つのプロセスが故障しただけでも、完璧に合意できる分散アルゴリズムは存在しない”

Fisher, Lynch, Paterson (1985) Impossibility of Distributed Consensus with One Faulty Process

完璧な split brain resolver のストラテジはない

Page 28: Akka Clusterの耐障害設計

オミッション(切り捨て)故障クラッシュ・リカバリー故障

ビザンチン(任意)故障Reliable and secure distributed programming, Ch.2

オミッション(切り捨て)故障クラッシュストップ故障

Page 29: Akka Clusterの耐障害設計

オミッション(切り捨て)故障• プロセスが送るべきメッセージを送らない、あるいは受信するべきメッセージを受信できない故障• プロセスがクラッシュした場合も送るべきメッセージを送れないので、オミッション故障はクラッシュストップ故障のより一般的な場合と見ることができる

Page 30: Akka Clusterの耐障害設計

Akka Remote におけるオミッション故障• システムメッセージを送信できず、ローカルとリモートのアクターシステム間の状態が同期できなくなったときにオミッション故障となる• システムメッセージには、リモートスーパーバイザーに管理されたアクターのライフサイクルイベント、 watch による死活監視、リモートアクターのデプロイメントがある• このとき Akka Remote の状態は quarantined になり、そのメンバーは unreachable から戻ってこれなくなる• split brain resolver を使用している場合、 unreachable なメンバーはクラスターから取り除かれ、取り除かれたメンバーはシャットダウンする→クラッシュストップ故障と全く同じ扱いになる

Page 31: Akka Clusterの耐障害設計

オミッション(切り捨て)故障クラッシュ・リカバリー故障

ビザンチン(任意)故障Reliable and secure distributed programming, Ch.2

クラッシュ・リカバリー故障クラッシュストップ故障

Page 32: Akka Clusterの耐障害設計

クラッシュ・リカバリー故障• プロセスがクラッシュしただけでなく、そこからリカバリーできない、あるいはクラッシュと再起動を繰り返してしまう故障• リカバリーできない場合、送るべきはずのメッセージを送れないので、オミッション故障と見ることもできる

Page 33: Akka Clusterの耐障害設計

Akka Cluster におけるクラッシュ・リカバリー故障• クラッシュして取り除かれたノードが再起動してクラスターに再加入することを前提としていない• クラッシュ・リカバリー故障はおきない

Page 34: Akka Clusterの耐障害設計

メンバーの識別• Akka Cluster はメンバーを hostname:port:uid の3つの識別子で認識する• uid はアクターシステム起動時に発行されるユニークな ID• ホストとポートが同じでも、再起動した後では uid が異なる• つまりクラッシュして再起動したプロセスは、以前のプロセスと別物と認識される• →新しくクラスターに加入することと全く同じ:クラッシュ・リカバリー故障はおきない

Page 35: Akka Clusterの耐障害設計

蘇り( incarnation )ノード• Q: クラッシュしたメンバーは unreachable となってリーダーアクションがとれなくなるため、再起動してもノードがクラスターに再加入できるのか?• A: できる• クラスターのメンバーと同じホスト:ポートのペアをもつメンバーが加入( joining )してきた場合、リーダーは古いメンバーを自動的に downする• 同じホスト:ポートのペアをもつメンバーが同時に2つ存在することはありえない。古いメンバーはクラッシュしたことをリーダーは判断できる。• auto-down や split brain resolver を使わなくてもこの機能は働く

Page 36: Akka Clusterの耐障害設計

再起動が引き起こすsplit brain 問題

正しい第一 seed 設定

Page 37: Akka Clusterの耐障害設計

再起動が引き起こすsplit brain 問題

誤った第一 seed 設定