サヌバヌ䞊のJavaScript、倉換ごずに1ミリ秒

なんで





「なぜ」ずいう質問は、決定を䞋す際に最も重芁です。 私たちの堎合、いく぀かの理由がありたした。



たず第䞀に、人々。 珟圚のテンプレヌト゚ンゞンはCによっお凊理されたした。 圌の倉曎に関するすべおの質問はすぐに解決されたせんでした。 そしお最も重芁なこずは、テンプレヌト゚ンゞンを曞いた人もいたすが、たったく別の人がそれを䜿甚したした。



䞀般に、これは頻繁に行われるものであり、私の意芋では、レむアりト蚭蚈者向けのツヌルを曞くこずはあたり良い習慣ではありたせん。 ツヌルが必芁であるこずは明らかですが、レむアりト蚭蚈者の日垞のタスクを非垞にリモヌトで想像しおいる人は、これらのツヌルを理解しおいたす。 むしろ、それどころか、「条件ずサむクルを曞かせお、レむアりトにこれ以䞊䜕も必芁ないようにする」ずいう蚈画の決定がしばしば䞋されたす。 おそらく、これはレむアりト蚭蚈者自身ず圌らの資栌のせいです。



しかし、Mail.Ru Groupには、JSを知っおおり、自分でツヌルを曞くこずができる有胜な人々のチヌムがあり、最も重芁なのは、それを䜿甚するこずです。



第二に、タスク。 プロゞェクトMail@Mail.ruを取りたす。 サヌバヌでのテンプレヌト䜜成を拒吊するこずはできたせん。最初のログむンで高速にロヌドする必芁がありたす。 クラむアントの暙準化を拒吊するこずはできたせん。ナヌザヌは自分の行動に察する高い反応率を確認する必芁がありたす。぀たり、クラむアントのAJAXず暙準化が必芁です。



問題は明らかです。サヌバヌずクラむアントで完党に異なるテンプレヌトの2぀のセット。 そしお、最も䞍快なのは、圌らが同じ問題を解決するこずです。 ロゞックの耇補は私たちを疲れさせたした。



v8はJavaScriptむンタヌプリタヌです。぀たり、サヌバヌずクラむアントの䞡方で機胜する1぀のテンプレヌトを取埗できたす。



第䞉に、スピヌド。 v8の速床を称賛する倚くの蚘事を読んだ埌、私たちはそれらの公平性を怜蚌する必芁があるず刀断したした。 しかし、最初に、新しいテンプレヌト゚ンゞンをどのように芋たいかを理解する必芁がありたした。



必芁なもの





倉換のためのサヌバヌ時間は非垞に限られおいるため、非垞に機胜的なものに気付くこずはありたせんでした。 ただし、v8からレむダヌを远加する点で唯䞀の違いを残しお叀い機胜を残すのは奇劙な考えです。



私は長い間XSLTを頻繁に䜿甚しおいたす倉換の最速バヌゞョンではありたせんが、正しく䜿甚するず、良い数倀を瀺したすlibxsltに぀いお話しおいる。 ただし、XSLTにはテンプレヌトの再定矩ずいう非垞に匷力なテンプレヌトツヌルがありたす。 類䌌したものを実装するこずにしたしたが、はるかに簡単です。



/head.xml 
 <title><fest:get name=”title”/></title> <fest:set name=”title”>Mail.ru</fest:set> /mail.xml 
 <fest:include src=”head.xml”/> <fest:set name=”title”> Mail.ru</fest:set>
      
      







v8を䜿甚し、テンプレヌトぞのJavaScriptアクセスを蚱可しないのは奇劙です。



 <fest:script> var text = “mail.ru” </fest:script> <fest:value>text</fest:value>
      
      







そしお、暙準的な条件ずサむクルに加えお、ささいなこずに぀いおはもっずたくさん。



XML





テンプレヌト゚ンゞンの構文ずしおXMLを䜿甚したした。



IDEの基本機胜のサポヌト。 人気のあるIDEの100がXMLを知っおいたす。 ハむフネヌション、バックラむト、基本的なオヌトコンプリヌトは無料です。



IDEレベルの怜蚌。 有効なHTMLは、有効なテンプレヌトから取埗されたす。 繰り返したすが、すべおのIDEはxml自䜓を怜蚌できたす。



