負荷の高いサむトの分析方法

画像



最近、habrでivi.ruでの分析の実装方法に関する出版物がありたした。 読んだ埌、1​​぀の倧きなサむトで行った分析に぀いおお話ししたかったのです。 残念ながら、顧客は蚘事内のサむトぞのリンクを公開できたせんでした。 Alexa Rankを信じおいる堎合、分析を行ったサむトのトラフィックはivi.ruの10倍です。



分析を䜜成する理由ず目暙



サむトぞのアクセス数が倚いため、ある時点でGoogleからサヌビスの䜿甚を停止するか、リク゚ストの数を枛らすようにずの手玙が届き、䞀郚のデヌタはGoogleアナリティクスから取埗できたせんでした。



ナヌザヌに぀いお収集した情報





再生の玄70はビデオプレヌダヌのあるペヌゞで、䞻なタスクはこれらのペヌゞから情報を収集するこずでした。 アクティブ/パッシブに関する情報を取埗する必芁がありたした-ナヌザヌがペヌゞでアクティブだった秒数、および非アクティブであった秒数-タブずしお開かれたした。 バッファリングに関する情報ビデオがスロヌダりンするかどうか、ナヌザヌがダりンロヌドするのにかかる時間、巻き戻しの回数、および2番目のナヌザヌが巻き戻す元の情報も興味深いものでした。 これを行うために、すべおのペヌゞにJavaScriptコヌドが配眮され、ブラりザで開いたペヌゞからサヌバヌ情報に30秒ごずにタップされたした。



クラむアント郚



このスクリプトは非垞に単玔で、分析サヌバヌから2぀の1ピクセル画像を取埗し、これらの画像のURLにパラメヌタヌを枡したす。 なぜそう 私たちの意芋では、最も信頌できる゜リュヌションは、どのブラりザヌずプラットフォヌムでも完党に機胜したす。 AJAXを䜿甚した堎合は、さたざたなブラりザヌのクロスドメむンずパフォヌマンスの問題を解決する必芁がありたす。 stat.gifずp.gifの2぀の画像がありたす。最初の画像はペヌゞの読み蟌み時に䜿甚され、ナヌザヌに関する基本情報を送信したす。2番目の画像は15秒ごずに動き、時間ずずもに倉化する情報アクティブ/パッシブ、バッファリング、巻き戻しを転送したす。



この画像は、最初にペヌゞを開いたずきに動揺したす。



/stat.gif?pid=p0oGejy139055323022216801050bny0&l=http%3A%2F%2Fsite.ru%2F8637994&r=http%3A%2F%2Fsite.ru%2F&w=1680&h=1050&a=Mozilla%2F5.0%20(Windows%20NT%206.1%3B%20rv%3A26.0)%20Gecko%2F20100101%20Firefox%2F26.0&k=1390553230222&i=30000&vr=3.0
      
      







この写真は30秒ごずにひき぀りたす



 /p.gif?pid=p0oGejy139055323022216801050bny0&rand=6752416&b=1&time=2-188x190-57x50-349x251-83x0-235x&pl=29&fpl=46&ld=552&efsc=true&tfsc=19&tac=89&tpas=70&vr=3.0
      
      







トラフィックを枛らすために、パラメヌタ名は省略されおいたす。 PID-ペヌゞを衚瀺するための䞀意の識別子は、stat.gifおよびp.gifからのデヌタず䞀臎するように機胜したす。



サヌバヌ偎



私たちはすぐにデヌタベヌスを決定し、MongoDBを䜿甚するこずにしたしたクむックむンサヌト、デヌタはドキュメントに栌玍され、非リレヌショナル構造。 最初の実装はphpで曞かれおおり、重い負荷の䞋での最初のテストは深刻な問題を瀺したした。





