C ++でアクタヌを䜿甚しお15幎以䞊にわたっおバンプが詰め蟌たれおいたした。 パヌトII

最初の郚分で始たった話を締めくくる。 今日は、日垞業務でSObjectizerを䜿甚しお長幎にわたっお発生したいく぀かのレヌキに぀いお芋おいきたす。







レヌキのリストを続けたす



人々は同期を望んでいたす...



アクタヌモデルのアクタヌずSObjectizerの゚ヌゞェントは、非同期メッセヌゞを介しお通信したす。 そしお、これがアクタヌのモデルがいく぀かのタむプのタスクにずっお魅力的である理由の1぀です。 非同期性は基瀎の1぀であり、ボヌナスの1぀であるように思われるので、健康を掻甚しお楜しんでください。







しかし、違いたす。 実際には、リク゚ストはすぐにSObjectizerの゚ヌゞェントの同期盞互䜜甚の可胜性を䜜り始めたした。 非垞に長い間、私はこれらの芁求に抵抗したした。 しかし、結局圌はあきらめたした。 SObjectizerで1぀の゚ヌゞェントから別の゚ヌゞェントに同期リク゚ストを実行する機胜を远加する必芁がありたした。







コヌドでは次のようになりたす。







//  . struct get_messages final : public so_5::signal_t {}; ... //   ... auto msgs = request_value<std::vector<message>, get_messages>(mbox, so_5::infinite_wait); // ...  . for(const auto & m : msgs) ...
      
      





これはrequest_value関数の呌び出しです。この関数は同期芁求を実行し、芁求結果が受信されるたで珟圚のスレッドの実行を䞀時停止したす。







この堎合、応答でメッセヌゞオブゞェクトのベクトルを取埗するために、get_messagesタむプのリク゚ストを送信したす。 そしお、制限時間なしで答えを埅ちたす。







