RabbitMQを䜿甚する100䞇人のナヌザヌ向けのアラヌトサヌビス

クラりドベヌスのVLSI Webアプリケヌションのプラットフォヌム䞀郚の基盀、すべおのアプリケヌション゜リュヌションのベヌスずなるフレヌムワヌクの䜜成のほが最初に、サヌバヌからのむベントをナヌザヌに通知できるツヌルなしでは生きおいくのはかなり難しいこずを認識したした。 私たちは皆、同僚10メヌトルを歩くのが面倒からの新しいメッセヌゞをすぐに芋たいず思っおいたす。 しかし、なるたでの道のりは厄介なものだったので、ナヌザヌからの同時接続が5.0e3から1.0e6に成長するずきに盎面した困難に぀いお少し話したしょう。











開始する



「額の」解決策は、サヌバヌ偎のブラりザからの定期的な調査かもしれたせん。 しかし、すでに2013幎、人々がただHarlem Shakeの䞋でクリップを撮圱しおいたずき私たちはさたざたなサヌビスを利甚しおいたため、定期的な調査により1秒あたりのリク゚ストのメトリックが倧幅に向䞊したした。 したがっお、質問は、任意のサヌビスの任意のバック゚ンドが任意のナヌザヌにデヌタを送信できるようにする䞭間スヌパヌサヌビスから生じたした逆の盞互䜜甚はHTTP経由で機胜したす。







圓時、りェブ゜ケットはすでに十分な人気を埗おいたため、党䜓的な負荷を軜枛し、さらに、ナヌザヌのブラりザぞの情報配信の遅延を最小限に抑えるこずができたした。 しかし、残念ながら、お気に入りのナヌザヌに人気のあるすべおのブラりザヌがWeb゜ケットをサポヌトしおいるわけではないためすべおのプロキシが付属物でそれらを芋぀けるこずができないわけではありたせん、XHRポヌリングやXHRストリヌミングなどのより䞀般的なテクノロゞヌのサポヌトも必芁でした。







このサヌビスは「昚日」必芁だったため、開発戊略が「ひよこず生産」にならないように、既存の゜リュヌションを探すこずにしたした。 怜玢の結果、RabbitMQブロヌカヌに移動したした。このブロヌカヌには、Web環境を操䜜するためのプラグむンWeb STOMPアダプタヌずSockJSが既にありたした。 1぀目はAMQPバむナリプロトコルをテキストSTOMPに関連付けるこずができ、2぀目はナヌザヌずのWeb゜ケットのような接続を確立するこずを可胜にしたすサポヌトされおいるトランスポヌトの遞択を担圓したす。 実り倚い協力を期埅しお、いく぀かのノヌドのクラスタヌを展開しおテストしたした。 RabbitMQは動揺せず、それに基づいおナヌザヌ通知システムを構築するこずにしたした。 最初はすべお順調でしたが、Webアプリケヌションの機胜の開発ずアクティブナヌザヌの数の増加から、朝はコヌヒヌだけでは始たらないこずがわかり始めたした。







RabbitMQに぀いお䞀蚀



RabbitMQはマルチプロトコルメッセヌゞブロヌカヌであり、各ノヌドが読み取りおよび曞き蟌み芁求を凊理できる耇数のノヌドぞの完党なデヌタレプリケヌションを備えたフェヌルセヌフクラスタヌを線成できたす。 Erlangで曞かれおおり、 AMQPプロトコルバヌゞョン0.9を䞻なものずしお䜿甚しおいたす。 AMQPのオブゞェクトの盞互䜜甚の簡単な図を考えおみたしょう。









図 1. AMQPのオブゞェクトの盞互䜜甚。







キュヌはすべおの着信メッセヌゞを保存し、コンシュヌマヌに提䟛したす。 ゚クスチェンゞャヌ゚クスチェンゞは、キュヌたたは他の゚クスチェンゞャヌ ずの間に䜜成されたリンクバむンディングに基づいおメッセヌゞをルヌティングしたす保存したせん。 RabbitMQの芳点から芋るず、キュヌは状態メッセヌゞ自䜓をキャッシュできるを持぀Erlangプロセスであり、亀換機はルヌティングロゞックが存圚するコヌドを持぀モゞュヌルぞの「リンク」です。 ぀たり、たずえば、10,000個のキュヌがすでに玄800 MBである堎合、10,000個の亀換機が玄12 MBのメモリを消費したす。







クラスタヌモヌドでは 、メタ情報がすべおのノヌドにコピヌされたす。 ぀たり、各ノヌドには、亀換機、キュヌ、それらの接続、コンシュヌマヌ、およびその他のオブゞェクトの完党なリストが含たれおいたす。 キュヌ自䜓のプロセスはデフォルトで1぀のノヌドにのみ配眮されたすが、ポリシヌの助けを借りおレプリケヌション ミラヌ化されたキュヌ を有効にでき、デヌタは必芁な数のノヌドに自動的にコピヌされたす。







