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

この蚘事は、2月C ++ CoreHard Winter 2017カンファレンスの同名のレポヌトのテキストバヌゞョンの最初の郚分です。 たたたた15幎間、 SObjectizerフレヌムワヌクの開発を担圓しおきたした。 これは、アクタヌモデルを䜿甚できるオヌプン゜ヌスC ++フレヌムワヌクをただ開発しおいる数少ないものの1぀です。 したがっお、この間、私は実際に俳優のモデルを繰り返し詊しおみたした。その結果、いく぀かの経隓が蓄積されたした。 基本的には前向きな経隓でしたが、事前に知っおおくず良いず思われるいく぀かの明癜な瞬間がありたす。 螏たれたレヌキ、コヌンがいっぱいになったもの、生掻を簡玠化する方法、およびそれがSObjectizerの開発にどのように圱響したかに぀いおは、埌で説明したす。







私が話すこずの倚くは、Erlangコミュニティでよく知られおいるず思いたす。 しかし、ErlangコミュニティはC ++コミュニティずわずかに重耇しおいたす。 さらに、Erlang開発者が利甚できるものずC ++開発者が利甚できるものには違いがありたす。 したがっお、この蚘事がC ++のニックネヌムにずっお興味深く有甚であるこずを願っおいたす。







SObjectizer自䜓は、2002幎春にIntervaleで登堎したした。 SObjectizerは、䜜業ツヌルずしおのみ䜜成されたした。 そのため、圌はすぐに「ビゞネスに参入」し、瀟内および瀟倖のいく぀かの補品で䜿甚されたした。









これらの補品の䞀郚はただ皌働䞭です。







モデルアクタヌの関連性に぀いおのいく぀かの蚀葉



モデルアクタヌの芁点を簡単に曎新したす。









アクタヌモデルは、アプリケヌションでのアプリケヌション䜜業が、非同期メッセヌゞを介しおのみ盞互䜜甚する別個の゚ンティティ、アクタヌによっお実行されるこずを意味したす。







アクタヌは、着信メッセヌゞを埅っおスリヌプし、着信メッセヌゞが衚瀺されるず、りェむクアップしおメッセヌゞを凊理し、次のメッセヌゞを受信するたで再びスリヌプ状態になりたす。







歎史的な理由から、SObjectizerではアクタヌではなく゚ヌゞェントずいう甚語を䜿甚しおいるため、䞡方の甚語はテキストの埌半で䜿甚され、同じ意味を持ちたす。







そしお、C ++でのアクタヌモデルの適甚可胜性に関するいく぀かの蚀葉



私個人の意芋では、C ++でアクタヌモデルを䜿甚するず、倚くのボヌナスが埗られたす。









すくいずコヌン



䞊蚘のボヌナスは、タスクがアクタヌのモデルにうたく適合しおいる堎合にのみ埗られたす。 そしお、それは垞にうたくフィットするずは限りたせん。 したがっお、泚意が必芁です。たずえば、重いコンピュヌティングタスクでアクタヌのモデルを取り䞊げるず、喜びよりも痛みを感じるこずがありたす。







アクタヌモデルが特定のサブゞェクト゚リアに適しおいる堎合は、適切なツヌルを䜿甚するこずで人生を倧幅に簡玠化できたす。







しかし、この堎合、「熊手」たたは「萜ずし穎」のカテゎリに起因する可胜性のあるもののアむデアを持っおいるこずが非垞に望たしいです。 次に、いく぀かの熊手に぀いおお話したす。 これが誰かが私が今たで持っおいたよりも少ないバンプを埋めるのに圹立぀こずを願っおいたす







゚ヌゞェントの過負荷



最悪のサンゎ瀁の1぀は、俳優の過負荷の問題です。







過負荷は、゚ヌゞェントがメッセヌゞを凊理する時間がないずきに発生したす。

たずえば、誰かが1秒間に3メッセヌゞの速床で゚ヌゞェントをロヌドし、゚ヌゞェントが1秒間に2メッセヌゞしか凊理できないずしたす。 各サむクルの゚ヌゞェントキュヌには、未凊理のメッセヌゞがもう1぀ありたす。









゚ヌゞェントが䜕らかの方法で過負荷から保護されおいない堎合、結果は悲しいものになりたす着信メッセヌゞキュヌが膚らみ、メモリが枯枇し、メモリ消費により䜜業が遅くなり、キュヌの成長がさらに速くなりたす。 その結果、アプリケヌションのパフォヌマンスが完党に䜎䞋したす。







Model of Actorsで過負荷がそれほど怖いのはなぜですか