すぐに䜿えるモゞュラリティ名前空間。 テンプレヌト゚ンゞンの基本機胜は、非垞に迅速に拡匵する必芁がありたす。 たずえば、耇数の蚀語でプロゞェクトを実行できるタグを远加したす。 名前空間を䜿甚するず簡単になりたす。



幅広い垂販のツヌル。 長幎にわたっお、XMLを凊理するための倚くのツヌルが蓄積されおきたした。たずえば、XSLたたはSAXパヌサヌのクラス党䜓を䜿甚しおXMLを凊理するためのラむブラリ、怜蚌甚のXSDおよびDTDスキヌムなどです。



凊理構造の構文ず結果の構造の䞀臎。 蚀い換えれば、XMLからXMLぞの䜜成は䟿利であり、フェストテンプレヌトは読みやすいです。 さらに、すべおのデヌタシヌルドの問題が解決されたした。



実装









カりボヌむ 私自身、最近そのような甚語があるこずを知りたした。



それ以前は、タスクを完了するための最も信頌できる方法は、プログラミングずテストのペアであるず確信しおいたした。 い぀ものようにテストは報われたしたが、ペアリングプログラミングが代替手段を芋぀けたした。



このタスクず兞型的なタスクずの違いは、テンプレヌトず、このテンプレヌトが生成する結果のHTMLです。 KostyaFrontend Mail Developerず私は独自​​の実装を曞き始めたした。 週に䞀床、倉換速床の枬定倀を比范したした。



私たちは2぀の異なるアプロヌチを遞択したした。圌はテンプレヌトを関数にコンパむルし、私は構造にコンパむルしたした。 最も単玔な構造の䟋



 01 [ 02 {action:"template"}, 03 "<html>...", 04 {action:"value"}, 05 "json.value" 06 ]
      
      







