a-blog cmsをリバースプロキシ(nginx)で高速化


この記事はa-blog cms Advent Calendar 2013に参加した記事になります。最終日の担当です。

リバースプロキシとは

リバースプロキシ(英: Reverse proxy)または逆プロキシは、特定のサーバへの要求を必ず経由するように設置されたプロキシサーバ。一般的なプロキシとは異なり不特定多数のサーバを対象としない。リバースプロキシは、不特定多数のクライアントから寄せられる要求に対して、応答を肩代わりすることにより特定のサーバの負担を軽減したり、アクセスを制限することにより特定のサーバのセキュリティを高めたりする目的に用いられる。

引用元 wikipedia wikipedia

リバースプロキシの役割はいろいろあるのですが、公開の目的はWEBサーバ(Apache)の前にリバースプロキシを置きリバースプロキシにキャッシュさせa-blog cmsを高速に動かそう!という目的になります。

一連の流れ

イメージがつきにくので簡単な図にしてみました。



上の図でnginxサーバがリバースプロキシになりキャッシュをしてくれます。同じリクエストがきた場合は、a-blog cmsが動いているWEBサーバ(apache)にアクセスする事なくnginxがリクエストを返します。

キャッシュが無かった場合は、WEBサーバ(apache)にアクセスしてリクエストを返します。その際nginxはそのリクエストをキャッシュするので次回からはキャッシュを利用するようになります。

これによりa-blog cmsが動いているWEBサーバの負荷が下がり、さらにnginxがキャッシュをする事により高速にうごくようになります。

nginxとは

Nginxは無料で利用できるオープンソースのハイパフォーマンスHTTPサーバ且つリバースプロキシで、IMAP/POP3のプロキシサーバとしても動作します。Igor Sysoevによって2002年に開発が始まり、2004年に最初のバージョンが公開されました。今では世界中のドメインのおよそ12.18% (22.2M)のWebサイトをNginxが稼働させています。 Nginxはその高いパフォーマンスと安定性、豊富な機能、設定の容易さ、消費リソースの低さで知られています。

引用元 NginxJa

Apacheに比べて安定的に高速に動作するようです。 WEBサーバである事と安定して高速に動作する事を押さえていればOKです。

動かしてみる

ここでは、a-blog cmsでnginxを使う注意点やキャッシュ処理に重点を置いて、 nginxのインストール方法などは省きたいと思います。 探してみるといろいろと記事があります。リストは自分が参考にしたサイトになります。

a-blog cmsでのnginx設定

a-blog cmsでnginxをリバースプロキシとして使う場合いくつか注意点があります。普通にキャッシュサーバとして nginxを設定すると全てをキャッシュしてしまうからです。 次にnginxでの設定の一例を上げたいと思います。(一部の設定のみになります。)

// キャッシュファイルを指定
proxy_cache_path /var/cache/nginx/static_file_cache levels=1:2 keys_zone=cache_static_file:128m inactive=7d max_size=480m;
proxy_temp_path /var/cache/nginx/temp;

// apacheサーバを指定
upstream backend {
    // ここではapacheを8080で動作
    server 127.0.0.1:8080; 
}
server {
    listen       80; // nginxを80番ポートで起動
    server_name  atsu666.com;

    location / {
        // リバースプロキシの設定
        proxy_redirect off;
	proxy_set_header Host $host;
	proxy_set_header X-Real-IP $remote_addr;
	proxy_set_header X-Forwarded-Host $host;
	proxy_set_header X-Forwarded-Server $host;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

	set $mobile 0; // モバイルの変数を用意
        // UserAgentをみてモバイルからのアクセスか判定
	if ( $http_user_agent ~* (Android|iPhone) ) {
	    set $mobile 1; // モバイルかの場合、変数に"1"をセット
	}
        // GETリクエスト以外はキャッシュをしない
	if ( $request_method != GET ) {
	    proxy_pass http://backend; // すぐにapacheに転送
	    break;
	}
        // Cookieにsidがある場合、a-blog cmsにログインしているとみなしキャッシュしない
	if ( $http_cookie ~* sid ) {
	    proxy_pass http://backend; // すぐにapacheに転送
	    break;
	}
        // キャッシュの設定
	proxy_cache cache_static_file;
        // キャッシュキー、モバイルは別キャッシュに
	proxy_cache_key $scheme$host$uri$args$mobile;
	proxy_cache_valid 200 2h;
	proxy_cache_valid any 1m;

	proxy_pass http://backend;
    }
}

