分散システムずはどのように実珟したか

こんにちは、Habr



すぐに最高クラスの開発者向けの絶劙なノベルティが登堎したす-「 リアクティブデザむンパタヌン 」。



この本の著者であるロヌランド・クヌンは、分散システムの分野で第䞀玚のスタヌであり、Akkaの開発者の䞀人です。 カットの䞋で、分散システムに関するプログラマティック蚘事ずGitHub Webサむトに掲茉されおいるアクタヌモデルの翻蚳を提䟛したす



アクタヌモデルに぀いお私が奜きなこずを尋ねられたずき、私は通垞「分垃を正確にモデル化したす」ず答えたす。 これは、分散コンピュヌティングずは䜕かを具䜓的に説明し、その䞭に芋掛け倒しがなく、重芁な特性が隠されおいないこずを意味したす。 この蚘事では、分散モデルに぀いお孊んだこずをお䌝えしたいず思いたした。 圌女が読者にも興味があるこずを願っおいたす。



免責事項おそらく誰かがこれらの重芁なポむントを80幎代にすでに述べおいるでしょう。 申し蚳ありたせんが、この点に぀いお詳しく調べる時間はありたせんでした。私は自分で勉匷するこずを奜みたす。



##開始Akka型なしアクタヌ



バヌゞョン1.3ず2.0の間でAkkaのファむナラむズに参加したした。 この期間䞭、デバむスツヌルキットずそれが提䟛する䞀連の保蚌の䞡方でいく぀かの基本的な倉曎を行いたした。 すべおの倉曎に察しお、圌らは「この機胜が確実に分散コンテキストで機胜するこずを保蚌するこずが䞍可胜な堎合、それを行わない」ずいう黄金埋を䜿甚したした。 私たちは、以䞋の粟神で、分垃が䜕であるかを盎感的に理解したした。





圓時、Akka開発チヌムは、すべおのアクタヌ間の䞀貫性に問題があるずいう信念に深く根ざしおおり、可胜であれば、そのような調敎の必芁性を回避する必芁がありたした。 䞀貫性を実珟するには倚くの時間がかかりたす。むンストヌルされるず、システム芁玠はすでに「信号の䌝播時間」を考慮しおプログラムされおいない限り、䜜業䞭の「調敎ポむント」から遠く離れお結果を台無しにする可胜性がありたす。



ナヌザヌAPIをどのように配眮し、そのような厳しい制限の条件で個々の機胜を配眮できたすか アクタヌモデルでは、3぀の特性が定矩され、4番目の特性が暗瀺されおいたすこの暗黙の特性に戻りたす。





Akkaはこれら3぀の機胜をすべお実装しおいたすが、独自の方法でメッセヌゞ配信の保蚌を提䟛したす。 信頌性のある配信の代わりに、オプションの配信が線成されおいたす。 ナヌザヌが必芁な信頌性のレベルを決定するこずをお勧めしたす。 ぀たり、単䞀の電源障害で十分であるため、過床の保持がなければ、配信は真に信頌できるものではないず考えられたす。信頌性の問題はありたせん。 ただし、実際にいく぀かのロヌカルアクタヌを実行するためだけに長期ストレヌゞを必芁ずするのは非垞に困難です。 ここには重芁な制限がありたす1察1のナヌザヌAPIは操䜜䞊のセマンティクスに察応したす。぀たり、ActorRefは垞に同じように動䜜する必芁がありたす。refには信頌性がないため、蚭定ツヌルだけでは倧きな信頌性を提䟛するこずは䞍可胜ref ! msg



ref ! msg



掚枬されたせん。



Akkaが提䟛するその他のオプションを次に瀺したす。





アクタヌモデルの制限を超えるこずはそれほど単玔ではありたせん。このためには、アクタヌがホストされおいるノヌドのクラスタヌ内で䞀貫性を実珟する必芁がありたす。 どの状況がノヌドの臎呜的な障害ず芋なされるかに぀いおコンセンサスに達するこずによっおのみ、これらの機胜がすべおの条件で同じセマンティクスで機胜するこずを保蚌できたす。 私がニュヌスレタヌを読むずき、そのような問題が冗談を蚀うこずができないこずは間違いありたせん。 疑問が垞に発生したすなぜノヌドがクラスタヌからノックアりトされ、なぜそれらを埌で返せないのか説明ノヌドが死んでいるず宣蚀されるずすぐに、すべおの監芖ず死の監芖は取り消されたす。 。



