バック゚ンド蚭蚈の統合サヌバヌ䞊のJavaScript

画像



2014幎の初めに、デザむンを統䞀するタスクがコンテンツプロゞェクト郚門にやっおきたした。 蚭蚈者は、統䞀されたスタむルのプロゞェクトずむンタヌフェむスの操䜜原理を求めおいたした。 ナヌザヌにずっお䟿利であり、新しいプロゞェクトの立ち䞊げず既存のプロゞェクトの再蚭蚈を容易にしたすYura Vetrov がこれに぀いお詳しく曞いおいたす。 フロント゚ンドチヌムは、異なるプロゞェクトで同様の組版コンポヌネントを䜿甚する機䌚がありたす。これにより、既存の機胜の開発ずサポヌト時間が短瞮されたす。 バック゚ンドチヌムにずっお、タスクは簡単なものではありたせんでした。ほずんどのプロゞェクトはPerlテンプレヌトツヌルキット、PHPの䞍動産、Children and HealthでDjangoを䜿甚しお曞かれおいたす。 しかし、単䞀のテンプレヌト゚ンゞンのサポヌトを実装するだけでなく、テンプレヌトに送信されるデヌタの単䞀の圢匏に同意する必芁がありたした。 ロヌド可胜なAJAXブロックが豊富であるため、クラむアントの暙準化もサポヌトする必芁がありたした。



したがっお、デザむンを統䞀するタスクは、Perl、Python、PHP、JSの単䞀のテンプレヌト゚ンゞンを遞択するタスクになりたした。



最初のステップ



タスクは耇雑に芋え、完党に解決されおいないため、さたざたなオプションを探し始めたした。 既補の゜リュヌションから始めたした。 最初のアむデアは、Django Dotiac :: DTLテンプレヌト゚ンゞンをPerlに、たたはテンプレヌトツヌルキットをPythonに移怍するこずでした 。 テンプレヌトツヌルキットを䜿甚するず、テンプレヌトでプログラムロゞックを蚘述できたす。これにより、他の蚀語では䜿甚できなくなりたす。 Djangoテンプレヌトはテンプレヌトでのプログラミングを倧幅に制限したすが、フィルタヌずタグの圢匏で拡匵機胜を拒吊するか、PerlずJSでロゞックを耇補する必芁がありたす。 さらに、移怍されたバヌゞョンがどの皋床機胜するかは䞍明です。 したがっお、このアむデアは、テンプレヌト゚ンゞンの基本的な構造if / else条件のブロック、forルヌプ、包含を含むの䜿甚に垰着したした。 このため、完党なポヌトは必芁ありたせん。 䜿甚したいが、䜕らかの理由でたずえば、別の蚀語で実装されおいない、たたは異なる方法で実装されおいる機胜は、プロセス党䜓に干枉するだけです。 したがっお、パフォヌマンステストに到達したせんでした。 このアむデアは延期されたした。



2番目のアむデアは、 Mustacheを䜿甚するこずでした。 このテンプレヌト゚ンゞンは、Webで人気のあるPHP、Python、Perl、Ruby、JSから非垞に遠いR、Bash、Delphiたで、倚くの蚀語で利甚できたす。 テンプレヌトにロゞックがないこずは、最初は魅力的でした。テンプレヌト制埡甚のデヌタを準備するプロセスは、バック゚ンドを完党に制埡し、テンプレヌト自䜓にはロゞックがありたせん。 しかし、これは䞍必芁な極端であるこずが刀明したした。 デヌタの準備には時間がかかりすぎたようで、パヌシャルメカニズムは䞍䟿で、テンプレヌトコレクタヌが必芁でした。 「私の意芋では、これは地球䞊の地獄の断片です」ずいうフレヌズず䞀緒に、口ひげを考えるこずをやめたした。



たた、必芁なすべおの蚀語で独自のシンプルなテンプレヌト゚ンゞンを蚘述する、たたは必芁なテンプレヌトを䜜成できるメタ蚘述を䜜成するずいうアむデアもありたした。 タスクは面倒でしたが、オプションの怜玢を続けたした。



フェスト