2行目は、パタヌンの始たりを瀺しおいたす。 3぀目は、単にブラりザに枡すこずです。 4぀目は、5぀目はJavaScriptずしお実行する必芁があり、実行結果はブラりザに枡す必芁があるこずを瀺しおいたす。



 01 [ 02 {action:"template"}, 03 "<html>....”, 04 {action:"if"}, 05 "json.value", 06 "<span>true</span>", 07 "<span>false</span>" 08 ]
      
      







オプションはもう少し耇雑です。 4行目は、5行目を実行する必芁があるこずを意味し、結果がtrueたたはfalseの堎合、それぞれ6行目たたは7行目を指定したす。



この機胜を備えたオプションは、特に説明する必芁はありたせん。



 01 function template(json){ 02 var html = ""; 03 html += "<html>
"; 04 html += json.value; 05 return html; 07 }
      
      







今埌は、圌のバヌゞョンの方が速かったず思いたす。 しばらくの間、私たちはほがスムヌズに歩きたしたが、構造を備えたバヌゞョンははるかに早く倩井に達したした。



私がこのアプロヌチを䞎えたこずを理解するために私の最初の実装はタスクを200ms完了したした。 可胜なすべおを絞り出しお、2぀のプログラムのベストを組み合わせたずき、3ミリ秒になりたした。



珟圚の実装を簡単に説明するず、サむクルをサむクルに、条件ステヌトメントを条件ステヌトメントなどに倉換したす。



 fest:foreach for(i = 0; i < l; i++) {} fest:if if(value) {} fest:choose if(value) {} else {}
      
      







コンテキストの絞り蟌みはありたせん。 はい、これは制限ですが、コンテキストを制限するためのオヌバヌヘッドはありたせん。最も重芁なこずは、コンテキストを絞り蟌むずすぐに、グロヌバルコンテキストたたはコンテキストからレベルを䞊げるタスクがすぐに発生するこずです。



テンプレヌトが厳栌モヌドで動䜜するJS関数に倉換されるこずが重芁です。 これは、メモリリヌクに぀ながるコヌドを䜜成する機䌚をコヌダヌに䞎えたせん。



デヌタを論理的に凊理する必芁がある堎合はい぀でも、JavaScriptを䜿甚できたす。



 <fest:if test=”_javascript_”></fest:if> <fest:value>_javascript_</fest:value>
      
      







JavaScriptを含むすべおの構成䜓は、try catchにラップされたす。



JavaScriptの実行埌にHTML出力を前提ずするすべおの構成は、デフォルトでHTML゚スケヌプになりたす。



 <fest:value>json.name</fest:value>
      
      





 try { html += __escape(json.name) } catch(e) {}
      
      







テンプレヌト゚ンゞンの開発は、最初からオヌプンな圢で行われおきたした。

https://github.com/mailru/fest



統合オプション





䞀方、v8はJavaScriptを解釈できるラむブラリにすぎたせん。 それ自䜓では、圹に立たないようです-システムにアクセスできたせん。 しかし、䞀方で、他の蚀語に簡単にねじ蟌たれたす。



CおよびPerlプログラミングの経隓がないため、䞡方の蚀語でテストケヌスを䜜成したした。 さらに、珟時点ではPythonがたくさんありたす。



そしおもちろん、プロトタむプずブラりザヌ甚のNodeJSは、JavaScriptテンプレヌトがそのたた䜿甚できる環境です。



戊闘条件に近い





3msを受け取った埌、サヌバヌ偎のプログラマヌに行きたした。 ナヌザヌのメヌルのリストを送信するリク゚ストにどれだけの時間があるかを尋ねられたずき、圌らは蚀った4ms以䞋。 倉換にはすでに3msありたしたので、詊しおみたした。



私たちが持っおいる文字のリストは、Cで曞かれた独自のhttpサヌバヌによっお䞎えられたす。 デヌタ取埗-プロセッサず競合しない操䜜なので、枬定されたせんでした。 倉換甚のデヌタの準備ず倉換自䜓は停止したした。



歎史的な理由から、httpサヌバヌはデヌタをフラットハッシュに保存したす。



 msg_length = 5 msg_1_title = “letter” msg_1_Unread = 1
      
      







JavaScriptに぀いお話しおいるので、最初に思い浮かぶのはJSONです



 msg = [ {title: “letter”, Unread: true} ]
      
      







テンプレヌトをv8に倉換するずきにJSONを䜿甚しおJavaScriptを操䜜するず、フラットハッシュの行をメモリに入れお結果を出し始めたした。



私たちは倚くのオプションを詊したした。 オブゞェクトを転送し、文字列を転送しおJavaScriptで解析し、文字列を転送しおJSON.parseに枡したす。



奇劙なこずに、フラットハッシュをJSONに䞀臎する文字列に倉換し、v8に文字列を䞎えるのが最速であるこずが刀明したした



 “template([ {title: \“letter\”, Unread: true} ])”
      
      







しかし、すべおにもかかわらず、2ミリ秒の倉換で6ミリ秒になりたした。 誰もがgiveめる準備ができおいたした。 それでも、゜ヌスデヌタ、フラットハッシュを含む行を取埗し、同じコンパむル枈みテンプレヌトを䜿甚しお、NodeJSで必芁なHTMLを取埗するこずにしたした。



4ミリ秒。 この番号でシシニコフに来たずき、「クヌルですが、NodeJSには曞くリ゜ヌスがありたせん」ずいうフレヌズを正盎に期埅しおいたしたが、代わりに「NodeJSが4msでできるなら、私たちもできたす」







その瞬間に気付いたのは、これを本番環境に持ち蟌むこずです。 第二の颚がありたした



解決策は簡単でした。 デヌタの準備に時間の67を倱い、原則ずしお既にデヌタを持っおいるので、デヌタの準備を捚おる必芁がありたす。



__get 'key'関数をv8に投入したした。 したがっお、v8からは、httpサヌバヌのハッシュから盎接デヌタを取埗したした。 目的の圢匏ぞのデヌタ倉換はありたせん。 この文字列からv8内のオブゞェクトぞの倉換はありたせん。 3ミリ秒で出発し、1ミリ秒の予玄がありたした。







ほが生産





だから、すべおが玠晎らしく芋えたすが、私たちも生産に近づいおいたせんでした。 手がかゆみしおみおください。



別のサヌバヌを甚意し、v8で動䜜するhttpサヌバヌのバヌゞョンを䞊げお、実際のリク゚ストを耇補したす。 2.2 GHz Xeonのコアを30時間攟眮したす。



 10,000,000件以䞊のヒット
平均倉換時間1.6ms

 992 422 2〜5ミリ秒の10
 208 464 5〜10ミリ秒の2
 10ミリ秒以䞊39 649 0.4




2msを超えるのはわずか12でした。 v8はメモリから安定しお動䜜したす。



生産





私は最埌の数字で副テクニカルディレクタヌに来お、v8は生産の準備ができおいるので、別の小さなプロゞェクトを䜜成する必芁があり、倱敗した堎合には忘れおしたう可胜性がありたす。 これに応えお、圌は「数字は良奜で、倱敗がひどくない別のプロゞェクトは正しいですが、本圓にv8を立ち䞊げたいですか」 Mail.Ruホヌムペヌゞから開始したす。 質問は正しく提起されおいたす-私たちはビゞネスをしおいる、たたは傍芳者を楜しんでいたす。



フェストのメむンペヌゞのレむアりトには3日かかりたした。 バランサヌから1぀のサヌバヌの電源を切り、バヌゞョンをv8でアップロヌドし、リク゚ストを耇補したした。 すべおの蚈算は、単䞀のデヌモン/カヌネルのコンテキストで行われたす。



さらに、良い結末で非垞に有益な話をしたす。



グラフの衚瀺内容を垞に詳现に確認しおください。 テストサヌバヌに半分の負荷をかけたす。 CPU消費は通垞の3倍でした。 これは、珟圚のテンプレヌト゚ンゞンず比范しお、リ゜ヌスの6倍の損倱ずいう障害のように芋えたした。



圌らは芋始めたした。 ここでは、メむンアヌキテクチャに぀いお少し説明したす。 さたざたなプロゞェクトから情報を収集したす。 内郚開発を収集し、RBず呌びたす。 メむンを返すために生成される165kbのうち、100kbがRBを収集したす。 そしお、次のこずが起こりたすRBはHTMLピヌスをv8のhttpサヌバヌを通しお送信し、v8はそれらを独自の文字列で連結し、結果はこれらすべおをhttpサヌバヌに返したす。



二重デヌタ転送がありたす。 最適化されたした。 v8では、RBからのデヌタを含む1぀の倧きな行を構築する代わりに、デヌタを盎接httpサヌバヌに送信したす。



 __push_string('foo'); __push_rb(id); __push_string('bar');
      
      







さらに、v8には文字列の連結がなく、サヌバヌからv8ぞ、たたはその逆ぞのダブルRB転送はありたせん。最も重芁なこずは、デヌタ転送はutf-8からutf-16ぞ、たたはその逆ぞの倉換です。 V8はすべおをutf-16に保存したす。



利益があり、リ゜ヌスは3぀ではなく通垞の2倍に消費されたした。 ぀たり 私たちはただ4回負けおいたしたが、すべおを絞っおしたったように芋えたした。



そしお今、有益な郚分。 興味を匕くために、テストした負荷に、マシン䞊の悪魔の数ずマシンの数の2を掛けたした。 4億4千䞇件のヒットを受けたした。 さらに、1日あたり1億1,000䞇件のヒットがありたす。 曖昧な疑いが忍び蟌んだ。



ログを芋おみたしょう。 負荷のあるリク゚ストごずに、統蚈のログにレポヌトを含む3぀のリク゚ストを受け取ったこずが刀明したした 1぀のhttpサヌバヌの実際の負荷は、テス​​ト察象の4倍です。



翌朝、v8のメむンペヌゞのバヌゞョンを公開したした。



今日のデヌタ

v8が生成するHTMLのサむズは65kbです。

時間、リク゚スト1msあたりv8の䜜業。

平均しお、v8ではコンテキストごずに40MBが必芁です。



いく぀かの説明





v8に぀いお考えおいるすべおの人が、Igor Sysoevによる蚘事を芋぀けたしたsysoev.ru/prog/v8.html



このタスクに取り組んでいる間ずっず、v8開発者Vyacheslav Egorovhttp://mrale.phが私たちを倧いに助けおくれたした。



蚘憶の恐怖は正圓化されたす。 正しい操䜜が重芁な堎合メモリ䞍足が通垞の状況である堎合、問題が発生したす。 割り圓お゚ラヌを正しくキャッチできたすが、これに぀いおできるこずは、正しく再起動するこずだけです。



しかし、正盎に蚀うず、重芁な補品は1぀だけです。 メむンペヌゞに぀いおは、倧量のメモリがあり、非垞によく監芖しおいたす。



v8トランクが流れおいるこずがわかりたした。 Vyacheslavはこれを再珟できたせんでしたが、開発者がリヌクを発芋するのに圹立぀テストケヌスをたずめるず思いたす。 バヌゞョン3.6はメモリから正垞に動䜜したす。



䟿利なリンク



-github.com/mailru/festテンプレヌト゚ンゞン

-code.google.com/p/v8 v8 API

-Igor Sysoevによるsysoev.ru/prog/v8.html蚘事





Andrey Sumin、開発郚長、クラむアントパヌトMail.ru



All Articles