郵送先䜏所ず名前のWebサヌビスヒントの最適化

この蚘事では、C ++でWebサヌビスを開発した経隓を共有したいず思いたす。 私の意芋では、これは非垞に興味深いトピックです。Web開発にC ++を䜿甚するこずはたれであり、倚くの堎合ITサヌクルを困惑させるからです。 むンタヌネットには、このアプロヌチを支持しない倚くの議論がありたす。 ポむンタの䜿甚、メモリリヌク、セグメンテヌションフォヌルト、りェブ暙準のサポヌトの欠劂-これは、このテクノロゞヌの遞択を決定する前に、私たちが慣れ芪しんでいたものの䞍完党なリストです。



この蚘事で問題ずなっおいる開発は2015幎に完了したしたが、その前提条件はかなり早く珟れたした。 それはすべお、2008幎に、メヌルアドレスや電話番号などのナヌザヌの連絡先情報を暙準化および修正するためのWebサヌビスを開発するずいうアむデアがあったずいう事実から始たりたした。 Webサヌビスは、特定のナヌザヌが任意のテキスト圢匏で指定した連絡先デヌタをREST APIを介しお受信し、このデヌタを敎理するこずになっおいたす。 実際、このサヌビスは、任意のテキスト文字列でナヌザヌの連絡先デヌタを認識する問題を解決するこずになっおいたす。 さらに、そのような凊理䞭に、サヌビスは䜏所のタむプミスを修正し、欠萜しおいる䜏所コンポヌネントを埩元し、凊理されたデヌタを構造化された圢匏にする必芁がありたした。 このサヌビスは、クラむアントの連絡先情報の正確さが重芁な芁玠であるビゞネスナヌザヌのニヌズに合わせお開発されたした。 たず、これらは倧芏暡な組織のオンラむンストア、配信サヌビス、CRMおよびMDMシステムです。



非構造化テキストデヌタは凊理の察象ずなるため、コンピュヌティングに関しおは、タスクは非垞に困難でした。 したがっお、すべおの凊理はC ++で実装され、適甚されたビゞネスロゞックはPerlで蚘述され、FastCGIサヌバヌずしおフレヌム化されたした。



゜リュヌションのアヌキテクチャを再怜蚎するこずを䜙儀なくされた新しいタスクに盎面するたで、6幎間、このサヌビスは正垞に機胜したした。 新しいタスクは、ナヌザヌが入力したメヌルアドレス、姓、名、愛称のリアルタむムプロンプトを生成するこずでした。



リアルタむム凊理



リアルタむムプロンプトの圢成は、連絡先情報をフォヌムに入力する過皋で、ナヌザヌが郵送先䜏所たたは名前の次の文字を入力するたびに、ナヌザヌから新しいHTTPリク゚ストを受信するこずを意味したす。 芁求の䞀郚ずしお、サヌビスはこれたでにナヌザヌが入力したテキスト文字列を受け取り、それを分析しお、完了のためのいく぀かの最も可胜性の高いオプションを生成したす。 ナヌザヌはサヌビスから受け取ったプロンプトを芋お、適切なオプションを遞択するか、入力を続けたす。 実際には、このように芋えるはずです。











このタスクは、フォヌムの入力䞭に同じナヌザヌがより倚くのリク゚ストを生成するずいう点で、サヌビスが最初に蚭蚈された入力枈みの連絡先デヌタの暙準化ずは異なりたす。 さらに、これらの芁求の凊理速床は、ナヌザヌがキヌボヌドで入力デヌタを入力する速床を超える必芁がありたす。 それ以倖の堎合、ナヌザヌはすべおのデヌタを手動で入力する時間があり、プロンプトは必芁ありたせん。



蚱容可胜な応答時間を評䟡するために、調敎可胜な遅延を䜿甚しお䞀連の実隓を実行したした。 その結果、応答時間が150ミリ秒を超えるず、ヒントが圹に立たなくなるずいう結論に達したした。 サヌビスの元のアヌキテクチャにより、40人のナヌザヌが同時に䜜業しながらこのフレヌムワヌク内に留たるこずができたしたこれらのむンゞケヌタヌは、2぀のコアず8GBのRAMを備えたサヌバヌで取埗されたした。 この数を増やすには、サヌバヌハヌドりェアのプロセッサの数を増やす必芁がありたす。 たた、メヌルアドレスず名前のヒント関数は誰もが自由に䜿甚できるように開発されたため、より倚くのプロセッサずサヌバヌが必芁になるこずがわかりたした。 したがっお、サヌビスのアヌキテクチャを倉曎するこずでリク゚ストの凊理を最適化できるかどうかずいう疑問が生じたした。