重要な所はコメントを残しました。 a-blog cmsで重要な設定を列挙していきます。

GETリクエスト以外はキャッシュしない

すごく重要な設定になります。POSTリクエストなどをキャッシュしてしまうと、 フォームの内容やキーワード検索のPOSTリクエストの結果をキャッシュしてしまい、大変な事になります。

スマフォのアクセスはキャッシュを分ける

a-blog cmsのUserAgentのルールを使っている場合に必要になってきます。 proxy_cache_keyにスマフォの判定をいれる事によりPCとスマートフォンで別のキャッシュが作られます。 これをしないと、キャッシュが作られた時のUserAgentで両方ともキャッシュを返してしまいます。(PCでアクセスしているのにスマフォの表示がされるなど。)

ログインしてる時はキャッシュをしない

基本的にログインする時はポートを指定して(例:https://atsu666.com:8080/)操作するのですが、 nginxを通してみてしまった場合の事を考えて設定しておきます。もしログインしている状態がキャッシュされてしまう場合、管理パーツなどが一般の人に見えてしまう事になってしまいます。

a-blog cmsでnginxをリバースプロキシで使う場合の注意点をあげてみました。 ここでの設定はあくまで一例ですので、環境や設定にあわせて自分でカスタマイズして下さい。

Nginxのキャッシュをどうにかする

nginxの設定が終わった事で目的は達成する事はできました。しかしキャッシュサーバを利用する事で キャッシュクリアで注意しなければなりません。nginxのキャッシュは強力です。設定にもよりますが、 いつまでたってもキャッシュがクリアされないという事があります。

そこで、新しい記事をかいた時やhtmlを触った時など好きなタイミングでキャッシュを消す事をa-blog cmsで実装したいと思います。

キャッシュ削除スクリプトを用意

nginxのキャッシュを削除するスクリプトを用意します。今回は乱暴ですが、 キャッシュをすべて消すスクリプトにしています。 /usr/bin/ あたりに、適当にnginx_clear.shと名前をつけてファイルを作成します。


#! /bin/sh
sudo rm -rf /var/cache/nginx/static_file_cache/*

ここでは、乱暴にキャッシュファイルを消すコマンドを書いているだけです。 ただし、このスクリプトをapcheが操作できないといけないので一工夫します。

apacheユーザでsudoコマンドを叩く
# visudo 
apache ALL=(ALL) NOPASSWD: /bin/sh /usr/bin/nginx_clear.sh

これによりapacheが先ほど用意したスクリプトを実行できるようになりました。

a-blog cmsからスクリプトを実行

apacheからスクリプトを叩けるようになりましたので、こんどはa-blog cmsと連携します。 a-blog cms v2.0よりキャッシュをクリアするHookが用意されましたので、Hookを利用します。 まず、Hookを使う為にconfig.server.phpでHOOK_ENABLEを設定します。

define('HOOK_ENABLE', 1);

次に/ACMS/User/Hook.phpに以下を記述します。

   
     /**
     * キャッシュのリフレッシュ時
     *
     */
    public function cacheRefresh()
    {
        exec("sudo /bin/sh /usr/bin/nginx_clear.sh");
    }

    /**
     * キャッシュのクリア時
     *
     */
    public function cacheClear()
    {
        exec("sudo /bin/sh /usr/bin/nginx_clear.sh");
    }

    /**
     * キャッシュの削除時
     *
     */
    public function cacheDelete()
    {
        exec("sudo /bin/sh /usr/bin/nginx_clear.sh");
    }

これで、a-blog cmsがキャッシュをクリアするタイミング(記事を更新、コンフィグを変更、ダッシュボードよりキャッシュをクリアなど)でnginxのキャッシュも同時にクリアしてくれるようになりました。

ベンチマーク

せっかくnginxを導入したのでベンチマークをしてみました。利用したベンチマークソフトは Apache Benchで同時接続数: 5、総リクエスト数:500で試してみました。

// apacheのみ a-blog cmsキャッシュなし
Concurrency Level:      5
Time taken for tests:   77.999 seconds
Complete requests:      500
Failed requests:        0
Write errors:           0
Total transferred:      4223000 bytes
HTML transferred:       4145000 bytes
Requests per second:    6.41 [#/sec] (mean)
Time per request:       779.990 [ms] (mean)
Time per request:       155.998 [ms] (mean, across all concurrent requests)
Transfer rate:          52.87 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       31   61  53.9     48     555
Processing:   414  714  93.7    710    1149
Waiting:      396  705  95.5    702    1145
Total:        460  775 111.7    763    1315

// apacheのみ a-blog cmsキャッシュあり
Concurrency Level:      5
Time taken for tests:   37.678 seconds
Complete requests:      500
Failed requests:        0
Write errors:           0
Total transferred:      3695000 bytes
HTML transferred:       3561000 bytes
Requests per second:    13.27 [#/sec] (mean)
Time per request:       376.776 [ms] (mean)
Time per request:       75.355 [ms] (mean, across all concurrent requests)
Transfer rate:          95.77 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       54  347 488.9    219    5663
Processing:     0   27  25.3     21     148
Waiting:        0   19  23.5     12     148
Total:        134  374 484.7    246    5663

// nginx (プロキシサーバとして使用)
Concurrency Level:      5
Time taken for tests:   19.248 seconds
Complete requests:      500
Failed requests:        0
Write errors:           0
Total transferred:      3670000 bytes
HTML transferred:       3533500 bytes
Requests per second:    25.98 [#/sec] (mean)
Time per request:       192.478 [ms] (mean)
Time per request:       38.496 [ms] (mean, across all concurrent requests)
Transfer rate:          186.20 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       39  100 111.7     87    1231
Processing:    37   92  43.5     86     510
Waiting:       35   77  35.2     72     406
Total:         76  192 119.6    174    1350

全ての処理を完了するまでに、a-blog cmsのキャッシュを利用しないapacheでは77秒かかり、キャッシュを利用するapacheでは、37秒、nginxをキャッシュサーバとして利用した場合、19秒という結果でした。

うーん。もっと早くなりそうな気がしますが、今回は力尽きたのでここまでにします。。

という感じで今回はa-blog cmsでnginxをプロキシサーバとして利用する注意点などを書きました。 是非お試しを!

最後に

最後になりますが、皆様のご協力のおかげで、なんとかa-blog cms2.0をリリースする事が出来ました。本当にありがとうございました。

2.0ではいろいろなと機能追加や改善がされています。皆様のお役にたてればうれしいです。 また、まだまだ新機能、改良などいろいろとやる事はあります。ご要望なども、どしどし受付中です。 より一層使いやすいCMSになるよう頑張りますので、これからもよろしくお願い致します。

では長くなりましたがこのぐらいにしておきます。

メリークリスマス!よいお年を!


関連記事

a-blog cms + Varnish 触ってみる

a-blog cms テンプレート解体新書

Document Outliner

アウトライン生成ライブラリ、document-outliner をリリースしました

a-blog cmsでSVGを画像プレイスホルダーとして使う

【a-blog cms】アップロードしたPDFのサムネイルを作成する

a-blog cmsで画像のロスレス圧縮をする

最新記事

カテゴリー

ハッシュタグ