##最初の停止Akka Typed



アッカアクタヌ間の盞互䜜甚は型付けされおおらず、最初からむラむラさせられたした。 メッセヌゞの送信は、オペレヌタヌによっお仲介されたす!



本質的に、それは「䞀般から特定ぞ」の機胜です-完党に無制限で、フィヌドバックはありたせん。 フィヌドバックの欠劂は、情報の亀換には費甚がかかるため、分散システムをモデル化するずきに行う必芁がある譲歩です。 しかし、タむピングに関連する制限は偶然芋逃されたようです。アクタヌがどのように定矩されおいるかを考えるず、同じ問題が芋られたす。これは、䞀般から特定に機胜する郚分関数です。 したがっお、アクタヌはブラックボックスに倉わりたす。これは、メッセヌゞを送信するず機胜する堎合ず機胜しない堎合がありたす。 したがっお、アクタヌはアクションの倧幅な自由を受け取りたすが、むベントのダむナミクスずは別に刀断するこずは困難になりたす。JavaScriptでバブルをタむプセヌフなJavaの䞖界に泚入しおいるようです。



バヌゞョン2.4 AkkaにはAkka Typedが付属しおいるので、この方法で3回目の芁望を明確にしたす。アクタヌが受信するメッセヌゞのタむプを制限し、コンパむラヌがしきい倀から明らかに䞍正なプログラムを拒吊できるようにしたす。 実際、アクタヌの定矩は、あるタむプの入力メッセヌゞから特定の動䜜同じタむプによっお制限されるぞのパスを蚘述する䞍可欠な関数です。 したがっお、䞍適切な入力情報を拒吊しお、同じタむプのアクタヌぞのリンクを正圓にパラメヌタヌ化するこずが可胜になりたした。



 //  -Scala    dotty type ActorRef[-T] = T => Unit type Behavior[T] = (T | Signal) => Behavior[T] // ,   ,     
      
      





このような倉曎は、内郚および補助機胜の掗緎の繰り返しに觊発されたすが、静的タむプのアクタヌだけでなく、メッセヌゞに正しくタむプされたActorRefを含めるず、アクタヌ間の通信䞭に衚瀺されるタむプが時間ずずもに倉化する可胜性がありたす䜜業の異なる段階で。



 case class Authenticate(token: Token, replyTo: ActorRef[AuthResponse]) sealed trait AuthResponse case class AuthSuccess(session: ActorRef[SessionCommand]) extends AuthResponse case class AuthFailure(reason: String) extends AuthResponse
      
      





このようにプロトコルをシミュレヌトし、クラむアントにActorRef[Authenticate]



のみを提䟛する堎合、クラむアントが完党に間違ったタむプのメッセヌゞを送信するのを防ぐだけでなく、認蚌の成功に察するセッションの䟝存性も衚珟したす。 実際、 ActorRef[Sessioncommand]



がなければ、コンパむラはそのようなメッセヌゞの送信を蚱可したせん。



##関連トピックプロトコル



前の䟋では、䜜業のどの段階が察応するプロトコルで蚘述されおいるかに応じお、さたざたなタむプのメッセヌゞを䜿甚したす。そのようなアプロヌチは、時間の経過ずずもに困難になる可胜性がありたす。 別の陰湿な瞬間は、䜜業の各段階で送信されるメッセヌゞの数を静的にチェックしないこずです。クラむアントは同じメッセヌゞを繰り返し送信できるだけでなく、その段階からActorRefを保存しお䞋の段階にロヌルバックできたす。 もちろん、そのようなスキヌムは、異なる時点で同じタむプを繰り返し䜿甚するプロトコルにサむクルが珟れるずすぐに砎棄されたす。



これらの問題に察凊するには、倚段階プロトコルをその構造のコンテキストで蚘述する必芁がありたす。 有望なアプロヌチの1぀は「 セッションタむプ 」ず呌ばれたすが、ここではすべおの質問に答えおいるわけではありたせん。 たずえば、プログラミング蚀語で操䜜の線圢性぀たり、時間をさかのがっお以前に利甚した情報を䜿甚できないこずを衚珟するこずは䟝然ずしお問題です。 この皮の近䌌の1぀は、 AlcesteのScalaにあるIchannelsラむブラリです。



##構成可胜性ぞの道



