オリジナル
- vBulletin 3.8.xの下のフォーラム
- forum.domain.comサブドメインに送信されました
- Nginx 1.1.13、PHP 5.3.x(fpm)
- フォーラムに加えて、このサーバーでは何も回転していません。 ( これは重要です )。
- 別のサーバー上のMySQL、TCP / IPを介した通信。
背景
フォーラムに参加し、気にしませんでしたが、 xmのトップロードは30〜40%程度でした。 そして、「X」の時が来て、負荷が90%の平らな棚に跳ね上がり、ピークがより高くなりましたが、実際にはうなりません。 DDOSの疑いは確認されていません。 ログによると、通常のワークロードが観察されました。 馬鹿げたリソースを増やす前に、何が起こっているのかを理解し、可能なすべてをキャッシュしようとする考えが生まれました。
調査。 パート1- 女性の訪問者が望むもの
私はこのソフトウェアのイデオロギーと機能に慣れていなかったため、訪問者とサーバー間のログとトラフィックの分析で問題を調査し始めました。 まず、フォーラムのメッセージへの添付ファイルは、 attachment.phpスクリプトによってのみ提供され、ファイル自体はデータベースに保存でき、ローカルディスク上にあることができますが、返されるのはスクリプトのみです。 そして他の方法はありません。 つまり、8〜10枚の写真を含むメッセージブランチごとに、8〜10の追加のphpインタープリターの痙攣が発生します。 そして、これはすべての訪問者のためです。 このフォーラムで添付ファイルを表示するために登録は必要ないため、添付ファイルは、たとえば数日間キャッシュできます。 このようなもの:
location = /attachment.php { expires max; limit_req zone=lim_req_1s_zone burst=5; fastcgi_pass forum__php_cluster; include /etc/nginx/fastcgi_params; include /etc/nginx/fastcgi_params_php-fpm; fastcgi_cache forum_att__cache; fastcgi_ignore_headers Cache-Control Expires Set-Cookie; fastcgi_hide_header Set-Cookie; fastcgi_hide_header Pragma; fastcgi_cache_key "$request_method:$http_if_modified_since:$http_if_none_match:$host:$request_uri:"; fastcgi_cache_use_stale updating error timeout invalid_header http_500; fastcgi_cache_lock on; fastcgi_cache_lock_timeout 2m; fastcgi_cache_valid 2d; } - http- forum_att__cache: fastcgi_cache_path /var/cache/nginx/att levels=1:2 keys_zone=forum_att__cache:4m max_size=2g inactive=2d;
2番目の「啓示」は、フォーラムにアーカイブがあり、アーカイブが存在するだけでなく、リクエストのほぼ半数がアーカイブによって作成されていることです。 ページの外観により、コンテンツをキャッシュすることもできます。
location /archive/ { expires 10d; limit_req zone=lim_req_1s_zone burst=2; location ~ \.css$ { expires max; } fastcgi_pass forum__php_cluster; fastcgi_index index.php; include /etc/nginx/fastcgi_params; include /etc/nginx/fastcgi_params_php-fpm; fastcgi_param SCRIPT_FILENAME $document_root/archive/index.php; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_cache forum_arc__cache; fastcgi_hide_header Set-Cookie; fastcgi_ignore_headers Cache-Control Expires Set-Cookie; fastcgi_cache_key "$request_method:$http_if_modified_since:$http_if_none_match:$host:$request_uri:"; fastcgi_cache_use_stale updating error timeout invalid_header http_500; fastcgi_cache_valid 2d; } http-: fastcgi_cache_path /var/cache/nginx/arc levels=1:2 keys_zone=forum_arc__cache:4m max_size=2g inactive=2d; DDOS-: limit_req_zone "$psUID" zone=lim_req_1s_zone:2m rate=1r/s;
キー「$ psUID」の形成についてさらに説明します。
調査。 パート2-vBulletinでの承認
フォーラム訪問者の観点からは、入力したユーザーは登録ユーザーまたはゲストのいずれかです。 しかし、ブラウザでのCookieの出現と消滅の観点から「来た、歩いた、ログインした、歩いた、ログインした、歩いた」という状況を観察すると、まったく異なる状況が発生します。 そのため、ドメインとそのサブドメインのCookieをクリアし、 HTTPfoxを開いて、何が起こるかを観察します。
HTTP/1.1 200 OK Set-Cookie: PHPSESSID=cdme9rrptft67tbo97p4t1cua5; expires=Wed, 22-Feb-2012 15:04:12 GMT; path=/; domain=.domain.com Set-Cookie: bblastvisit=1329059052; expires=Mon, 11-Feb-2013 15:04:12 GMT; path=/; domain=.domain.com Set-Cookie: bblastactivity=0; expires=Mon, 11-Feb-2013 15:04:12 GMT; path=/; domain=.domain.com Set-Cookie: uid=XCuiGU831OyC8VLqAx/QAg==; expires=Thu, 31-Dec-37 23:55:55 GMT; domain=.domain.com; path=/
uidとPHPSESSIDを使用すると、すべてが明確になります-これらはnginxの陰謀であり、 session.auto_startオプションがインストールされたphpインタープリターですが、残りはフォーラムのアクティビティフォロワーです。 ただし、メインセッションCookie vBulletinはまだ確認されていません。 今後は、vBulletinは標準のphp-session(より正確にはALMOSTは使用しません)を使用せず、独自のIDをbbsessionhash cookieに保存すると言います。 したがって、ユーザーはログインしましたが、セッションはありません。つまり、ユーザーはセッションのない匿名の人物です。 さらに、フォーラムへのリンクは2つの形式をとることができます(ページ上のすべてのリンクを意味し、1つだけでなく他のリンクも意味します)。
forum.domain.com/forumdisplay.php?s=12b66e447be52ebc84ab16d3f39626fb&f=69
forum.domain.com/forumdisplay.php?f=69
最初のタイプのリンクをたどると、フォーラムからの次の回答はセッションのCookieになりますが、2番目のリンクはそうではありません。 Cookieが2番目の回答でセッションから取得されなかった場合、最初のタイプのリンクに出会うまで(セッションの外観のパターンを特定できませんでした)、またはログインするまで、フォーラムをセッションレスで落ち着きません。 ログインに成功すると、セッションCookieはとにかく入ります。 ログインする前にゲストが匿名セッションだった場合、セッションは置き換えられます。 次のようになります。
HTTP/1.1 200 OK Set-Cookie: bbsessionhash=85745bc6110db5221e159087bf037f24; path=/; domain=.domain.com; HttpOnly
ログイン後、セッションは「安定」し、リンクを使用したリープフロッグは発生しません。 ログアウト手順の独創性に違いはありません-既存のフォーラムCookie(設定されていないものも含む)はすべて削除され、新しい(「匿名」)セッションのCookieが書き込まれます。
HTTP/1.1 200 OK Set-Cookie: bbsessionhash=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bblastvisit=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bblastactivity=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbthread_lastview=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbreferrerid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbuserid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbpassword=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbthreadedmode=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbstyleid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bblanguageid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.domain.com Set-Cookie: bbsessionhash=3d0bdc5dbe8dabae361deebe8f6048d2; path=/; domain=.domain.com; HttpOnly
つまり、出力では匿名(ゲスト)を取得しますが、セッションを持つのは100%です。
その結果、フォーラムソフトウェアと HTTPヘッダーの観点から、3つのタイプのユーザーがいます。 セッションのないゲスト、セッションのあるゲスト 、 ログインしたビジターです。 さらに、nginxレベルでは、2番目と3番目を区別することは非常に問題です。
これで、Cookieが何であり、訪問者とサーバー間でどのように実行されるかを理解したので、動的コンテンツのキャッシュの問題に取り組むことができます。 ご存知のように、nginxのfastcgiバックエンド応答のキャッシュ機能はngx_http_fastcgi_moduleモジュールに組み込まれています。 これを行うには、httpセクションでキャッシュゾーンをグローバルに設定し、目的の場所にキーを設定する必要があります。 また、条件付きで静的なコンテンツ(画像、アーカイブ)のキャッシングのキーとしてマイナーな追加のURIを考慮することができる場合、ユーザーのキャッシングダイナミクスの場合、ダイナミクスも考慮する必要があります それは次のようなルールのように思えます
fastcgi_cache_key "$request_method:$http_if_modified_since:$http_if_none_match:$host:$request_uri:$cookie_bbsessionhash:";
ゲストとログインユーザーの両方を満足させることができましたが、実際には、訪問者は他の誰かのキャッシュのコンテンツを受け取り始めました。 「真の」ダイナミクスのキャッシングを無効にする必要がありました。 この文章が最終的なものではないことを願っています。
ただし、この情報は無意味ではありません。 それに基づいて、訪問者のIPアドレスだけでなく、訪問者のステータスにも基づいて、リクエストの頻度を制限するキーを生成できます。
set $psUID "anon"; set $psUCL "anon"; if ($cookie_bbsessionhash) { set $psUID "$cookie_bbsessionhash"; set $psUCL "user"; } if ($psUCL = "anon") { set $psUID "anon:$remote_addr"; }
この構成のフラグメントは、すべての場所の説明の前に、nginx構成のサーバーセクションに配置します。 その結果、セッションを持つユーザーの元のキーと、セッションクローラーを持たないセッション訪問者のIPアドレスに基づくキーが取得されます。
結果
実施した取り組みの結果、仮想マシンの合計負荷は、シェルフから90パーセント減少し、40バーストで80パーセントになりました。