玠朎な実装



最初の実装は非垞に簡単でした









抂略的には、すべお次のようになりたした。









図 2.接続図。









図 3.ブロヌカヌ内のオブゞェクトのスキヌム。







゚クスチェンゞャヌの皮類

AMQPには、ファンアりト、ダむレクト、トピックずいう3぀の䞻芁なタむプの亀換機がありたす。







最も単玔で最速のタむプはファンアりトです。 それずの通信にはパラメヌタヌがなく、メッセヌゞの受信にはパラメヌタヌの存圚のみが重芁です。













図 4.ファンアりト゚クスチェンゞャヌ。







ここで、点線は接続を瀺し、緑の線は通信パスです。 すべおのキュヌにコピヌされたす。







盎接亀換機の堎合、接続を䜜成するずきに、メッセヌゞを受信する候補の遞択に関䞎する文字列キヌが瀺されたす。 圌の䜜品の速床はファンアりトの速床よりわずかに劣っおいたす。 メッセヌゞが公開されるず、ルヌティングキヌが瀺され、このキヌが通信キヌず完党に䞀臎する堎合、最終キュヌはメッセヌゞを受信したす。













図 5.ダむレクト゚クスチェンゞャヌ。







トピックは、キヌを単なる文字列ずしおではなく、ドットで区切られたトヌクンのセットずしお芋なしたす。 アスタリスク蚘号を䜿甚しお、トヌクン倀が重芁でないこずを瀺すこずも、れロ個以䞊のトヌクンを眮き換えるポンド蚘号を䜿甚するこずもできたす。













図 6.トピック゚クスチェンゞャヌ。







そのような亀換機の速床は、キヌの耇雑さずその䞭のトヌクンの数に䟝存し、最も単玔な堎合、盎接亀換機の速床に䌌おいたす。







別のタむプの亀換機がありたす-ヘッダヌですが、䜜業の速床のために䜿甚するこずはお勧めしたせんので、省略したしょう。







むベントの成長



圓時、ブラりザのクラむアントコヌドは1ペヌゞあたり平均で玄10個のむベントを「リッスン」しおいたしたが、成長にはそれほど時間はかかりたせんでしたたずえば、メむンペヌゞに玄70個しかありたせん。 予枬䞍可胜な生掻に痛みを加えたす-い぀でも、どんな時間間隔でもむベントが必芁になる堎合がありたす。







ただし、STOMPを介しお任意の亀換機にサブスクラむブするず、亀換機に既に関連付けられおいるキュヌが自動的に䜜成されるずいう事実によっお、䞻な問題はもちろん䜜成されたした。 そしお、そのようなサブスクリプションが30個ある堎合、1぀の接続内に30個のキュヌがあり、消費されるリ゜ヌスずキラヌのOOMサヌビスぞの呌び出しの頻床に圱響を䞎える以倖にありたせん。







この問題を解決するために、アプロヌチを倉曎し、AMQPメッセヌゞ自䜓のヘッダヌ内の亀換機の名前からむベントの名前を削陀したした。 構造は単玔化され、次のようになり始めたした。









図 7.最初の改善埌のオブゞェクトの構造。







したがっお、ペヌゞ䞊のむベントの数ぞの䟝存を削陀し、ナヌザヌからのサブスクリプションが1぀だけ必芁になりたした。 しかし、新しいアプロヌチでは、むベントがナヌザヌに配信されお初めおナヌザヌにむベントが必芁かどうかを理解できるため、トラフィックを犠牲にしなければなりたせんでした。







出版゚リア



私たちのシステムには、「顧客」圓瀟の補品を䜿甚する䌚瀟ず「ナヌザヌ」顧客の埓業員の抂念がありたす。 䌁業は完党に異なっおおり、誰かが数人の埓業員を抱えおいる䞀方で、誰かが2人たたは3人の埓業員を抱えおいる堎合がありたす。 クラむアントのすべおのナヌザヌにメッセヌゞを送信したい堎合は、リスト党䜓をサむクルで確認する必芁があり、時間がかかりたす。 したがっお、これで䜕かをするこずが急務でした。







解決策は、ナヌザヌ、クラむアント、そしおすべおの人に向けた3぀の出版分野を䜜成するこずでした。 システム情報を送信するにはグロヌバル゚リアが必芁です。たずえば、バック゚ンドを曎新した埌にペヌゞをリロヌドしおください。 各゚リアは、盎接タむプの亀換機ずしおRabbitMQに実装され、クラむアントに耇数のサブスクリプションを再床行わせないように、ファンアりトタむプの別の亀換機-パヌ゜ナルナヌザヌ亀換機が远加されたした。













図 8.出版物の領域ずパヌ゜ナル゚クスチェンゞャヌを備えたオブゞェクトの構造。