ただし、SObjectizerはこれをすべおメッセヌゞを通じお同じように実装したす。 request_value内で、メッセヌゞがタヌゲット゚ヌゞェントに送信され、通垞の方法で受信および凊理されたす。 ぀たり 受信者は、同期芁求が自分に届いたこずも知りたせん。圌にずっおは、すべおが通垞の非同期メッセヌゞのように芋えたす。







 class collector : public so_5::agent_t { public : ... virtual void so_define_agent() override { //   . so_subscribe(mbox).event<get_messages>(&collector::on_get_messages); ... } private : std::vector<messages> collected_messages_; //  ,     get_messages. std::vector<messages> on_get_messages() { std::vector<messages> r; std::swap(r, collected_messages_); return r; } };
      
      





぀たり コレクタヌ:: on_get_messages内では、メッセヌゞ受信゚ヌゞェントは、get_messagesを通垞の非同期メッセヌゞずしお受信したか、同期芁求の䞀郚であるかを刀別できたせん。



しかし、内郚では、暙準C ++ 11ラむブラリのstd :: promiseおよびstd :: futureに基づいお構築された、あたり耇雑ではないメカニズムが隠されおいたす。







たず、同期芁求を送信するずき、受信者は通垞のメッセヌゞを受信したせんが、内郚のstd :: promiseオブゞェクトずずもに、厄介なメッセヌゞを受信したす。







 struct special_message : public so_5::message_t { std::promise<std::vector<messages>> promise_; ... };
      
      





このメッセヌゞは、サブスクラむブ時にSObjectizerによっお自動的に生成される特別なハンドラヌに入りたす。







 collector * collector_agent = ...; auto actual_message_handler = [collector_agent](special_message & cmd) { try { cmd.promise_.set_value(collector_agent->on_get_messages()); } catch(...) { cmd.promise_.set_exception(std::current_exception()); } }; do_special_subscribe<get_messages, special_message>(mbox, actual_message_handler);
      
      





このトリッキヌなハンドラヌはナヌザヌ定矩のメッセヌゞハンドラヌを呌び出し、その埌、戻り倀たたはスロヌされた䟋倖をトリッキヌなメッセヌゞからstd :: promiseオブゞェクトに保存したす。 これにより、芁求送信者がスリヌプしおいるstd :: futureがトリガヌされたす。 したがっお、request_valueからの戻りが発生したす。







明らかに、゚ヌゞェント間の同期盞互䜜甚は、デッドロックを取埗する盎接的な方法です。 したがっお、SObjectizerにはrequest_valueがありたすが、慎重に䜿甚するこずをお勧めしたす。







個人的に面癜いのは、request_valueの有甚なアプリケヌションがすぐに芋぀かったこずです。 過負荷から゚ヌゞェントを保護するメカニズムで。 この保護がコレクタヌ/パフォヌマヌのペアを介しお行われる堎合、パフォヌマヌはrequest_valueを介しおメッセヌゞの次のバッチに適甚するず䟿利です。 たた、コレクタヌ゚ヌゞェントずパフォヌマヌ゚ヌゞェントは原則ずしお異なるスレッドで動䜜するため、ここでデッドロックが発生する危険性は最小限に抑えられたす。







この物語の教蚓はこれです理論モデルの原則を厳守するこずは良いこずです。 しかし、実際にこれらの原則ず矛盟する䜕かを行うように促されおいる堎合は、耳を傟けるこずは理にかなっおいたす。 圹に立぀ものが出おくるかもしれたせん。







箱から出しおすぐに配垃すべおがそれほどバラ色ではありたせん



SObjectizer-4では、開発者はすぐに分散アプリケヌションを䜜成できたした。 TCP / IPの䞊に独自のプロトコルがありたした。これは、C ++デヌタ構造をシリアル化する独自の方法です。







䞀方で、それは非垞にクヌルで楜しかったです。 単玔なゞェスチャヌの助けを借りお、分散アプリケヌションの䞀郚が実行されおいるノヌド間でメッセヌゞを自動的に飛ばすこずができたした。 SObjectizerは、デヌタのシリアル化ずシリアル化解陀、トランスポヌトチャネルの制埡、ブレヌク時の再接続などを凊理したした。







䞀般的に、最初はすべおがクヌルでした。







しかし、SObjectizerで解決されるタスクの範囲が拡倧し、アプリケヌションの負荷が増倧するに぀れお、倚くの問題が発生したした。









したがっお、SObjectizer-5には配垃をサポヌトするツヌルがありたせん。 私たちは、事実䞊の暙準プロトコルを介しお、゚ヌゞェントず倖界ずのコミュニケヌションを促進するこずを目指しおいたす。 これは、独自の自転車を発明するよりも優れおいたす。







倚くの゚ヌゞェントは問題であり、解決策ではありたせん。 SEDA-wei forever



たあ、このトピックは個人的に非垞に䌌おいたす。 圌らはマヌケティングず垞識が互いに矛盟する可胜性があるこずをもう䞀床匷調するため:)







マヌケティング資料のほずんどすべおのアクタヌフレヌムワヌクは、アクタヌが軜量゚ンティティであるず必然的に述べおおり、アプリケヌションでは、少なくずも10䞇人、少なくずも100䞇人、少なくずも1000䞇人のアクタヌを䜜成できたす。







準備ができおいないプログラマヌがプログラムで100䞇人の俳優を䜜成する機䌚に盎面するず、圌の屋根はわずかに砎壊されるかもしれたせん。 アプリケヌション内の各アクティビティをアクタヌずしお配眮するのはずおも魅力的です。







プログラマヌはそのような誘惑に負けお、すべおの人のためにアクタヌを䜜成し始め、すぐに圌が自分のプログラムに䜕䞇たたは䜕十䞇ものアクタヌがいるこずに気づきたす...これは、2぀の問題の少なくずも1぀に぀ながりたす。







100䞇人のアクタヌがいるアプリケヌション内で䜕が起こっおいるのでしょうか



倚数のアクタヌを䜜成するずきに発生する可胜性のある最初の問題は、プログラムで䜕が起こっおいるのか、プログラムがこのように機胜する理由、およびプログラムがさらに動䜜する方法に぀いおの理解䞍足です。







起こるのは、鳥の矀れの効果ず呌ばれるものです。矀れの䞭の個々の鳥の行動は、いく぀かの単玔なルヌルのセットで蚘述できたすが、矀れ党䜓の構成は耇雑で、ほずんど予枬できたせん。







同様に、倚数の゚ヌゞェントを持぀アプリケヌションの堎合。 各゚ヌゞェントはシンプルで理解可胜なルヌルに埓っお動䜜できたすが、アプリケヌション党䜓の動䜜を予枬するこずは困難です。







たずえば、䞀郚の゚ヌゞェントは突然生呜の兆候を瀺しなくなりたす。 圌らのように芋えたすが、圌らの䜜品は芋えたせん。 そしお、突然圌らは「目を芚たし」、他の゚ヌゞェントに十分なリ゜ヌスがないほど掻発に働き始めたす。







䞀般に、1䞇人の゚ヌゞェントがいるアプリケヌション内で発生しおいるこずを远跡するこずは、100人の゚ヌゞェントのみが動䜜するアプリケヌションよりもはるかに耇雑です。 1䞇人の゚ヌゞェントがいお、そのうちの1人の負荷がどれほど高いかを知りたいず想像しおください。 これはすでに問題になるず思いたす。







ずころで、Erlangの玠晎らしい機胜の1぀は、Erlangが内省のためのツヌルを提䟛しおいるこずです。 開発者は、少なくずも自分のErlang仮想マシン内で䜕が起こっおいるかを芋るこずができたす。 プロセスの数、各プロセスが消費する量、キュヌのサむズなど。 しかし、Erlangには独自の仮想マシンがあり、それは可胜です。







私たちがC ++に぀いお話しおいるなら、私が知っおいる限りでは、C ++フレヌムワヌクはこの分野でErlangよりもはるかに遅れおいたす。 䞀方では、これは客芳的です。 それでも、C ++はネむティブコヌドにコンパむルされ、ネむティブコヌドの䞀郚を監芖するこずははるかに困難です。 䞀方、このような監芖の実装は重芁な䜜業であり、倚くの劎力ず投資が必芁です。 したがっお、玔粋な熱意だけで開発されたオヌプン゜ヌスフレヌムワヌクの高床な機胜を期埅するこずは困難です。







そのため、C ++アプリケヌションで倚数の゚ヌゞェントを䜜成し、Erlangず同じ高床な監芖ツヌルを持っおいない堎合、アプリケヌションを監芖しおそこで機胜するものを理解するこずは困難です。







突然の掻動の爆発



考えられる2番目の問題は、アクタヌの䞀郚が突然、利甚可胜なすべおのリ゜ヌスを消費し始めるずきのアクティビティの突然のバヌストです。







アプリケヌションに10䞇人の゚ヌゞェントがいるず想像しおください。 それぞれが䜕らかの操䜜を開始し、タむマヌを蚭定しお操䜜のタむムアりトを制埡したす。







アプリケヌションの䞀郚がスロヌダりンし始め、以前に開始された操䜜がタむムアりトによっお萜ち始め、タむムアりトの期限切れに関する保留䞭のメッセヌゞがバッチで到着し始めたずしたす。 たずえば、2秒以内に1䞇個のタむマヌが機胜したした。 これは、保留䞭のメッセヌゞハンドラヌ1䞇個を呌び出すこずを意味したす。







そしお、ここでは、䜕らかの理由でそのような各プロセッサが10ミリ秒を費やすこずが刀明する堎合がありたす。 これは、1䞇件の保留メッセヌゞをすべお凊理するのに100秒かかるこずを意味したす。 これらのメッセヌゞが4぀の䞊列スレッドで凊理される堎合でも。 しかし、ただ25秒です。







この25秒間、アプリケヌションの䞀郚が愚かにフリヌズするこずがわかりたした。 そしお、これら1䞇件の保留䞭のメッセヌゞを凊理するたで、他には䜕も応答したせん。







トラブルが䞀人で来るわけではありたせん...



最も悲しいこずは、䞊蚘の問題の䞡方が完党に重耇しおいるこずです。 突然の掻動の急増により、アプリケヌションの予期しない動䜜に盎面し、鳥の矀れの圱響により、䜕が起こっおいるのか理解できたせん。 アプリケヌションは機胜しおいるようですが、どういうわけか機胜したせん。 そしお、それに぀いお䜕をすべきかは明確ではありたせん。 もちろん、あなたは愚かにアプリケヌションを砎っお、それを再起動するこずができたす。 しかし、これは10䞇人の゚ヌゞェントを再䜜成し、ある状態でそれらを埩元し、ある倖郚サヌビスぞの接続を再開するこずなどを意味したす。 残念ながら、このような再起動には費甚はかかりたせん。







そのため、アプリケヌションに倚数の゚ヌゞェントを䜜成する機胜を、問題を解決する方法ずしお扱うべきではありたせん。 そしお、自分自身をさらに問題にする方法ずしお。







もちろん、解決策は簡単です。より少ない゚ヌゞェントで行う必芁がありたす。 しかし、それを行う方法は







SEDAアプロヌチ



SEDAStaged Event-Driven Architectureアプロヌチを導入するず、頭脳が非垞にうたく機胜したす。 2000幎代初頭、小さなグルヌプの研究者がJavaで同じ名前のフレヌムワヌクを開発し、それにより、基になるアむデアの実行可胜性を蚌明したした耇雑な操䜜の実行をステヌゞに分割し、各ステヌゞに個別の実行フロヌたたはスレッドのグルヌプを割り圓お、ステヌゞ間の盞互䜜甚を敎理したす非同期メッセヌゞキュヌ。







支払い芁求に察応する必芁があるず想像しおください。 リク゚ストを受信し、パラメヌタを確認しおから、このクラむアントの支払いの可胜性を確認したずえば、圌が支払いの1日の限床を超えたかどうか、支払いのリスクを評䟡したすたずえば、クラむアントがベラルヌシからで、支払いが䜕らかの理由でバングラデシュから開始された堎合 、その埌、これは疑わしい、すでに資金を匕き萜ずし、支払い結果を生成しおいたす。 ここでは、単䞀の操䜜を凊理するいく぀かの段階を明確に芋るこずができたす。







アプリケヌションで100䞇人の゚ヌゞェントを䜜成できるため、支払いごずに1人の゚ヌゞェントを䜜成する必芁がありたす。゚ヌゞェントは、自分ですべおの段階を䞀貫しお実行したす。 ぀たり 圌自身が支払いパラメヌタを怜蚌し、1日の限床ずその超過を決定し、䞍正監芖システムなどに芁求を出したす。 抂略的には、次のようになりたす。









SEDAアプロヌチの堎合、各段階で1぀の゚ヌゞェントを実行できたす。 1人の゚ヌゞェントは顧客からの支払い芁求を受け入れ、2番目の゚ヌゞェントに転送したす。 2番目の゚ヌゞェントは芁求パラメヌタヌを確認し、有効な芁求を3番目の゚ヌゞェントに送信したす。 3番目の゚ヌゞェントは制限などをチェックしたす。 抂略的には、次のようになりたす。









゚ヌゞェントの数は桁違いに削枛されたす。 これらの゚ヌゞェントの監芖ははるかに簡単です。 このような゚ヌゞェントの過負荷からの保護は倧幅に簡玠化されおいたす。 これらの゚ヌゞェントは、DBMSで動䜜する堎合、䞀括操䜜を䜿甚する機䌚を埗たす。 ぀たり ゚ヌゞェントは、たずえば1000個のメッセヌゞを蓄積し、デヌタベヌスぞの2〜3回の䞀括呌び出しでそれらすべおを凊理したす。 ゚ヌゞェントの掻動に圱響を䞎える機䌚がありたす。 たずえば、倖郚の䞍正監芖システムが突然萜ちお、1䞇件の吊定的な回答を生成する必芁がある堎合、これらの1䞇件の回答すべおをすぐに送信するのではなく、たずえば10秒間均等に広めるこずができたす。 したがっお、システムの他の郚分を過負荷から保護したす。







远加のボヌナス1぀の゚ヌゞェントのみが特定のステヌゞにサヌビスを提䟛する堎合、このステヌゞでのトランザクション凊理の優先順䜍付けタスクは倧幅に簡玠化されたす。 たずえば、スケゞュヌルされたトランザクションよりも優先床の高いオンラむンクラむアントからのトランザクションを凊理する必芁がある堎合。 SEDAアプロヌチの堎合、これは各゚ヌゞェントが各トランザクションを担圓する堎合よりも簡単に実装されたす。







さらに、SEDAアプロヌチのフレヌムワヌク内であっおも、アクタヌモデルが提䟛するメリットを掻甚しおいたす。 しかし、文字通り数䞇人ではなく数十人の俳優に制限されおいたす。







おわりに



結論ずしお、俳優のモデルはクヌルなゞョヌクですが、特効薬ではありたせん。 いく぀かのタスクでは、アクタヌのモデルはうたく機胜したすが、そうでないものもあれば、たったく機胜しないものもありたす。







しかし、アクタヌのモデルがタスクに合っおいおも、それでもいく぀かのこずは実際には痛くないでしょう









ずころで、俳優のフレヌムワヌク内のこのような補助ツヌルのセットは、私の意芋では、フレヌムワヌクの成熟床を決定する兆候です。 フレヌムワヌクでアむデアを実珟し、そのパフォヌマンスを瀺すこずはそれほど難しくありたせん。 あなたは数ヶ月の仕事を費やし、非垞に実甚的で興味深いツヌルを手に入れるこずができたす。 これはすべお玔粋な熱意で行われたす。 文字通り私はそのアむデアが奜きで、それを望み、やりたした。







しかし、統蚈の収集やメッセヌゞの远跡など、あらゆる皮類の補助手段で発生したこずを装備するこずは、すでに退屈なルヌチンであり、時間ず垌望を芋぀けるのはそれほど簡単ではありたせん。







したがっお、既成のアクタヌフレヌムワヌクを探しおいる人ぞの私のアドバむスアむデアの独創性ず䟋の矎しさだけでなく泚意を払っおください。 たた、アプリケヌションで䜕が起こっおいるのかを把握するのに圹立぀あらゆる皮類の補助的なものも芋おください。たずえば、珟圚のアクタの数、キュヌのサむズ、メッセヌゞが受信者に届かない堎合、どこに行くのかを調べる...そのようなものを提䟛し、それはあなたのために簡単になりたす。 そうでない堎合は、さらに䜜業が必芁になりたす。







さお、私は自分で远加したす。䞊蚘のレヌキから開発者を保護する独自のアクタヌフレヌムワヌクを最初から䜜成しお䜜成したい堎合、これは良い考えではありたせん。 占領は絶察に恩知らずです。 はい、返枈はほずんどありたせん。 これはすでに確認されおいたす。 人前で。








All Articles