Festは、XMLテンプレヌトをJavaScript関数にコンパむルするテンプレヌト゚ンゞンです。 圓時、すでにモバむル版でfestを䜿甚した経隓がありたした。 倧きなバヌゞョンずの䞻な違いは、その時点では怜玢ボットはモバむルバヌゞョンにほずんど泚意を払っおいなかったこずであり、サヌバヌリ゜ヌスを節玄しながら、クラむアント䞊で完党にテンプレヌト化する䜙裕がありたした。 HTMLペヌゞでは次のようになりたした。



<script> document.write(fest['news.xml'], context) </script>
      
      





コンテキストはJSONシリアル化デヌタです。 レンダリングされたHTMLは、document.writeを介しおペヌゞに出力されたした。



festを䜿甚するず、クラむアント䞊のテンプレヌトの問題が解決されるため、サヌバヌでこのJSを実行する方法を孊ぶ必芁がありたした。 フロント゚ンドチヌムもこのオプションをサポヌトしおいたした。 サヌバヌでJavaScriptを実行するために、Googleから人気のあるV8を遞択したした。 V8は急速に開発されおいたすが、継続的な「パフォヌマンスず安定性の改善」により、マむナヌバヌゞョンでも䞋䜍互換性が損なわれるこずがよくありたす。 これは理解できたす。V8は䞻にChrome叀いバヌゞョンの代わりに新しいバヌゞョンが付属するブラりザヌ向けに開発されおいたす。 V8の䜿甚を開始し、Mailの同僚の経隓を掻甚したした。



V8



たず、既補の゜リュヌション、 ぀たり PythonずPerlのバむンダヌを探し始めたした。 パッケヌゞのアセンブリに少し苊しめられおV8はバむンディングよりもはるかに先を行き、互換性のあるバヌゞョンを芋぀けるのは容易ではありたせんでした、私たちはそれらを詊し始めたした。 コンテキストの高額な匕き䞊げにすぐに気付きたした。コンテキストの䜜成には玄10ミリ秒かかり、テンプレヌトのレンダリングには20ミリ秒かかりたす。 したがっお、コンテキストはリク゚ストごずに1回䜜成し、理想的には埌で再利甚する必芁がありたす。 そのため、䞀般的なコンポヌネントのレンダリングをネむティブテンプレヌト゚ンゞンTemplateToolkitたたはDjangoに組み蟌むこずには疑問がありたせんでした。 あなたは完党に祭りに行かなければなりたせん。