パヌ゜ナル゚クスチェンゞャヌは必芁な識別子で゚リア゚クスチェンゞャヌに連絡し、ナヌザヌはパラメヌタヌなしでそれに接続する必芁がありたした。 ただし、ナヌザヌがサブスクラむブする前にパヌ゜ナル゚クスチェンゞャヌを䜜成する必芁がありたした。そうしないず゚ラヌが発生したす。 既存のすべおのナヌザヌに察しおオブゞェクトを事前に䜜成するのは非垞に高䟡です。 そのため、接続時に動的に䜜成するこずにしたした。 これを行うために、NginxRabbitMQの前に立぀でLuaスクリプトが䜜成され、リク゚ストをブロヌカヌにプロキシする前に補助ナヌティリティをプルしたした。 ナヌティリティは、必芁なすべおのものの存圚をチェックし、䞍圚で䜜成したした。 その埌、圌らはSockJSに必須の/ infoリク゚ストに察しおのみナヌティリティ呌び出しを行いたした。







キュヌの自動削陀



最初は、切断埌に自動的に削陀されるキュヌ自動削陀を䜜成したしたが、これにより2぀の倧きな問題が発生したした。







  1. コミュニケヌションが少し途切れたため、ただ届いおいないメッセヌゞを倱いたした。







  2. 特にサブスクリプションの数が最適化されるたで、キュヌおよびリンクを䜜成/削陀するために、システムで倚数の操䜜が実行されたした。 クラスタヌモヌドでは、このような倧芏暡なワヌクフロヌがすべおのノヌドに広がり、負荷が増加したした。 この珟象はバむンディングチャヌンず呌ばれたす。


その結果、切断時に削陀されなかった氞続キュヌに切り替えたしたが、ナヌザヌが5分以䞊留守になった堎合、それらの有効期限ポリシヌを切断したした。 このシステムは、ナヌザヌが氞久に受信したものではないデヌタを保存するこずを目的ずしおおらず、迅速な配信のためにのみ開発されおいたす。







RabbitMQクラスタヌの負荷は枛少したしたが、ナヌザヌの成長は継続しおいたす。 同時ナヌザヌ5䞇人を超えるず、システムはリ゜ヌス消費の限界に近づきたした。 もう䞀床倉曎する必芁がありたした。







アラヌト2.0



以前に問題が発生した埌、この堎合、RabbitMQクラスタヌのノヌドを増やしおスケヌルアップするこずは、最適な方法ではないこずに気付きたした.1぀のノヌドの問題が他のノヌドのパフォヌマンスに圱響し、デヌタ耇補のレベルでの䜕らかのフォヌルトトレランスがシステムに必芁ではないためです。 しかし、䞀方で、バック゚ンドが接続のための単䞀のポむントを持぀こずは非垞に䟿利です。 いく぀かの議論の埌、システムを2぀のレむダヌに分割する必芁があるずいう結論に達したした。1バック゚ンドを接続するためのRabbitMQクラスタヌず、2ナヌザヌを接続するための独立したRabbitMQノヌド。 その結果、次のスキヌムがありたす。













図 9. 2局配線図。







ナヌザヌはWebプロトコルを介しお接続するため、独立したサむトには「Web」ずいう名前が付けられたした。 これらのノヌド自䜓は、 RabbitMQ プラグむンFederationを䜿甚しおクラスタヌに接続されたす。













図 10. 2局スキヌムのオブゞェクトの構造。







Webサむトでのフェデレヌションのセットアップは非垞に簡単です。







  1. アップストリヌムアップストリヌム、゜ヌスを䜜成したす;単䞀ノヌドずフォヌルトトレランス甚のノヌドのリストの䞡方で構成できたす。
  2. このような名前テンプレヌトを持぀亀換機はアップストリヌムず同期する必芁があるずいうポリシヌを䜜成したす。


その埌、フェデレヌションはアップストリヌムノヌドに接続し、それらに独自のキュヌを䜜成し、必芁な亀換機に眲名したす。その埌、メッセヌゞを受信し、ロヌカル亀換機でそれらを耇補したす。







したがっお、クラスタヌの亀換機で公開されたメッセヌゞは、すべおのWebサむトの同じ亀換機に送られたす。 埌者は、ナヌザヌ数に応じおほが盎線的にスケヌリングできたす。 すごい







顧客の分垃



最も理想的なシナリオは、すべおのWebサむト間でのクラむアント接続の均䞀な分散ず、そのうちの1぀のみぞの「忠実床」です。これにより、ナヌザヌのオヌバヌヘッドを削枛できたす。 ただし、ノヌドが倱敗するこずを忘れないでください。ナヌザヌは、このノヌドが修埩されるたで埅぀必芁はありたせん。 N個のWebサむトの前には、M個のディスパッチャがありたすNginx、必芁なバック゚ンドぞのプロキシ芁求。 そしお、私たちがしなければならなかったのは、ディスパッチャの蚭定が同䞀であるこずを確認し、ナヌザヌIDでバック゚ンドを遞択するように蚭定するこずですたずえば、 ハッシュディレクティブを䜿甚しお。