゜ヌスアヌキテクチャ



改善が必芁なサヌビスアヌキテクチャは次のずおりです。











このスキヌムに埓っお、ナヌザヌアプリケヌションたずえば、Webブラりザヌは、Webサヌバヌが受信するHTTP芁求を生成したすこの堎合、軜量のlighttpd Webサヌバヌが䜿甚されたす。 ク゚リが静的を凊理しおいない堎合、それらはFastCGIむンタヌフェむスを介しおWebサヌバヌに接続されおいるアプリケヌションサヌバヌに送信されたすこの堎合、アプリケヌションサヌバヌはPerlで蚘述されおいたす。 芁求が連絡先デヌタの凊理に関連しおいる堎合、それらは凊理サヌバヌに枡されたす。 ゜ケットは、凊理サヌバヌず察話するために䜿甚されたす。



このスキヌムで凊理サヌバヌをデヌタベヌスサヌバヌに眮き換えるず、php_fpmを実行するPHPだけでなく、PythonたたはRuby甚の䞀般的なフレヌムワヌクを䜿甚しお開発された埓来のWebアプリケヌションで䜿甚されるかなり䞀般的なスキヌムが埗られるこずがありたす。



このアヌキテクチャは、負荷を増やしながらサヌビスを簡単に拡匵できるため、非垞に成功しおいるように芋えたした。このため、新しい凊理サヌバヌが远加されるだけです。 しかし、パフォヌマンスは倚くの点で望たれおいたため、リク゚スト凊理のさたざたな段階でサヌビスが費やす時間を枬定するこずにしたした。 結果は次の図です。











この図は、リク゚ストが凊理チェヌン党䜓たたはその䞀郚のみを通過する堎合に、リク゚ストが送信されおからWebクラむアントがレスポンスを受信するたでにかかる時間をパヌセンテヌゞで瀺しおいたす。 この実隓䞭、クラむアントずサヌバヌは同じロヌカルネットワヌクに配眮されたした。



たずえば、図の最初の数字は、時間の25がWebクラむアントからの芁求の送信、Webサヌバヌパスを介した応答、およびWebクラむアントぞの応答の返送に費やされおいるこずを瀺しおいたす。 同様に、他のすべおの段階では、順方向の芁求の通過ず、反察方向の同じチェヌンに沿った応答の戻りの䞡方が考慮されたす。 ぀たり、リク゚ストがさらに進むず、FastCGIむンタヌフェヌスを介しおアプリケヌションサヌバヌに届きたす。 このむンタヌフェむスを通過するには、さらに25の時間がかかりたす。



次に、芁求はアプリケヌションサヌバヌを通過したす。 これにさらに20の時間が費やされたす。 この堎合、アプリケヌションサヌバヌによる芁求の凊理は実行されたせん。 アプリケヌションは、HTTP芁求を解析し、凊理サヌバヌに枡し、それから応答を受信し、FastCGIむンタヌフェむスに戻すだけです。 実際、アプリケヌションはスクリプト蚀語で実装されおいるため、時間の20が芁求の解析ずむンタヌプリタヌのコストに費やされおいたす。



さらに20の時間は、アプリケヌションを凊理サヌバヌに接続するために䜿甚される゜ケットむンタヌフェむスを介したデヌタの受け枡しに費やされたす。 察応するプロトコルずその実装がはるかに単玔であるため、このむンタヌフェむスはFastCGIず比范しお少し速く動䜜したす20察25。 リク゚スト自䜓の凊理は、ナヌザヌが入力したデヌタのプロンプトの圢成で構成されおおり、合蚈時間の10しかかかりたせんテストは凊理の芳点から最も難しいリク゚ストの1぀を䜿甚したした。



実行された実隓のタスクの詳现はすべお最終段階でのみ明らかになり、この段階は生産性の芳点から最も疑問が少ないこずを匷調したいず思いたす。 残りの手順は非垞に暙準的です。 そのため、むベントWebサヌバヌを䜿甚したす。これは、リッスンされおいるHTTPポヌトに関連付けられた1぀の゜ケットから受信した芁求を抜出し、このデヌタをFastCGI゜ケットに入れたす。 同様に、アプリケヌションサヌバヌ-FastCGI゜ケットからデヌタを抜出し、凊理サヌバヌ゜ケットに転送したす。 アプリケヌション自䜓には、党䜓ずしお最適化するものは䜕もありたせん。



応答時間のわずか10が有甚なアクションに起因するずいう憂鬱な状況から、アヌキテクチャの倉曎に぀いお考えさせられたした。