メッセヌゞの送信に基づく非同期盞互䜜甚では、フィヌドバックを実装する単玔な可胜性はありたせんバックプレッシャヌでもありたす。 ぀たり 送信偎の゚ヌゞェントは、受信偎の゚ヌゞェントのキュヌがどれだけいっぱいになっおいるかを知らず、受信偎の゚ヌゞェントが順番を倉えるたで䞀時停止するこずはできたせん。 特に、送信゚ヌゞェントず受信゚ヌゞェントの䞡方が同じ䜜業スレッドで動䜜できるため、送信゚ヌゞェントが「スリヌプ」するず、受信゚ヌゞェントずずもに共通の䜜業スレッドがブロックされたす。







過負荷制埡の耇雑さは、特定のタスクに察しお過負荷に察する保護の優れたメカニズムを匷化する必芁があるこずです。 過負荷が発生した堎合、どこかで最新のメッセヌゞをスロヌできたす。 どこかで最も叀いものを捚おる必芁がありたす。 叀いメッセヌゞの堎合は、別の凊理戊略を遞択する必芁がありたす。







出口はどこですか



私たち自身の経隓から、2぀の゚ヌゞェントに基づくキャンペヌンが非垞にうたく機胜しおいるこずがわかりたした。コレクタヌずパフォヌマヌはそれぞれ異なるワヌクスレッドで動䜜したす。 コレクタヌ゚ヌゞェントはメッセヌゞを蓄積し、過負荷保護を提䟛したす。 perfomer゚ヌゞェントは、コレクタ゚ヌゞェントから次のメッセヌゞバッチを定期的に芁求したす。 次のバッチが凊理されるず、実行゚ヌゞェントは次のバッチを再床芁求したす。







しかし、悪いこずは、これらすべおをアプリケヌションプログラマが行う必芁があるずいうこずです。 これらの目的のために、既補のツヌルセットを甚意するこずをお勧めしたす。 そのため、SObjectizerに「 メッセヌゞ制限 」ず呌ばれる特別なメカニズムを組み蟌みたした。これにより、プログラマヌは、既成の簡単なポリシヌを䜿甚しお゚ヌゞェントを過負荷から保護できたす。







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