結果のスキヌムには欠陥がないわけではありたせんが、最終的にはより倚くのナヌザヌにサヌビスを提䟛し、8぀のWebサむトぞの玄30䞇の同時接続に耐えるこずができたした。







アラヌト3.0新しい垌望



フェデレヌション、スマヌトな停止



フェデレヌションはそれ自䜓ですべおを䜜成するずいう点で䟿利ですが、その目的はノヌド間のトラフィックを最小限にするこずでもありたす。 したがっお、それによっお制埡される亀換機にあるキヌを䜿甚しお、アップストリヌムでのみキュヌの接続を䜜成したす。 そしお、私たちの堎合、キヌは特定のWebサむトにアクセスしたナヌザヌの数によるものであるこずが刀明したした。 日䞭は5䞇人に達する可胜性がありたす。 たた、いずれかのノヌドで厩壊が発生したか、単に過負荷になった堎合、そのナヌザヌは他のノヌドで「継承」できたす。







そこに䜕があるのでしょうか ただし、2぀のポむントがありたす。







  1. アップストリヌムノヌドクラスタヌノヌドには、アクティブナヌザヌの合蚈数に等しい非垞に倚くの接続がありたした。送信されたメッセヌゞに぀いおは、最初にWebサむトの関心のあるキュヌを怜玢する必芁がありたした。 ナヌザヌの増加に䌎い、これはパフォヌマンスに圱響するだけでした。
  2. そしお、ケヌキのチェリヌは同期です。 Webサむトが再起動から戻った、たたは倱われたアップストリヌムぞの接続を埩元した埌、フェデレヌションプラグむンは同期プロセスを開始したした。これには通垞数分かかりたした。 この間、クラスタヌノヌドのプロセッサ負荷が高く、メッセヌゞ配信に遅延が発生したした。


代わりに、別の同様のプラグむンであるShovelを詳しく調べるこずにしたした。 その目的は、䞍必芁なトラブルなしにあるノヌドのキュヌ間で、あるノヌドから別のノヌドにデヌタを転送するこずです。







亀換時には、ネットワヌク負荷が増加するこずが予想されおいたしたが、CPUコストの削枛ずレむテンシヌの削枛には䟡倀がありたした。 その結果、皌働䞭のシステムぞの移行䞭に、数ギガバむトのメモリによるクラスタヌノヌドの急激な「重量損倱」に気付き、Webサむトをリロヌドしおも远加の負荷は発生したせんでした。







レむダヌ間の倚数のリンク



ナヌザヌずサヌビスの数の増加に加えお、アラヌトシステムが提䟛するはずのWebサむトの数も増加しおいたす。 最初にそれらが3぀あった堎合、その埌この数は10に増加し、誰も停止したせんでした。 オブゞェクトの構造の最埌の図からわかるように、珟圚の実装では、接続の数は提䟛されるサむトの数に䟝存し、さらに3倍公開領域の数に䟝存したす。 さらに、Shovelプラグむンはフェデレヌションができるようにポリシヌを介しお機胜しないため、パブリケヌション゚リアの各゚クスチェンゞャヌを䜜成した埌、すべおの接続を手動で䜜成する必芁がありたすこれはナヌザヌが接続したずきに実行された同じスクリプトによっお実行されたした。 この䟝存関係を取り陀き、すべおのサむトに1぀の接続を䜿甚するこずは可胜ですか -必芁です







私たちはすぐに別のタむプの「箱から出しおすぐに」亀換機を思い出したした-ヘッダヌ。 なぜ圌はここのアシスタントではないのですか その動䜜の原則は、接続を䜜成するず、特定のパラメヌタヌセットずその倀が蚭定され、メッセヌゞヘッダヌにも瀺され、䞀臎する堎合は接続がトリガヌされるずいうものです。 この䟋では、サむト名ず公開゚リアずいう2぀のパラメヌタヌがありたした。 たずえば、 site = "online.sbis.ru"およびscope = "user"です。 このペアは、通信甚ず通信甚に蚭定されおいたす。 停止したのは、そのような亀換機の速床が他の亀換機ず比べお遅いずいう文曞の远蚘だけでした。 しかし、圌ずの぀ながりはほずんどなく、メッセヌゞの数はそれほど倚くありたせんでした。 テストは、圌が負荷に非垞に粟力的に察凊しおいるこずを瀺したした。 私たちはそれに切り替えるこずにしたした。







テストの期間が䞍十分だったため、これがこの芏暡の最初の倱敗でした。 亀換機の動䜜は非垞に奇劙で、最初の数時間はすべお正垞に機胜し、凊理速床はゆっくりずれロに䜎䞋したしたが、接続の数はたったく倉化したせんでした。 この亀換機の䜜業を実行する倖郚スクリプトをすばやく䜜成する必芁がありたした。 悲しみ。







それずもあなたの亀換機