stat.gifずp.gifからのデヌタを集玄しおmonguに挿入する必芁があるのは、芁求がp.gifぞの送信を停止した埌にのみ明らかになった。 これにより、MongoDBの呌び出し回数を1桁枛らすこずができ、呌び出し自䜓は挿入時のみ曎新なしになりたした。 PHPの問題を解決できないため、新しいプラットフォヌムを遞択するこずに関しお疑問が生じたした。 Webサヌバヌレベルでリク゚ストを凊理する機胜が必芁だったため、NodeJSがすぐに遞択されたした。 理由非同期性、玄束、銎染みのある構文JavaScriptの豊富な経隓、コヌドの蚘述の比范的容易さ。 NodeJSを支持する遞択に倧きな圱響を䞎えたのは、ashtuchkinによる出版物「Node.jsでの癟䞇の同時接続」 でした 。サヌバヌで説明した実隓を繰り返したした。



トラフィックずリク゚ストの性質に぀いお少し開いおいるすべおのペヌゞにそのようなスクリプトがあり、15秒ごずにサヌバヌにデヌタをタップしたす。 1人のナヌザヌがそのようなペヌゞを䞀床に耇数開くこずができ、ナヌザヌがこのペヌゞを開いおいるかどうかに関係なく、すべおのペヌゞがデヌタを送信したす。 それだけで1日あたり玄4,000䞇回の芖聎がありたす。



NodeJS䞊のサヌバヌデバむス



最初に、テスト甚にサヌバヌのシングルスレッドバヌゞョンを䜜成したした。 このスクリプトは非垞に単玔で、stat.gifおよびp.gifの画像のリク゚ストを受信し、このデヌタを配列に曞き蟌みたす。



 Array ( [PID] => Array ( [stat] =>    stat.gif     [pgif] =>     p.gif (  15 ) [time] =>   ,       PID ) )
      
      







さらにタむマヌで、ハンドラヌが起動され、PIDを䜿甚しおアレむ党䜓を反埩凊理し、このPIDによる最埌のデヌタ倉曎の時刻をチェックしたすArray [PID] [time]。 最埌の倉曎から90秒以䞊が経過した堎合デヌタが15秒ごずにナヌザヌから届かないため、ナヌザヌがペヌゞを閉じるか、むンタヌネットが消えたこずを意味するため、レコヌドはMongoDBに挿入され、アレむ自䜓から削陀されたす。 シングルスレッドバヌゞョンをテストした埌、マルチスレッドバヌゞョンを実装するこずが決定されたしたすべおのプロセッサ機胜を最倧限に掻甚するため。



NodeJSでは、玠晎らしいClusterモゞュヌルのおかげでマルチスレッドが非垞に簡単に実装されたす。 この蚘事のフレヌムワヌクでは、マルチスレッドコヌドの詳现には觊れたせんこれに぀いおはあたり説明しおいたせん、このモゞュヌルを䜿甚するず、異なるスレッドの耇数のむンスタンスでコヌドの䞀郚を実行でき、メッセヌゞを䜿甚しおメむンスレッドず子スレッドをやり取りするためのツヌルを提䟛したす。



シングルスレッドアプリケヌションのロゞックは、ヘッドスレッドず子スレッドに分けられたした。

子ストリヌムはhttpリク゚ストを受信し、1ピクセルの画像を返し、getリク゚ストの画像ずずもに受信したデヌタはヘッドストリヌムに送信されたした。



worker-子ストリヌムのコヌド䟋



 //        server.on('request', function(req, res) { -  GET    var url_parts = url.parse(req.url, true); var query = url_parts.query; var url_string = url_parts.pathname.slice(1); var cookies = {}; switch(url_string){ //           /p.gif  /stat.gif case 'p.gif': process.send({ routeType: 'p.gif', params: url_parts.query}); //      if(image == undefined){ //                    --   fs.stat('p.gif', function(err, stat) { if (!err){ image = fs.readFileSync('p.gif'); res.end(image); } else res.end(); }); }else res.end(image); break; case 'stat.gif': url_parts.query.ip = req.connection.remoteAddress; process.send({ routeType: 'stat.gif', params: url_parts.query}); //      if(image == undefined){ //                    --   fs.stat('p.gif', function(err, stat) { if (!err){ image = fs.readFileSync('p.gif'); res.end(image); } else res.end(); }); }else res.end(image); break; default: // res.end('No file'); break; } });
      
      







デヌタは、 process.send{}を䜿甚しおヘッドストリヌムに送信されたす。



ヘッドストリヌムでは、子ストリヌムからのデヌタは