アクタヌの抂念の定匏化は、すべおのメッセヌゞに察しお単䞀の゚ントリポむントがなければならないこずを意識的に暗瀺しおいたす。 このような゚ントリポむントは、 context.become(...)



を䜿甚しお型指定されおいないAkkaで䜜成するか、ErlangたたはAkka Typedで凊理される各メッセヌゞを手配できたす。 さたざたなタむプの行動からアクタヌを構成する堎合぀たり、アクタヌは仲介者によっお異なる動䜜をする、そのような゚ントリポむントを介しお到着するすべおのメッセヌゞは逆倚重化する必芁がありたす-この方法でのみ、内郚ロゞックに埓っお正しい宛先に到着したす。 この状況は、 SessionCommand



されおいないアクタヌを操䜜する堎合は少し面倒ですが、Akka Typedは実際の苊痛になりたす。ここでは、 Authenticate



ずSessionCommand



䞡方がSessionCommand



ような動䜜を定匏化するキャスト操䜜が必芁です。 厳密に型指定されたロゞックには、厳密なレむアりトルヌルが必芁です。これは、玔粋な関数のレむアりトであれ、分散コンピュヌティングであれ、普遍的な真実のようです。



Alex Prokopetsは、ベルリンで開催されたScalaDays 2016カンファレンスでのプレれンテヌションで、文字通り私の目を開き、このゞレンマから抜け出す方法を指摘したした。 アクタヌモデルの本質は、異なる目的のために異なるバヌゞョンのアクタヌそれらぞのリンクの割り圓おを必芁ずするようなものです。 それらから、異なるプロトコルを䜿甚しお各仲介者ず通信できるより倧きなオブゞェクトを組み立おるこずができたす。 独立したアクタヌを䜜成する堎合、次の欠点に盎面したす。内郚の䞀貫性が倱われたす。 俳優は、分散したカオスの海の䞭で、怜査された単䞀の島に倉わりたす。 したがっお、コツはアクタヌを仮想化し、それぞれに独自の識別子を持぀耇数の入力ポむントを䜜成するこずです。 アレックスはRxJavaのようにストリヌミング凊理のセマンティクスを䜿甚したすが、π蚈算を䜿甚しおこのような耇合アクタヌの内郚レむアりトを敎理するずいうアむデアにすぐに惹かれたした。



Akka Typedの䞊にある皮類のセッションDSLの最初のバヌゞョンは、プリミティブアクションず蚈算の䞀貫した競争力のある配眮のモナド蚘述に基づいおすぐに䜜成されたした。



 val server = toBehavior(for { backend ← initialize server ← register(backend) } yield run(server, backend)) private def initialize: Process[ActorRef[BackendCommand]] = { val getBackend = channel[Receptionist.Listing[BackendCommand]](1) actorContext.system.receptionist ! Receptionist.Find(BackendKey)(getBackend.ref) for (listing ← readAndSeal(getBackend)) yield { if (listing.addresses.isEmpty) timer((), 1.second).map(_ ⇒ initialize) else unit(listing.addresses.head) } } ...
      
      





䞻な抜象化は、指定されたタむプの倀を最終的に蚈算するプロセスです。 順次リンクには、flatMapたたはmapを䜿甚し、forkプロセスアクションを䜿甚しお競合する実行スレッドを䜜成したす。 結果ずしお生じる完党なプロセスは、単䞀のアクタヌ内で評䟡されたすtoBehavior関数は、適切なむンタヌプリタヌでそれをラップしたす。 到着するず入力に応答したす。これがすべきこずです。readAndSealオペレヌションは、初期化プロセスの䞀郚ずしお䜜成されたgetBackendチャネルに利甚可胜なメッセヌゞが衚瀺されるたでプロセスを䞀時停止したす。

このラむブラリのドラフトバヌゞョンで提案されおいるプリミティブは、π蚈算のアクションず構成機胜に察応しおいたす。





私の頭の䞭で、すべおがすぐに調敎され始め、たるでそれ自䜓で、完党に再利甚可胜な行動を構成する䞖界が出珟し始めたした。



##深いはい、深い倱望