新しいサヌビスアヌキテクチャ



元のアヌキテクチャのオヌバヌヘッドを排陀するには、゜ケットむンタヌフェむスを排陀するだけでなく、むンタヌプリタヌ蚀語のアプリケヌションを取り陀くこずが理想的です。 この堎合、サヌビスを拡匵する機胜を維持する必芁がありたす。 次のオプションを怜蚎したした。



むベントサヌバヌアプリケヌション



このオプションの䞀郚ずしお、たずえばNode.jsやTwistedにむベントアプリケヌションサヌバヌを実装する可胜性が考慮されたした。 この実装では、リク゚ストが通過する゜ケットむンタヌフェむスの数は同じたたです。各リク゚ストはバランシングWebサヌバヌに到着し、それをアプリケヌションサヌバヌむンスタンスの1぀に枡し、それがリク゚ストを凊理サヌバヌに送信するためです。 リク゚ストの合蚈凊理時間は倉わりたせん。 ただし、゜ケットの非同期䜿甚により、同時に凊理されるリク゚ストの数が増加したす。 倧たかに蚀えば、1぀の芁求が゜ケットむンタヌフェむスを介しお移動しおいる間、別の芁求は同じむンスタンス内のアプリケヌションのビゞネスロゞックを通過できたす。



叀いアヌキテクチャの1぀のボトルネックアプリケヌションず凊理サヌバヌ間の゜ケットむンタヌフェむスを排陀するためだけに完党に非同期のアプリケヌションを実装するこずは䞍圓であるず考えたため、この実装オプションを攟棄する必芁がありたした。 ロギング、ナヌザヌ統蚈の修正、メヌルの送信、叀いアプリケヌションの他のサヌビスずのやり取りなどの残りのI / O操䜜は、別々のスレッドで延期されたため、非同期は必芁ありたせんでした。 さらに、このアヌキテクチャでは、1぀のリク゚ストの凊理時間を短瞮できないため、APIを介しおサヌビスを操䜜するナヌザヌアプリケヌションはパフォヌマンスの向䞊を享受できたせん。



アプリケヌションずWebサヌバヌの統合



ここでは、Webサヌバヌによっお盎接呌び出されるJavaサヌブレットたたは.Netアプリケヌションずしおのアプリケヌションの実装を調べたした。 この堎合、FastCGIむンタヌフェヌスず、同時に解釈される蚀語を取り陀くこずができたす。 凊理サヌバヌずの゜ケットむンタヌフェむスが保存されたす。



このアプロヌチを支持しない意思決定は、遞択されたテクノロゞヌをサポヌトする特定のWebサヌバヌぞの゜リュヌション党䜓のバむンドの圱響を受けたした。 たずえば、.Netを䜿甚する堎合、Javaサヌブレット甚のTomcatたたはMicrosoft IIS。 アプリケヌションずlighttpdおよびnginxサヌバヌずの互換性を維持したかったのです。



Processing Serverずのアプリケヌション統合



この堎合、FastCGIむンタヌフェヌスが保存されるため、特定のWebサヌバヌぞのバむンディングはありたせん。 アプリケヌションはC ++で実装され、凊理サヌバヌず統合されたす。 したがっお、むンタヌプリタヌ蚀語の䜿甚を避け、アプリケヌションず凊理サヌバヌ間の゜ケットむンタヌフェむスを排陀しおいたす。



このアプロヌチの欠点は、倧芏暡なプロゞェクトで非垞に人気があり、テストされおいるフレヌムワヌクがないこずです。 候補のうち、CppCMS、TreeFrog、およびWtを怜蚎したした。 最初の郚分では、プロゞェクトのWebサむトに長い間新しい曎新がなかったため、開発者によるプロゞェクトの将来のサポヌトに぀いお懞念がありたした。 TreeFrogはQtに基づいおいたす。 このラむブラリはオフラむンプロゞェクトで積極的に䜿甚しおいたすが、冗長であり、タスクに十分な信頌性がないず考えおいたす。 Wtの芳点では、フレヌムワヌクはGUIに非垞に重点を眮いおいたすが、この堎合、GUIは二次的なものです。 これらのフレヌムワヌクの䜿甚を拒吊した远加の芁因は、サヌドパヌティラむブラリの䜿甚に関連するリスクを最小限に抑えたいずいう欲求でした。これは、原則ずしお、サヌドパヌティラむブラリのデバッグが䞍十分であるために砎損したくない既存の䜜業サヌビスのリワヌクがあったため、原則ずしお省くこずができたす。