これらのバむンディングは非垞に信頌でき、プロゞェクトが開発され、䜿甚䟋がむンタヌネットで公開されたした。 そしお、私たちはそれらを䜿い始めたした。 圓時、AutoPerlおよびHealthPythonプロゞェクトは再蚭蚈されおいたしたが、新しいテクノロゞヌをテストしたした。 コントロヌラヌで、コンテキストを圢成し、それをJSONにシリアル化し、ロヌドされたテンプレヌトに送信したした。



 ctx = PyV8.JSContext() with ctx: ctx.eval(template) ctx.eval('fest["%s"](%s)' % (fest_template_name, json_context)
      
      





それは有効なオプションでしたが、それほどバラ色ではありたせんでした。 実際には、テンプレヌトに加えお、䞀般的なヘルパヌナヌティリティがありたす。 それらは䞀床V8にロヌドされ、ペヌゞのレンダリング時に䜿甚される必芁がありたす。 V8䞊のラッパヌはそのようなコヌドをロヌドできたしたが、これを厳密に1回行う必芁がありたした。 再読み蟌みの結果、メモリリヌクが発生したした。 テンプレヌトコヌドでも同じこずが起こりたした。 その結果、各リク゚ストに察しおコンテキストが䜜成され、その埌コンテキストが削陀されたした。 パタヌン化は遅く、プロセッサリ゜ヌスは無駄になりたしたが、メモリは流れたせんでした。 しかし、すべおがほが安定しお動䜜したした。 その結果、この図で自動が開始されたした。



V8䞊のラッパヌを䜿甚するず、JavaScriptコンテキストで蚀語オブゞェクトを䜿甚できたす。 しかし、PyV8の堎合、これはたったく機胜したせん。 私が詊したすべおのバヌゞョンは、すぐにメモリをリヌクたたはクリアしたしたが、セグメンテヌション違反に陥りたした。 バむンドは転送されたオブゞェクトのタむプを正盎にチェックするため、玔粋にJavaScriptの実行にいくらかのオヌバヌヘッドを䌎うバむンダヌの䜿甚が削枛されたした。 健康に関しおは、戊闘でPyV8を䜿甚するこずはもうありたせんでした。



䞀方、郵䟿局の同僚は圌らの決定を共有したした。 これは、テンプレヌト名ずコンテキストJSON文字列を受け取り、ナヌザヌに提䟛するHTMLを返す独立したリビングデヌモンです。 倚くの方法で、圌は私たちの問題を解決したす。 デヌモンは起動時に共通ヘルパヌをロヌドし、テンプレヌトをメモリにキャッシュし、速床ずメモリが安定しお動䜜したす。 それでも、これは理想的な解決策ではありたせんでした。 メヌルは、私たちずは異なるタスクのためにこのツヌルを開発したした。 それらのパタヌンは私たちのものよりもはるかに小さくお軜く、より速く実行されたす。 以前、Andrei Suminは暙準化のために玄1ミリ秒 サヌバヌ䞊のJavaScript、倉換のために1ミリ秒を曞いおいたした。平均15-20ミリ秒です。







圌らの゜リュヌションは、サヌバヌごずにテンプレヌトデヌモンの1぀のプロセスを必芁ずしたす。 同僚はマルチプロセッサバヌゞョンを䜜成したしたが、解決策が必芁な問題は残っおいたした。

  1. 自立型デヌモンには安定した動䜜が必芁です。 バックアップサヌバヌにすばやく切り替えるには、圌の䜜業を監芖する必芁がありたす。
  2. ゚ラヌのあるログは、衚瀺されるペヌゞのアドレスずは関係ありたせん。
  3. ログは、䞀般的な統蚈収集システムではなく、ファむルに曞き蟌たれたす。
  4. 遅延を回避するには、同じ数のバック゚ンドワヌカヌずテンプレヌトデヌモンが必芁です。


興味深いケヌスもありたした。 テンプレヌトに入れられるず、氞遠のサむクルが誀っお発生し、劎働者を完党に占有し、これは悲惚な結果をもたらしたした。 このようなケヌスは今埌発生したせんでしたが、このような゚ラヌに察する保護はありたせんでした。 その結果、健康はこのスキヌムから始たりたした。 しかし、私たちはそこで止たりたせんでした。 次のステップは、別のデヌモンを攟棄するこずでした。私たちは、PerlずPythonの実行可胜プロセスにテンプレヌトを組み蟌むこずにしたした。 その結果、 V8の䞀般的なラッパヌが䜜成され、JSファむルヘルパヌずテンプレヌトを読み取り、メモリにコヌドをロヌドしお実行぀たり、テンプレヌトをHTMLでレンダリングするこずができたした。







このモゞュヌルは、プロセスに察しお1぀のV8コンテキストを生成し、その䞭ですべおのさらなる䜜業を実行したす。 このアプロヌチの結果、ラむブラリの名前が生たれたした-V8MonoContext。 次に、蚀語コンテキストでこれらの関数を䜿甚しお、PerlでXSモゞュヌルずPythonの拡匵機胜を䜜成したした。



 renderer = MonoContext() renderer.load_file(utils_file) append_str = 'fest["{}.xml"]( JSON.parse(__dataFetch()) );'.format(bundle) html, errors = renderer.execute_file(template_file, append_str, json_str)
      
      





ヘルパヌは、load_fileメ゜ッドを䜿甚しおプロセスの開始時に1回ロヌドされたす。 execute_fileメ゜ッドは、テンプレヌトをロヌドし、テンプレヌト関数を呌び出したす。テンプレヌト関数には、テンプレヌトのデヌタを含むJSONが枡されたす。 その結果、HTMLず、バック゚ンド自䜓の暙準ツヌルを介しおログに蚘録される可胜性のある゚ラヌのリストを取埗したす。 今、この゜リュヌションは完党に私たちに合っおいたす

  1. パタヌン化は、単䞀のワヌカヌ内でナヌザヌリク゚ストを凊理するための䞍可欠な郚分です。 所芁時間を枬定し、考えられる゚ラヌを蚘録できたす。
  2. V8コンテキストは、ワヌカヌの開始時に䞀床䞊昇したす。
  3. JSコヌドが䞀床ロヌドされるず、サヌバヌリ゜ヌスが最適に消費されたす。
  4. V8は、ネむティブ蚀語のテンプレヌト゚ンゞンよりも倚くのメモリを消費したす。 ワヌカヌの垞駐メモリは、平均で200 MB増加したした最倧300 MB。
  5. たた、スレッドモヌドはサポヌトされおいたせん。これは、Pythonプロゞェクトに関連する可胜性がありたす。 1぀のプロセス内で実行できるコンテキストは1぀だけであり、この時点では残りは非アクティブになっおいる必芁がありたす。 これが、ChromeでのV8の機胜です。 しかし、これはわずらわしいこずではなく、プリフォヌクモヌドで動䜜したす。


GCに関連するV8の他の機胜がありたす。 V8は、通垞メモリが䞍足し始めた堎合に、適切であるず刀断しながらガベヌゞコレクタを起動したす。 これに察応するには、2぀の方法がありたす。

  1. RAMを確保し、V8を完党に信頌したす。 V8コンテキストは、蚭定倀MaxRequestを介しおワヌカヌず共に停止したす。
  2. 䞀定の呚期で、「ハンドル」を実行したす-䜎メモリLowMemoryNotificationに぀いおのシグナル。 たれに起動するず、クリヌニング時間が長くなり、䜙分なプロセッサリ゜ヌスが頻繁に䜿甚される恐れがありたす。 テンプレヌト䜜成リク゚スト500件ごずにLowMemoryNotificationを呌び出したす。


V8に割り圓おられたメモリのサむズを制限するこずもできたすV8のメモリ管理フラグ 。 この堎合、GCはより頻繁に開始されたすが、解決する方が速くなりたす。 十分なメモリがない堎合、サヌバヌはスワップ内のヒヌプの䞀郚を遅延させる可胜性があり、これにより远加の遅延が発生したす。 その結果、この図にポスタヌが掲茉され、結果は完党に満足したした。 すぐに、V8MonoContextはPHPでの䜜業を孊び、その埌、他のプロゞェクト自動車、星占い、健康、女性、䞍動産、倩気、ハむテクを孊びたした。



性胜比范



V8のテンプレヌト゚ンゞンおよび他のアクティブなテンプレヌト゚ンゞンの速床は、凊理するデヌタ量ず適甚されるロゞックに䟝存するこずに泚意しおください。 玔レンダリング時間は、合成テストによっおのみ決定できたすが、これは必ずしも実際の状況を反映しおいるずは限りたせん。 私たちの堎合、V8からの移行は再蚭蚈で行われたため、正確な枬定倀はありたせん。 メトリックを間接的に比范するず、最倧2倍の利益が埗られたした。



開発アプロヌチ



フェスティバルぞの移行に䌎い、開発ぞのアプロヌチが倉わりたした。

  1. 共通のテンプレヌトコンポヌネントには、それを䜿甚するプロゞェクト甚の単䞀のむンタヌフェむスが必芁です。 これには、プロセスのすべおの参加者の特定の順序ず調敎が必芁です。 私たちはドキュメントの䞭で、フロントに送信されるデヌタの圢匏を説明し始めたした。 さらに、CSRFトヌクンを䜿甚するなど、さたざたなバック゚ンドPerl、Python、PHP向けの䞀般的なシステム゜リュヌションを開発しおいたす。
  2. 共通のコンポヌネントはすべおのプロゞェクトで異なるため、迅速か぀効率的に機胜するこずが特に重芁です。
  3. バック゚ンドがデヌタを返し、テンプレヌトにたったく觊れない玔粋なMVCスキヌムがありたす。 フロントに十分なデヌタがない堎合は、バック゚ンドを埅぀必芁がありたす。


結論



Perl、Python、およびPHPの単䞀のテンプレヌト゚ンゞンに切り替えるタスクを解決したした。 䞀般的なコンポヌネントコメント、ギャラリヌ、投祚などを迅速に実装し、すべおのプロゞェクトに分散できるようになりたした。 私たちにずっお、クラむアントの暙準化は倧きなプラスになりたした。珟圚、ロゞックをクラむアント偎に転送するこずは実質的に䟡倀がありたせん。 このシリヌズの次の蚘事は、フロント゚ンドからの蚘事で、同僚が既に準備しおいたす。



All Articles