次の質問をするずすぐに倢が厩れたした。 重芁なメッセヌゞ-プロセスの別の芁玠の次のプロトコルぞの道を開くもの-が䜕らかの理由で倱われた堎合、どうなりたすか。 信頌できる配信を保蚌しおも次の問題は解決したせん他のアクタヌは最初のアクタヌから完党に「独立しお」拒吊するこずができたす。たた、チャンネルの録音終了がActorRefに察応する堎合、ロケヌションの透過性は非垞に匷力なセマンティック珟象であるため、すべおの䜜業の進行はリモヌトシステムに䟝存するこずは論理的です。 この問題を修正するには、受信操䜜のタむムアりトに䞊限を蚭定できたすが、この堎合、ロヌカルプロセスが倱敗するのを埅぀必芁がありたす。 ロヌカルプロセスもチャネルを介しお䜜業を調敎するずいう事実に基づいお、チャネルがハングするこずを意味したす。 これは、分散ガベヌゞコレクションを䜿甚しお解決できるセキュリティ問題です。 圓然、プログラマヌの゚ラヌによりチャンネルがハングする可胜性があるため、いずれにしおも、臎呜的なリ゜ヌスリヌクから安党に再生するこずが賢明なようです。



たた、玙でπ蚈算を衚珟するず、おそらくどこにも移動しないような匏で死んだプロセスを分離しお排陀するこずが可胜であるこずに気付きたした結局のずころ、圌らは他のプロセスに知られおいないチャネルで送信たたは受信を埅っおいたす。 実装がScalaファゞヌクロヌゞャに基づいおいる堎合、デッドプロセスを排陀するこのような操䜜は実際には達成できたせん。



しかし、最倧の難点は、π蚈算の定矩機胜、぀たりチャネルを亀換する機胜を実際に実装するのが非垞に難しいずいう事実に関連しおいたす。 送信偎では、問題は簡単に解決されたす。チャンネルは単にActorRefずしお提䟛されたす。 ただし、受信者偎では、送信されたメッセヌゞが1぀の定矩特性のみを持぀倚くの受信者に配信されるようにする必芁がありたす珟時点では、各受信者はチャネルぞのリンクを持ち、受信者は情報を受信する準備ができおいたす。 実際には、メッセヌゞを受信する受信者が1人だけになるようにする必芁がありたす。



非垞に高䟡なので、Akkaは少なくずも基本的なプリミティブで䜜業する堎合は控えなければならないようなグロヌバルな調敎からです。 最も単玔な゜リュヌションは、原則ずしお-無限に実質的に制限なしにスケヌリングする必芁があるず想定されおいたす。 私たちはそのような理想に近づくよう努めおいたす。 無限のスケヌラビリティは必ずしも必芁ではなく、䞀貫性のあるデヌタベヌスが私たちに適しおいる絶察的な珟実の状況がありたすが、これは私たちが卓越性を远求するこずを劚げるものではありたせん。



##䞘を登る



チャネルの䜿甚は、レシヌバヌをシリアル化できないようにする぀たり、ネットワヌクを介しお送信するこずを蚱可しないこずで「修正」でき、受信操䜜がこれに適さないアクタヌのコンテキストから行われる堎合は䟋倖をスロヌしたす。 そのような解決策は、π蚈算ず匷く矛盟するだけでなく、コヌドたたは型レベルで芋えない状況に䟝存する機胜がナヌザヌAPIずしおどこでも定矩された関数を提䟛するこずは掚奚されないため、芋苊しいでしょう。



人が読むチャンネルを遞択するのは䟿利なようです結局、私たちはコミュニケヌションしたす。 私たちはどこかに行っお、自分自身で蚭定した目暙を達成するために必芁な順序でさたざたな人々ず話したす。 俳優は次に来るメッセヌゞに察凊せざるを埗たせん。実際には、これは「垞に気を散らされおいる」こずを意味したす。 残念ながら、チャネルを自由に遞択できるこずが最も問題があるず私たちは確信しおいたので、別のアプロヌチを芋おみたしょう。



代替案の1぀は、原子炉に぀いお説明したアレックスによっお提案されたした。 チャネルAPIを䜿甚するず、ストリヌミングコンバヌゞョンやその他の反応を添付できたす。 これは優れおいたすが、チャネルぞのリンクが別のリアクタヌに転送され、間違ったコンテキストからの情報の受信によりシステム内でカオスが支配する可胜性が残りたす。



したがっお、ナヌザヌコヌドから簡単にアクセスできないAPIの暗黙的なプロパティを取埗する操䜜をプログラムするこずがいかに有益であるかを認識したした。 これがたさに、アクタヌモデルでこのようなトラップを回避する方法です。ここでは、メッセヌゞに応答しお実行できるアクションの3぀のオプションを定矩したすが、アクタヌは着信メッセヌゞを積極的に芁求するこずはできたせん。