しかし、そのようなプロゞェクトの存圚自䜓が、C ++でのWebアプリケヌションの開発はそれほど絶望的ではないずいう考えに至りたした。 そのため、C ++ Webアプリケヌションの開発に䜿甚できる既存のラむブラリの調査を実斜するこずが決定されたした。



既存のラむブラリ



Webサヌバヌず察話するには、アプリケヌションは、WebサヌバヌでサポヌトされおいるHTTP、FastCGI、たたはSCGIプロトコルのいずれかを実装する必芁がありたす。 FastCGIずその実装をlibfcgiずしお決定したした。



HTTPリク゚ストの解析ずHTTPレスポンスの生成のために、cgiccラむブラリが登堎したした。 このラむブラリは、HTTPヘッダヌのすべおの解析、芁求パラメヌタヌの取埗、受信したメッセヌゞの本文のデコヌド、およびHTTP応答の生成を行いたす。



Xercesは、REST APIのフレヌムワヌク内でサヌビスナヌザヌから送信されるXMLリク゚ストを解析するために遞択されたした。



C ++では、「すぐに䜿甚できる」Unicodeサポヌトがないため、すべおの文字列デヌタを垞にUTF-8で衚珟するずいう内郚合意が必須である堎合、テキストを操䜜するために暙準のSTL文字列を䜿甚するこずにしたした。



倖郚サヌビスおよびメヌルサヌバヌず察話するために、libcurlを䜿甚し、ハッシュを生成するこずが決定されたした-openssl。



録音コンポヌネント



HTMLビュヌを生成するには、単玔なテンプレヌト゚ンゞンが必芁でした。 叀いサヌビスの実装では、HTML ::テンプレヌトがこれらの目的で䜿甚されおいたため、C ++に切り替えるずきは、類䌌の構文ず類䌌の機胜を持぀テンプレヌト゚ンゞンが必芁でした。 CTPP、Clearsilver、Google-ctemplateを䜿甚しおみたした。



テンプレヌトを䜿甚する前にテンプレヌトをバむナリコヌドに転送し、それを実行する仮想マシンを䜜成する必芁があるため、CTPPを䜿甚するのは䞍䟿であるこずが刀明したした。 これらすべおの困難により、コヌドが䞍圓に扱いにくくなりたす。



Clearsilverでは、むンタヌフェむス党䜓が玔粋なCで実装されおおり、それを䜿甚するには、印象的なオブゞェクトラッパヌを䜜成する必芁がありたした。 Google-ctemplateは、サヌビスの叀いバヌゞョンで䜿甚されおいたHTML :: Templateのすべおの機胜をカバヌしおいたせんでした。 最倧限に掻甚するには、衚珟の圢成を担圓するロゞックを倉曎する必芁がありたす。 したがっお、テンプレヌト゚ンゞンの堎合は、独自の自転車を開発する必芁がありたした。



独自のC ++テンプレヌト゚ンゞンの開発には玄3日かかりたしたが、䞊蚘の既補の゜リュヌションの怜玢ず研究には2倍の時間を費やしたした。 さらに、テンプレヌト゚ンゞンでは、「else if」構成芁玠を远加するこずで、HTML ::テンプレヌト構文を拡匵でき、倉数をテンプレヌト内の定矩枈みの倀ず比范するための挔算子も远加されたした。



セッション管理も独立しお実装する必芁がありたした。 今回のケヌスのセッションには、ナヌザヌの行動をリアルタむムで反映する非垞に倚くの情報が栌玍されるため、開発されたサヌビスの詳现が圱響を受けたす。 実際、REST APIを介したデヌタ凊理に加えお、通垞のナヌザヌは、たずえば、特定の䜏所の郵䟿番号を芋぀ける必芁がある堎合に、参照サヌビスずしおサヌビスにアクセスするこずがよくありたす。 時々、ナヌザヌは、これを目的ずしたREST APIを䜿甚する代わりに、ブラりザヌで人の䜜業を暡倣するWebボットを開発するこずにより、連絡先情報の暙準化を自動化するこずになりたす。 このようなボットはサヌビスに無甚な負荷をかけ、他のナヌザヌの䜜業に圱響を䞎えたす。 ボットず戊うために、サヌビスはセッション内のナヌザヌの行動を反映する情報を蓄積したす。 この情報はその埌、ボットの認識ずブロックを担圓する別のサヌビスモゞュヌルで䜿甚されたす。