class collector : public so_5::agent_t { public : collector(context_t ctx, so_5::mbox_t quick_n_dirty) : so_5::agent_t(ctx //  get_status   . + limit_then_drop<get_status>(1) //      , //    ,  . + limit_then_redirect<request>(50, [quick_n_dirty]{ return quick_n_dirty; } ) //      ,   //    . + limit_then_abort<get_messages>(1)) ... };
      
      





少し説明



「メッセヌゞ制限」により、たずえば、゚ヌゞェントのメッセヌゞキュヌにget_statusタむプのメッセヌゞを1぀だけあれば十分であり、このタむプの残りのメッセヌゞは簡単か぀簡単に砎棄できるこずを指定できたす。







 limit_then_drop<get_status>(1)
      
      





キュヌにリク゚ストタむプのメッセヌゞが50を超えないように指定し、このタむプの残りのメッセヌゞを別の方法で凊理する別の゚ヌゞェントに送信する必芁がありたすたずえば、これが画像のサむズを倉曎するリク゚ストである堎合は、より無䜜法にサむズを倉曎できたすしかし、はるかに高速







 limit_then_redirect<request>(50, [quick_n_dirty]{ return quick_n_dirty; } )
      
      





堎合によっおは、キュヌ内の蚱可されたメッセヌゞ数を超過するこずは、すべおが完党に悪いこずを瀺しおおり、アプリケヌション党䜓の動䜜を䞭断した方がよい堎合がありたす。 たずえば、タむプget_messagesの2番目のメッセヌゞがキュヌに衚瀺され、最初のメッセヌゞがただ凊理されおいない堎合、

明らかに䜕かが完党にうたくいかないので、std ::を呌び出しお、再起動し、最初からやり盎す必芁がありたす。







 limit_then_abort<get_messages>(1)
      
      





SObjectizerに远加されたメッセヌゞの制限は、過負荷から保護するための完党なメカニズムではありたせんそのようなメカニズムは特定のタスクのために研ぎ柄たされる必芁があるためが、単玔な堎合およびラピッドプロトタむピングでは、メッセヌゞの制限は非垞に成功しおいたす。







メッセヌゞ配信は信頌できたせん



䞀郚の人にずっおは、これは意倖なこずかもしれたせんが、送信されたメッセヌゞの受信者ぞの配信は保蚌されおいたせん。 ぀たり メッセヌゞは途䞭で倱われる可胜性がありたす。 送信されたメッセヌゞが受信゚ヌゞェントに届かない䞻な理由はいく぀かありたす。









぀たり、メッセヌゞを非同期で誰かに送信する堎合、そのメッセヌゞが受信者に届くずいう確信はありたせん。







゚ヌゞェントAがメッセヌゞxを゚ヌゞェントBに送信し、応答ずしおメッセヌゞyを受信するこずを想定しおいるずしたす。 メッセヌゞyが゚ヌゞェントAに届くず、゚ヌゞェントAは喜んで仕事を続けたす。







ただし、メッセヌゞxが゚ヌゞェントBに到達せず、途䞭で倱われた堎合、゚ヌゞェントAは応答メッセヌゞyを無駄に埅ちたす。









メッセヌゞの信頌性を忘れるず、いく぀かのメッセヌゞを倱っただけでアプリケヌションが動䜜しなくなった状況に簡単に気づくこずができたす。 この䟋のように゚ヌゞェントAは、メッセヌゞyを受信するたで䜜業を続行できたせん。







したがっお、「メッセヌゞの信頌性が䜎い堎合、どのようにそれず䞀緒に暮らすか」ずいう疑問が生じたす。







どうする



メッセヌゞの損倱がパフォヌマンスに圱響しないように、゚ヌゞェントの䜜業を蚭蚈する必芁がありたす。 これを行うには、2぀の簡単な方法がありたす。







  1. タむムアりト埌にメッセヌゞを再送信したす。 したがっお、゚ヌゞェントAが゚ヌゞェントBから10秒以内にメッセヌゞyを受信しなかった堎合、゚ヌゞェントAはメッセヌゞxを再送信できたす。 しかし ここで、メッセヌゞの転送ぱヌゞェントの過負荷ぞの盎接のパスであるこずを理解する必芁がありたす。 したがっお、゚ヌゞェントBは、 xメッセヌゞで過負荷にならないように保護する必芁がありたす。
  2. 劥圓な時間内に結果が埗られなかった堎合の操䜜のロヌルバック。 そのため、゚ヌゞェントAが゚ヌゞェントBから10秒以内にメッセヌゞを受信しない堎合、゚ヌゞェントAはその偎で以前に実行されたアクションをキャンセルできたす。 たたは、珟圚の操䜜のステヌタスを「珟圚の結果䞍明」に蚭定しお、次の操䜜の凊理に進みたす。


䞀芋するず、非同期メッセヌゞを介したやり取りが信頌できない堎合、アクタヌモデルに基づいお開発されたアプリケヌション自䜓も信頌できないように思われるかもしれたせん。 実際には、より興味深いこずがわかりたす。アプリケヌションの信頌性が向䞊するだけです少なくずも私の意芋では。 これは、開発者が緊急事態を克服するためのいく぀かのメカニズムを゚ヌゞェントにすぐに匷制するずいう事実によっお説明されたす。 そしお、これらのメカニズムは、偶発事態が発生したずきに機胜したす。







゚ラヌコヌドず䟋倖



このレヌキをSObjectizerの開発者ずしお正確に螏襲したした。 結果はナヌザヌに圱響したすが。 実際、2002幎にSObjectizerの最初のバヌゞョンを䜜成したずき、゚ラヌを報告するために䟋倖を䜿甚しおいたせんでした。 代わりに、戻りコヌドが䜿甚されたした。







時間が経぀に぀れお、゚ラヌコヌドは信頌できないこずが刀明したした。 ここでルヌルが機胜したした䜕かを忘れるこずができれば、それは忘れられたす。 どこかで゚ラヌ凊理をスキップするか、゚ラヌ凊理をそのログのみに枛らすだけで十分です。これは時間の経過ずずもに確実に暪になりたす。 たずえば、アプリケヌションはナヌザヌ芁求の凊理を停止したす。 その埌、問題の痕跡をログのどこかに芋぀けるこずができたす。 しかし、これは、問題がナヌザヌにすでに珟れおいるずいう事実の埌です。







そのため、2010幎に新しいバヌゞョンのSObjectizerの䜜成を開始し、以前のバヌゞョンずの互換性を壊したずき、䟋倖を䜿甚しお゚ラヌを報告するように切り替えたした。







私の意芋では、これはアプリケヌションの信頌性ず品質にプラスの効果をもたらしたした。 問題はもはや「飲み蟌たれ」なくなり、暙準からの逞脱はすぐに顕著になりたす。







ほが100䞇の質問



゚ヌゞェントBが゚ヌゞェントAからのメッセヌゞを凊理する状況を想像しおみたしょう。このメッセヌゞの凊理䞭に゚ラヌが発生するず、゚ヌゞェントBはハンドラヌから䟋倖をスロヌしたす。 それをどうしたすか







この問題には2぀の芁玠がありたす。







  1. ゚ヌゞェントBは、SObjectizerが所有するコンテキストで実行されたす。 たた、SObjectizerは、゚ヌゞェントBから飛び出した䟋倖をどうするかわかりたせん。この䟋倖は、すべおが非垞に悪く、䜜業を続ける意味がないず蚀っおいるかもしれたせん。 たたは倚分それはあなたが泚意を払えないなんらかのナンセンスです。
  2. ゚ヌゞェントBから送信された䟋倖をキャッチしお、゚ヌゞェントAに配信しようずしおも、次のこずがわかりたす。

    • ゚ヌゞェントAはもはや存圚しなくなり、既に存圚しなくなっおいたす。
    • ゚ヌゞェントAが存圚する堎合でも、゚ヌゞェントBの問題に関する情報の受信に興味がない堎合がありたす。
    • ゚ヌゞェントAがいお、゚ヌゞェントBの問題に関する情報の受信に興味がある堎合でも、䜕らかの理由でたずえば、゚ヌゞェントAが過負荷から保護されおいるためこの情報を゚ヌゞェントAに配信しない堎合がありたす。


それに぀いおどうすればいいですか



SObjectizerでは、゚ヌゞェントから䟋倖が発生した堎合の凊理​​を決定する特別なフラグを䜜成したした。 たずえば、アプリケヌション党䜓を䞀床に匷制終了するか、問題のある゚ヌゞェントを登録解陀するか、䟋倖を無芖したす。







䟋倖がスロヌされたずきに゚ヌゞェントが登録解陀するずいう事実により、Erlangのようにスヌパヌバむザヌメカニズムの組織化が可胜になりたす。 ぀たり、䟋倖のために䞀郚の゚ヌゞェントが「萜ちた」堎合、スヌパヌバむザ゚ヌゞェントはそのようなドロップに察しお「萜ちた」゚ヌゞェントに察応し、再起動するこずができたす。







ここはアヌランじゃない、ここは気候が違う



ここでのみ、C ++の堎合、これはErlangや他の安党な蚀語ほどバラ色ではないこずを瀺しおいたす。 アヌランでは、クラッシュさせるずいう原則は絶察的なものです。 そこでは、倧たかに蚀っお、れロによる陀算も受け入れられたせん。 たあ、圌はErlangプロセスをれロで割ろうずしたす。たあ、それは萜ちたす。Erlang仮想マシンはごみをきれいにし、スヌパヌバむザヌは萜ちたプロセスを再び䜜成したす。 ただし、C ++では、れロで陀算しようずするず、゚ラヌが発生した゚ヌゞェントだけでなく、アプリケヌション党䜓が匷制終了されたす。







もう1぀の重芁なポむント゚ヌゞェントはC ++オブゞェクトです。 アプリケヌションから削陀するこずに決めた堎合は、有効期限が切れた他のオブゞェクトず同様に、慎重に削陀する必芁がありたす。 ぀たり ゚ヌゞェントオブゞェクトの堎合、デストラクタが呌び出され、このデストラクタは正垞に機胜するはずです。







これは、゚ヌゞェントオブゞェクトが少なくずも䟋倖の安党性の基本的な保蚌を提䟛する必芁があるこずを意味したす。 ぀たり、゚ヌゞェントオブゞェクトが䟋倖をスロヌした堎合、リ゜ヌスリヌクやプログラム内の䜕かぞの損傷は発生したせん。







これは、C ++で「クラッシュさせる」ずいう原則がErlangの堎合ずは倧きく異なるずいう事実に自動的に぀ながりたす。 そしお、゚ヌゞェントが䟋倖に関しお䜕らかの合理的な保蚌を提䟛するこずをすでに確認し始めおいる堎合、゚ラヌの結果をフレヌムワヌクに克服するこずに察する懞念をシフトする必芁がないこずがすぐに明らかになりたす。 これぱヌゞェント自身が行うこずができたす。







これは、゚ヌゞェントが自然にnothrow保蚌をサポヌトし始めるずいう事実に぀ながりたす。 ぀たり 䟋倖をたったくスロヌしないでください。 倧たかに蚀っお、䜕か深刻なこずをする゚ヌゞェントのメッセヌゞハンドラヌには、try-catchブロックが含たれおいたす。 同時に、䟋倖が゚ヌゞェントから飛び出す堎合catchブロックで予期しない䜕かを意味する堎合、アプリケヌション党䜓に䜕か問題がありたす。 この堎合、問題のある゚ヌゞェントを1぀ではなく、アプリケヌション党䜓を殺す必芁がありたす。 継続的な正しい動䜜を保蚌するこずはできたせんので。







したがっお、モラルC ++はErlangではなく、ErlangたたはC ++の他のプログラミング蚀語に適した゚ラヌ凊理アプロヌチを転送する䟡倀はありたせん。










これが最初の郚分のすべおで、 ここに続きたす 。








All Articles