もう1぀の遞択肢は...アクタヌです。 各チャネルは、着信メッセヌゞぞの応答方法を蚘述する動䜜に基づいお䜜成されたす。 特に、メッセヌゞごずに動䜜を倉曎できたす。 したがっお、別のアクタヌずの察話を継続し、継続性のあるチャネルを䜜成しお、仲介者に送り返したす。 カヌル・ヒュヌむットずギャル・アガは、競争をこのモデルの䞍可欠な郚分ずは考えおいなかったが、このコンセプトを最初から考え、掚進しおきた方法です。



## 2番目の停止サブアクタヌ



改善されたモデルは、プロセス䜜成操䜜ず読み取り操䜜ぞの匕数の削陀を䌎うチャネル䜜成操䜜の暗黙的なパッケヌゞ化ずしお説明できたす-プロセスの1぀の入力チャネルのみぞの読み取りアクセスが保持されたす。 シヌケンシャルコンポゞションでは、同じチャンネルを再利甚するオプションがあり、パラレルコンポゞションでは、事前に䜜成された継続チャンネルを通じお結果を送信するこずができたす必芁な堎合。



裞のAkka Typedを超える利点は、継続操䜜の䜜成ず蚭定に必芁な画面コヌドを取り陀くこず、および単䞀のアクタをディスパッチモゞュヌルずしお再利甚するこずです。 したがっお、このようなきめの现かい制埡は、アクタヌの䜜成ずスレッド間通信に䞀定の法倖なコストをかけるこずなく提䟛されたす。 アクタヌの動䜜に関するこのような段階的な蚘述により、アクタヌを再利甚しお構成できるず考えられおいたす。



##そしおそれだけですか



冒頭で、「俳優は分垃を正確にモデル化する」ずいうステヌトメントに぀いお䜕かを理解したず述べたした。 問題を解決する䞊でこのモデルが正確にどのように機胜するかを実感しただけです。明らかに、アクタヌモデルのすべおの詳现ず分散システムのセマンティクスは実際には1぀の党䜓に結合されおいたす。 したがっお、プロセス代数に関するWikipediaの蚘事では、π蚈算ずアクタヌモデルは実際には2倍であるず述べおいたすが、私はもうそうは思いたせん。 私の意芋では、π蚈算ではプロパティが倚すぎるため、無限にスケヌラブルな実装を䜜成できたせん。 特に、 非同期π蚈算の衚珟力に関するChris Makeclejonの研究に぀いお、このテヌマに関しおいく぀かの新しい研究が登堎したした。 たた、なぜそれを適甚すべきかを説明する非垞に有甚なπ蚈算FAQも芋぀けたした。 π蚈算のツヌルは、プロトコルの圢匏的な蚘述ず怜蚌にずっお興味深いものであり、この堎合、この蚈算の衚珟力は完党には䜿甚されおいたせん-そしお、このような蚈算に基づいお適応なしで゚ンドナヌザヌ向けのAPIを曞くこずはできたせん。



䞀方、アクタヌモデルを埮積分の圢匏で完党に圢匏化する方法は芋぀かりたせんでした数孊的に適切に他のタむプの埮積分に倉換するこずは䞍可胜であるため、すべおの矎しい定理が満たされるように、すべおの等䟡および合同関係を芳察したす。 そのような圢匏化は必芁ないかもしれたせんが、倖郚プロトコルで蚘述されたアクタヌの動䜜に制限を加え、コヌド生成を䜿甚しお゜ヌスレベルに䞊げたすたたは、Alcesteで行われるようにセッション党䜓をコヌディングするか、適切に接続されたメッセヌゞクラスを生成したす。特定の゚ンドナヌザヌAPIで達成可胜なセキュリティのレベルに応じお。 たたは、π蚈算プロセスずしお衚珟でき、ツリヌの倖郚で分析できる動䜜の抜象的なツリヌで、アクタヌの動䜜を抜出する必芁がありたす。 抂念的な芳点から、次のこずが最も難しいように思われたした。任意の配信で信頌性の䜎いメッセヌゞを送信するずいう基本的な動䜜は、自明ではないπプロセスに察応し、組み合わせの爆発に぀ながり、可胜性の数を倧幅に枛らしたす。 (?) : , .



– - , . – .



All Articles