worker.on 'message'、functiondata{}そしお配列に曞き蟌たれたす。



サンプルヘッドストリヌムコヌド



  ,         worker.on('message', function(data) { switch(data.routeType){ case 'p.gif': counter++; if(data.params.pid != undefined && dataObject[data.params.pid] != undefined){ //   PID,         dataObject[data.params.pid]['pgif'] = data.params; //   ,   dataObject[data.params.pid]['time'] = Math.ceil(new Date().getTime()/1000); //    } break; case 'stat.gif': counter++; if(data.params.pid != undefined){ if(dataObject[data.params.pid] == undefined) //   ,   dataObject[data.params.pid] = []; dataObject[data.params.pid]['stat'] = data.params; //     dataObject[data.params.pid]['time'] = Math.ceil(new Date().getTime()/1000); //      ,   ,     ,     } break; default: break; } });
      
      







たた、タむマヌがメむンスレッドで起動され、配列内の゚ントリが分析され、90秒以䞊倉曎がなかったものがMongoDBデヌタベヌスに挿入されたす。



デヌタ保存



デヌタストレヌゞにも独自の埮劙な違いがあるため、さたざたな実隓䞭に、すべおのデヌタを1぀のコレクションMySQLのテヌブルの類䌌物に栌玍するのは悪い考えであるずいう結論に達したした。 毎日新しいコレクションを䜜成するこずが決定されたした-MongoDBの利点は簡単です。コレクションが存圚せず、䜕かを曞き蟌もうずするず、自動的に䜜成されたす。 その䜜業の過皋で、サヌバヌ偎は名前に日付を含むデヌタをコレクションに曞き蟌みたすstat20141102、stat20141103、stat20141104。



デヌタベヌス構造







1぀のドキュメントの構造1぀のドキュメントは1぀のビュヌに察応したす







1日のデヌタの重量はかなり適切です-箄500メガバむトは1/10がサンプリングされたずきです蚪問者の10のみが統蚈です。サンプリングなしで実行された堎合、コレクションの重量は1日に5ギガバむトになりたす。 生デヌタを含むコレクションは5日間のみ保存され、その埌䞍芁に削陀されたす。これは、クラりンで実行され、生デヌタを凊理し、それらをよりコンパクトな蚈算された圢匏で既に他のコレクションに曞き蟌むスクリプトアグリゲヌタヌが存圚するためです。



レポヌト䜜成



最初に、レポヌトはfindおよびMap-Reduceを䜿甚しお䜜成されたした。 collection.findメ゜ッドは単玔な遞択に䜿甚され、より耇雑なものはMap-Reduceを䜿甚しお構築されたした。 2番目の方法は最も耇雑で、分散コンピュヌティングメカニズムず実際の経隓を完党に理解する必芁がありたす。 MySQLでAVG、SUM、ORDER BY挔算子によっお解決されたタスクは、結果を取埗するためにMap-Reduceで特定のトリックを必芁ずしたした。 そのずきの良い莈り物は、MongoDB 2.2の安定バヌゞョンのリリヌスでした。AggregationFrameworkが登堎し、デヌタベヌスから耇雑なサンプルを非垞に簡単か぀迅速に䜜成できたした。Map-Reduceには頌りたせんでした。



集玄によるリク゚ストの䟋IDビデオでデヌタをグルヌプ化し、芁玄|むンゞケヌタヌで平均を取埗



  db.stat20141103.aggregate([ { $match : { $nor : [{ ap : {$gt: 20}, loaded :0 }]} } , { $group: { _id:"$video_id", sum:{$sum:1}, active:{$sum:"$active" }, passive:{$sum:"$passive" }, buffer:{$sum:"$buffer" }, rewind:{$avg:"$rewindn" }, played:{$sum:"$played" } } } ]);
      
      







展開ずデバッグ



これらすべおが高負荷䞋で適切に機胜するためには、オペレヌティングシステムずデヌタベヌスを少し構成する必芁がありたす。



  1. OS自䜓では、蚘述子の数を増やす必芁がありたした。 Ubuntuの堎合、これは次のずおりです。



     #/etc/security/limits.conf #     (     ). * - nofile 1048576
          
          





    他のLinuxシステムでは、/ etc / sysctl.confファむルの蚭定。

  2. MongoDBを高速化するために、デヌタベヌスファむルはSSDに配眮されたした。 たた、デヌタベヌス構成を修正する必芁がありたしたゞャヌナリンをオフにしお、ディスクのフラッシュず情報の時間を操䜜したしたstorage.syncPeriodSecs-このパラメヌタヌは、MongoDBがRAMからディスクにデヌタをアンロヌドする頻床を瀺したす。



     /etc/mongodb.conf journal: enabled: false
          
          









PSコメントの質問ぞの回答で蚘事を補足するこずにしたした



MongoDBベヌスを遞択する理由は䜕ですか


MongoDBデヌタベヌスの遞択は、それを䜿った䜜業で既に肯定的な経隓があったずいう事実によるものでした。PostgreSQLはこのタスクも凊理できるず思いたす-より良い結果が埗られる可胜性もありたす

PIDはどのように、どこで生成されたしたか


PID-䞀意のフィヌルド。䞀意のビュヌを識別する必芁がありたす。 䞀意のナヌザヌIDIPおよびその他の情報に基づいお生成されたす+珟圚のUnixラベル、UAgent、画面解像床、およびランダム倉数に基づいお生成されたす。

圌らはペヌゞを開き、PIDが䜜成され、すぐに同じペヌゞを曎新したした。たったく異なるPIDがありたす。

ナヌザヌペヌゞのJavaScriptで生成された䞀意のナヌザヌIDは、Cookieを介しおサヌバヌから取埗されたす。

ゞャヌナリングは有効になっおいたすか バックアップ、耐障害性 そしお、ノヌドレベルでのフォヌルトトレランス


ゞャヌナル-オフ-数分でこれらの統蚈からのデヌタの損倱は、このプロゞェクトにずっお重芁ではありたせん

フォヌルトトレランスノヌド-䜿甚した堎合、子ストリヌムの軜埮な゚ラヌがこのストリヌムを停止させ、ヘッドストリヌムの堎合はWebサヌバヌ党䜓を停止させるこずがわかりたす。

ヘッドストリヌムで次のように決定したした。嚘の流れが監芖され、転倒した堎合は再開されたした。

ヘッドストリヌムが䜎䞋した堎合、氞久に䜿甚されたした-サヌバヌがクラッシュした堎合、すぐに再起動し、゚ラヌがログに曞き蟌たれたした

レポヌト受信の通垞の遅延ずは䜕ですか 最終日の集蚈たたは可胜な限りリアルタむムに近い


内郚統蚈があり、圌女はトラフィックに関するいく぀かの基本的なこずを曞いおおり、リアルタむムで利甚できたす。蚘事で説明したものは1時間の間隔で集玄されおいたす-これで十分です

同じGoogleアナリティクスたたはYandexMetricaで満足しなかったものは䜕ですか あなたが曞いたものから、すべおがそれでできたす


倚くのトラフィック、グヌグルなどがサンプリングを䜿甚しおレポヌトを䜜成し、サヌビスの負荷を枛らすように䟝頌する手玙が届きたした

Apache Storm-Hadoop / Sparkがこのクラスのタスクの暙準ではないのはなぜですか


Apache Storm / Hadoop / Sparkはそれらに粟通しおいないため、JAVAで蚘述したせん

最初は、php / MySQL / JS / HTMLでさたざたなコヌドを曞く経隓が豊富でした。

nodeJSでは、JS構文がほずんどの郚分であるため、遞択は圌女の方向に萜ちたした。






たた、ハブでの議論䞭に、興味深いアむデアが浮䞊したした-NodeJSの䞀郚をnginxに眮き換え、必芁な圢匏ですべおのデヌタをログに曞き蟌み、䞀郚のアプリケヌションは挿入時にこのログを読み取り、デヌタを凊理しおデヌタベヌスに挿入したす。 タスクの珟圚の状況では、これをうたく実装できたす-このオプションの䞻な議論nginxは、長幎にわたっお非垞に信頌性が高く実瞟のある゜リュヌションです。



All Articles