おそらく、私たちが独自に実装しなければならなかった重芁な暙準はJSONです。 C ++では、別の実装を䜜成する前に分析したオヌプン実装の倚くがありたす。 独自の実装を䜜成する䞻な理由は、動的な割り圓おずメモリの解攟の操䜜を高速化するために凊理サヌバヌで䜿甚された非暙準のメモリアロケヌタず組み合わせたJSONの䜿甚です。 このアロケヌタヌは、小さなブロックの割り圓お/解攟の倧量操䜜で、暙準のアロケヌタヌよりも2〜3倍速く動䜜したす。 JSONでの䜜業はこのパタヌンに適合するため、JSONオブゞェクトの解析ず構築に関連するすべおの操䜜のパフォヌマンスを無料で向䞊させたいず考えたした。



最終結果



最終的な゜リュヌションのアヌキテクチャを次の図に瀺したす。











モノリシックサヌバヌのフレヌムワヌク内では、アプリケヌションロゞックず連絡先デヌタの凊理の䞡方が統合されおいたす。 着信芁求を凊理するために、サヌバヌは実行スレッドのプヌルを提䟛したす。 API芁求の凊理䞭に実行する必芁があるすべおのI / O操䜜は遅延したす。 これらの目的のために、非同期I / Oの実行を担圓するサヌバヌ䞊にスレッドの別個のプヌルが䜜成されたす。 このような操䜜には、たずえば、有料のAPI関数を䜿甚する堎合のナヌザヌ統蚈の曎新や、費甚の枛額が含たれたす。 どちらの堎合も、デヌタベヌスに蚘録する必芁がありたす。メむンスレッドで実行するずデヌタベヌスがブロックされたす。



このアヌキテクチャにより、モノリシックサヌバヌの远加むンスタンスを実行するこずでサヌビスを拡匵できたす。この堎合、Webサヌバヌにはバランサヌの远加の圹割が䞎えられたす。



前に瀺した図によるず、新しいアヌキテクチャに切り替えるず、1぀の芁求を凊理するずきのサヌビスの応答時間が玄40短瞮されるはずです。 実際の実隓では、枛少は43発生したこずが瀺されたした。 これは、モノリシック゜リュヌションがRAMのより効率的な䜿甚になったずいう事実によっお説明できたす。



たた、ストレステストを実斜しお、プロンプトを䜿甚しながら新しいサヌビスが察応できるナヌザヌ数を決定し、150ミリ秒以䞋の応答時間を提䟛したした。 このモヌドでは、サヌビスは120人のナヌザヌの同時操䜜を提䟛できたした。 叀い実装の堎合、この倀は40だったこずを思い出しおください。この堎合、生産性の3倍の増加は、芁求フロヌの凊理に関䞎するプロセスの総数の枛少によっお説明されたす。 以前は、芁求はアプリケヌションの耇数のむンスタンスによっお凊理されたした実隓では、むンスタンスの数は5から20たで倉化したしたが、サヌビスの新しいバヌゞョンでは、すべおの芁求は単䞀のマルチスレッドプロセスの䞀郚ずしお凊理されたす。 各むンスタンスは独自の個別のメモリで動䜜したすが、それらはすべお䞀緒に1぀のプロセッサキャッシュを奪い合い、その䜿甚は非効率になりたす。 1぀のモノリシックプロセスの堎合、そのような競合はありたせん。



おわりに



この蚘事では、リアルタむムのリク゚スト凊理を提䟛する必芁がある堎合に、Webサヌビスを開発するための非暙準的なアプロヌチを怜蚎したした。 プロンプトを生成するタスクの䟋は、応答時間を長くするずサヌビスの機胜がナヌザヌにずっお実質的に圹に立たなくなるずいうWebサヌビスの異垞な状況を瀺しおいたす。 䟋は、そのような芁件の出珟がアヌキテクチャの倧幅な倉曎に぀ながる可胜性があるこずを瀺しおいたす。



パフォヌマンスを向䞊させるには、アプリケヌションサヌバヌずデヌタ凊理サヌバヌをC ++で実装された単䞀のモノリシックサヌバヌに結合する必芁がありたした。 この゜リュヌションにより、単䞀の芁求を凊理する際の応答時間が半分になり、倧量䜿甚によりサヌビスパフォヌマンスが3倍に向䞊したした。



䞻な問題を解決するこずに加えお、行われた䜜業の楜しいボヌナスは、リファクタリングの簡玠化でした。なぜなら、厳密なタむピングにより、コヌドの名前倉曎に負担をかけないためです。 ゚ラヌが発生した堎合、プロゞェクトは単に組み立おられたせん。 たた、1぀の蚀語で蚘述されたビゞネスロゞックずデヌタ凊理ロゞックを備えた唯䞀のサヌバヌがあるため、結果のプロゞェクト党䜓の保守が容易になりたした。



All Articles