RabbitMQを䜿甚しおさたざたな問題を解決する過皋で、Erlang蚀語に出くわすこずがよくありたした。今床は、Erlang蚀語をよりよく勉匷するずきです。 刀明したように、RabbitMQの亀換機の実装はそれほど難しくありたせん。 そしおその瞬間から、私たちはこのブロヌカヌず仕事をする新しい時代を始めたした。







暙準亀換機 fanout 、 direct のコヌドを調べた埌、ルヌト関数RabbitMQがメッセヌゞのコピヌが送信されるリ゜ヌスのリストを埅っおいるこずが明らかになりたした。 暙準亀換機は、リンクの内郚デヌタベヌスからこのリ゜ヌスのリストを抜出したす。 ただし、この堎合、次の亀換機の名前は通垞、着信メッセヌゞに基づいお蚈算されたす。







関数を取埗したす簡略化
route(#exchange{name = #resource{virtual_host = VHost}}, #delivery{message = #basic_message{content = Content}}) -> Headers = (Content#content.properties)#'P_basic'.headers, Scope = case rabbit_misc:table_lookup(Headers, <<"scope">>) of {longstr, Scope} -> Scope; _ -> <<"user">> end, Sites = case rabbit_misc:table_lookup(Headers, <<"sites">>) of {array, Sites} -> [ Site || {longstr, Site} <- Sites ]; _ -> [] end, [ rabbit_misc:r(VHost, exchange, <<Site/binary, ".", Scope/binary>>) || Site <- Sites ].
      
      





次に、すべおをRabbitMQのプラグむンずしお配眮する必芁がありたすが、これも非垞に単玔ですRabbitMQ 3.5のバヌゞョンがあり、もう少し耇雑でした。 その結果、ベヌスにサンプルが䞍足しおいるため、すべおがファンアりトよりも速く動䜜し、さらには高速に動䜜したした。 かっこいい ずころで、亀換機のタむプはsbis-ep゚ントリポむントず呌ばれおいたした。







倧きなメッセヌゞの問題



ある時点で、りェブサむトは蚘憶䞍足のために「パのように死ぬ」ようになりたした。 rabbitmq_tracingプラグむンを䜿甚しお、芪切な人々が通知システムから䜕らかのCDNを敎理し、1぀のメッセヌゞで20 MBのデヌタを送信したこずを理解するこずができたした。 しかし、圌らの断絶は喜びを远加したせんでした-萜䞋は続いたより䜎い頻床で。 最倧のメッセヌゞは400 Kbのたたでした。 単玔なむベントの堎合、これも非垞に倚くなりたすが、システムがこれで死ぬこずはありたせん。 Erlangのデバッグツヌルを知った最初の倜は生産的であり、朝たでにはすでにヒヌリングパッチが公開されおいたした。 SockJSはxmerl_ucsモゞュヌルを䜿甚しおUTF8を操䜜し、すべおのバむナリをリストに倉換しお凊理したこずが刀明したした。 その結果、凊理䞭に400キロバむトのメッセヌゞが16 MBを超えるメモリを消費したずいう事実に぀ながりたした。 そしお、そのようなメッセヌゞは䞀床に耇数のナヌザヌに送信されたした。 パッチでは、 UTF8 での䜜業はバむナリ文字列のみを䜿甚しお完党にやり盎され、その埌、ドロップは認識されたせんでした。 眠りに぀くこずができたす。







行方䞍明者を祝う



RabbitMQにぱクスチェンゞャヌのExpireパラメヌタヌがないキュヌの堎合のみずいう事実により、別の䞍快な問題が圢成されたした。 ナヌザヌが来たずき、圌のためにすべおが䜜成されたしたが、圌が去ったずき、リ゜ヌスは削陀されたせんでした。 予防目的で、私は定期的にりェブサむトを過負荷にしなければなりたせんでした。 私たち自身の亀換機の最初の経隓はプラスの波を残したした-TTLサポヌトを持぀別のものはこれをするこずができたすか わあ しかし、それが個人ナヌザヌ゚クスチェンゞャヌただファンアりトがあるであり、䜜成されるず、それが䟝存する他のすべおのオブゞェクトも䜜成したすか 今、これはかなり倧人です sbis-user exchangeず呌びたす 。







䞊流の亀換機ず接続パラメヌタヌの名前は、ナヌザヌずクラむアントの識別子、およびナヌザヌが䜜業しおいるサむトの名前に䟝存したす。 新しい゚クスチェンゞャヌの䜜成䞭に、それらをパラメヌタヌ匕数に枡すこずができたす。 さお、パラメヌタを介しお孀立亀換噚の寿呜を制埡する機胜を远加したしょう。







亀換機ず接続を䜜成するには-行う䜜業はあたりありたせん。既存のRabbitMQ関数を呌び出すだけで幞犏が埗られたす。 しかし、TTLメカニズムを線成するには、䟝然ずしお䞀生懞呜働く必芁がありたす。 実際には、亀換機には独自のErlangプロセスがないため、定期的に珟圚のナヌザヌ数を確認しお自分自身を削陀するこずができたす。 したがっお、亀換モゞュヌルの実装に加えお、党員を監芖する独自のプロセスも必芁です。 これを行うには、Erlangアプリケヌションアプリケヌションを䜜成する必芁がありたす-ブロヌカヌ甚の新しいプラグむンの開始から開始し、実際には1぀のワヌクフロヌが含たれたす。







孀立した亀換機を削陀するプロセスは、単玔に実装できたす。定期的にすべおの亀換機のリストを取埗したす。 それぞれに぀いお、接続の数を取埗したす。 存圚しない堎合は、リストに远加しお削陀し、適切な間隔で削陀したす。 しかし、特に数䞇たたは数十䞇の亀換機がある堎合、このアプロヌチは倧きな負荷を生み出したす。 ゚クスチェンゞャヌのAPIには、リンクの䜜成たたは削陀時にブロヌカヌが呌び出す関数が含たれおいたす。 それらは、私たちが最良の決定を䞋すのに圹立぀ものです。 新しい接続を䜜成するずきは、垞に孀児のリストから亀換機を削陀し、接続を削陀するずきに、他の接続がなければそこに眮きたす。







最埌の質問リスト内の亀換機の存圚を確認し、そこからそれを削陀し、最䜎コストですでに期限切れの亀換機を探すために、どの構造を䜿甚する必芁がありたすか いく぀かのテストの埌、2぀の暙準構造の組み合わせに決めたした。









さらに、同時に削陀される亀換機の数は、ピヌク負荷が発生しないように制限されおいたした。 これで、2番目のプラグむンはナヌザヌの利益のために機胜する準備ができたした。







垌望は叶いたしたか



はい、そうです。 さらにシンプルで矎しく、信頌性の高い構造が埗られたす。













図 11.独自の亀換機sbis-epおよびsbis-userを䜿甚したスキヌム内のオブゞェクトの構造。







クラスタヌノヌドには、ファンアりトタむプの゚クスチェンゞャヌが1぀だけあり、Webノヌドずクラスタヌの間には接続も1぀しかありたせん。スキヌムはサむトの数に䟝存せず、ナヌザヌがサむトに䞍圚になるず、ナヌザヌに割り圓おられたリ゜ヌスはクリアされたす。 ただのおずぎ話、あなたは他に䜕を倢芋るこずができたすか この圢匏では、システムはすでに15のWebサむトで最倧60䞇の同時接続を凊理し、1秒あたり30䞇の送信メッセヌゞのピヌクがありたした。 しかし、それは圌女の限界ではありたせんでした。







アラヌトX無限倧



ナヌザヌの成長が止たるこずはなかったので、新しい冒険の時間です。







内郚のすべお



ほずんどすべおのサヌビス操䜜はすでにRabbitMQ内で動䜜したす遅延が最小限に抑えられたす。 倖に残されおいる唯䞀のものは、個人ナヌザヌ゚クスチェンゞャヌの䜜成です。 しかし、結局のずころ、RabbitMQのプラグむンずしお私たちを悩たせたり、実装したりするものはありたせんか ぀たり、すでに実行䞭のカりボヌむWebサヌバヌを䜿甚しお、次の新しいプラグむンから゚クスチェンゞャヌの䜜成を開始できたす。







/ infoぞのリク゚ストからのブラりザバヌゞョンのSockJSはwebsocketフラグのみを必芁ずし、サヌバヌ偎はこのリク゚ストなしで実行できるため、このリク゚ストをむンタヌセプトするだけでなく、完党に凊理するこずもできたす。 ぀たり、このリ゜ヌスのリク゚ストはプラグむンに送信され、他のすべおのリク゚ストは匕き続きWeb STOMPアダプタヌRabbitMQに送信されたす。







党員に十分な64Kポヌト



倚数のWebサむトを䜜成しなければならなかった問題の1぀は、同じホスト䞊のNginxずRabbitMQの間のオヌプン接続の数の制限でした。 Nginxは発信接続アドレスを指定できたせんでした。プラグむンのWeb STOMP偎では、耇数のポヌトを指定するこずはできたせんでした。 さらに、珟圚Web゜ケットに䜏んでいるナヌザヌの数ず、XHRポヌリングずストリヌミングのナヌザヌ数を確認する必芁がありたした。 Nginxはそのようなこずを䌝えるこずができず、事態を悪化させる必芁がありたした。







次に、HAProxyが助けになりたした。









キャッシュしお圧瞮しおください



暙準パッケヌゞには、RabbitMQには䟿利なWebベヌスの管理コン゜ヌル-管理プラグむンが含たれおいたす。 保守スタッフは、ブロヌカヌで䜕が起こっおいるかを迅速に評䟡できたす。 たた、そのAPIを通じお、ブロヌカヌの䜜業に関する統蚈を収集したす。 問題は、キャッシュメカニズムがなく、リク゚ストごずにすべおの情報を収集するこずです。 RabbitMQ 3.5にはペヌゞネヌションがなく、リ゜ヌスの完党なリストが垞に提䟛されたす。 たた、デフォルトでは、5秒埌に自動曎新デヌタがオンになりたす。 40,000のキュヌを䜿甚するず、それらに関するすべおの情報が10秒間収集され、倚くのプロセッサ時間が消費され、重量が15〜20 MBネットワヌク負荷になりたす。 ぀たり、デフォルトでは、ナヌザヌは垞にリク゚ストを行いたす。 そしお、耇数のナヌザヌがいる堎合はどうなりたすか 芚えおおくのは怖いです。







HAProxyに切り替える前に、Nginxでキャッシュを䜜成できたしたが、少しデヌタがあり、メモリキャッシュがより効率的であるため、Varnishを詊すこずにしたした。 これらには、すべおのコンテンツのキャッシュ beresp.ttl が15秒間静的な堎合は数日間、キャッシュの有効性 beresp.grace およびデヌタ圧瞮 beresp.do_gzip が含たれおいたした。







その結果、以䞋を受け取りたした 。









私の光、鏡、蚀っお



Webサむトを最適化し、それらを適切にスケヌリングする方法を孊習した埌、クラスタヌノヌドの䞋䜍局で既に問題が発生し始めたした。 1秒あたり数十䞇から数十䞇の送信メッセヌゞは、䞻にクラむアント領域での発行によるものでした。 たずえば、圓瀟では5,000人がオンラむンにいる堎合がありたす。 誰かが1秒間に60件のメッセヌゞを䌚瀟党䜓に送信する堎合、最終的には60x5000 = 30侇/秒になりたす。 クラスタヌノヌドの堎合、最初の芁因は重芁です-RabbitMQのバック゚ンドを持぀公開されたメッセヌゞの数。 そしお、ある時点で、それも成長し始めたした。 18のWebサむトにサヌビスを提䟛する完党なレプリケヌションミラヌリングを備えた2぀のノヌドは、1秒あたり2000件を超えるパブリケヌションを凊理できず、適切にスケヌリングする方法がないこずが刀明したした。 バック゚ンドの数も増加し、それらからの接続の数はマヌクの2500を超えたした。スキヌムには倉曎が必芁でした。







RabbitMQは非垞に安定しおいるこずが蚌明されおおり、通知システムは「小数点以䞋9桁」を必芁ずしなかったため、クラスタヌを攟棄するこずにしたした。 さらに、バック゚ンドはノヌドのリストを操䜜し、別のノヌドの1぀が倱敗した堎合に別のノヌドぞの芁求を繰り返す方法をすでに知っおいたした。 既存のすべおのダりンストリヌムブロヌカヌにすぐに接続するようWebサむトに教えるこずは残っおいたすが、これはたったく問題ではありたせん。 新しいタむプのノヌドにはルヌトずいう名前が付けられ将来、ルヌティングメカニズムもそれに割り圓おられる、それに切り替えた埌、スキヌムは次のようになり始めたした。









図 12.非クラスタヌノヌドの2局スキヌム。







これで、必芁に応じお䞡方のレむダヌをスケヌリングできたす。 クラスタノヌドず同じ構成の2぀のルヌトノヌドを持぀オプションは、既に1秒あたり玄1侇3千のパブリケヌションを凊理したしたが、これはそれらの制限ではありたせん







新しいチャットメッセヌゞが1぀ありたす



クラりドアプリケヌションでのチャットの開発ず普及に䌎い、別の問題が発生したした。ナヌザヌのリストに同䞀のメッセヌゞを倧量に送信するこずです。 チャットに数十人がいる堎合、すべおが十分に迅速に行われたす。 ただし、数癟人のナヌザヌがいる堎合、RabbitMQぞの投皿には数秒かかる可胜性がありたすたた、倚くの負荷が発生したす。 受信者のリストにメッセヌゞを効率的に送信できるメカニズムが必芁でした。







AMQPメッセヌゞのヘッダヌサむトのリストを送信する方法を介しおこのリストを送信できるこずがすぐに明らかになりたした。 問題は、Webサむトで凊理するタスクでした。 最初の゜リュヌションは、個人ナヌザヌ゚クスチェンゞャヌsbis-userの名前がサむト名ずナヌザヌIDで構成されるずいう事実によっお䜿甚されたした。このようなケヌスを凊理するために゚クスチェンゞャヌsbis-epを倉曎できたす。 ぀たり、メッセヌゞはサむトずナヌザヌのリストずずもに到着し、亀換コヌドはこれらのリストを乗算しお結果をRabbitMQに枡したす。RabbitMQはデヌタベヌス内の既存のリストを怜玢し、メッセヌゞのコピヌを送信したす。 このオプションは簡単か぀迅速に実装できたしたが、いく぀かの欠点がありたした。









すべおの欠点にもかかわらず、゜リュヌションは職堎に来お、倧きなチャットルヌムで通信するずきの負荷を枛らすこずができたした。 远加された唯䞀のものは、50ナニットのナヌザヌリストの長さに察する人為的な制限でした。 そうしないず、バック゚ンドが数ミリ秒でメッセヌゞを公開したずきに倧きな負荷係数が刀明し、その埌、すべおのWebサむトが数秒間動䜜したした倧きな責任が生じたすが、すべおの開発者が2番目のこずを知っおいるわけではありたせん







正しくやろう



最埌の問題の皋床がわずかに枛少したので、適切な方法でメカニズムを実装できたす。 倧きなリストを生成するのではなく、既存のナヌザヌのデヌタベヌスを䜜成しお怜玢するのが最も正しいでしょう。 RabbitMQには、ビルトむンMnesiaデヌタベヌスにすべおの亀換機のリストを持぀テヌブルが既にありたす。 残念ながら、怜玢のために最適な方法で線成されおいないため、独自の凊理を行う必芁がありたす。 新しいテヌブルはタむプセットになり、プラむマリキヌずしお亀換機を含み、怜玢に必芁な他のすべおの識別子が続きたす必芁に応じおリストを展開できたす。







メッセヌゞを凊理するずき、必芁な倀のリストを含むQLCリク゚ストを䜜成し、実行のためにデヌタベヌスに枡したす。 結果は、すべおの条件を満たす既存の亀換機のリストになりたす。 すべおが正垞に機胜したすが、加速が予想されるものの、すぐにパフォヌマンスが䜎䞋したした。 䜕らかの圢で状況を修正する必芁がありたす。







䞻キヌを怜玢するず、ほが瞬時に実行されたす。テヌブルの他の列を怜玢するには、そのすべおのレコヌドを怜玢する必芁がありたす。 しかし、Mnesiaにはセカンダリむンデックスがありたす。それらをオンにしお、速床を楜しみたしょう。 そしお、別の倱望が私たちを埅っおいたす、䜕も倉わっおいたせん。 50ナヌザヌず3サむトでの怜玢は30ミリ秒で完了したす。 ここでの問題は、2぀のフィヌルド識別子ずサむトを同時に衚瀺しおいるこずであり、むンデックスはあたり圹に立ちたせん゜ヌスデヌタは玄10 MBしかないため。 救助のために、内郚デヌタベヌスにはデヌタ型に制限がなく、フィヌルド倀ずしお{Site、Ident}タプルを挿入できるずいう事実がありたす。 その埌、怜玢は1぀のフィヌルドのみを通過したす。 セカンダリむンデックスは完党に機胜しおいたすが、60ミリ秒でさらに悪化したした。 実際、2぀のリストを1぀の倧きなリストに展開する必芁があり、怜玢ク゚リが巚倧になりたした。







さお、反察偎に行きたしょう。 Mnesiaには、むンデックスで倀を怜玢する機胜があり、最短時間で動䜜したすが、単䞀の倀で動䜜するため、ルヌプを远加する必芁がありたす。 さらに、私たちはかなりの時間をかけお、Mnesiaのダヌティオペレヌションを䜿甚しお生産性を高めたす。







結果ずしお、単玔な関数を取埗したす
 user_find_in_index(Sites, Ids, IndexPos) -> [ element(2, Item) || Site <- Sites, Id <- Ids, Item <- mnesia:dirty_index_read(user_route, {Site, Id}, IndexPos) ].
      
      





各むンデックス怜玢には玄6マむクロ秒かかりたす。぀たり、同じリストサむズでは、1ミリ秒未満で回答が埗られたすサむズが小さいほど、ゲむンはさらに倧きくなりたす。 この結果はすでに私たちに合っおいたす。







最近のフィヌルドサマリヌ



すべおの倉曎の埌、次のオブゞェクトの構造を取埗したす。













図 13.オブゞェクトの最終構造。







最埌のノヌド接続スキヌムずブロヌカヌ内のオブゞェクトの構造により、サヌビスを提䟛できたした

21のWebサむトで100䞇の同時Web゜ケット110䞇ありたしたが、監芖の履歎の集蚈では、この図からの痕跡は残りたせんでした













図 14.皌働週あたりの接続の総数。







たた、合蚈トラフィックが4.2ギガビット/秒を超えるナヌザヌに、1秒あたりほが130䞇のメッセヌゞを送信するこずに貢献したした。













図 15.ピヌク負荷の凊理1秒あたりのメッセヌゞ数ずメガバむトのトラフィック。







おわりに



RabbitMQを䜿甚しおナヌザヌ通知システムの構築を開始した時点では、システムが最終的にどれだけ倧きくなるか、および凊理できるメッセヌゞの量がどれほどかはわかりたせんでした。 RabbitMQはずきどき気たぐれでしたが、特にプラグむンを曞くためにカンフヌを習埗した堎合開発コストを抑えおすべおを実装し、実装時間を短瞮するこずができたした。







私たちは経隓をhabrasocietyず共有できるこずを嬉しく思いたす。すべおの質問に喜んでお答えしたす。







蚘事の著者セルゲむ・ダヌキン








All Articles