nginxでプロキシ&キャッシュサーバー

(多分)一般的なWebサーバーであるApacheは複雑な設定も可能で便利なのですが、その分重いのです。

どう重いのかというと、Apacheは一つのプロセスが一つのHTTPリクエストを同期処理で裁いてるのでその間は他の処理をしません。なので、同時アクセス数が増えるとApacheはプロセスをどんどん生成します。(あるいは後からきたリクエストを待たせる)

なので、アクセス数が増えると急激にパフォーマンスが落ちるという問題を抱えてます。(ほかにもプロセスIDが足りなくなってどんなにリソースがあっても最大プロセスIDで制限されてしまう)

で、最近話題のハイパフォーマンスWebサーバーがnginx(えんじんえっくす)です。

nginxは一つのプロセスで複数のリクエストを非同期で同時に処理します。なので、アクセス数が増えてもパフォーマンスが落ちにくいという特性があります。特に静的ファイルの場合は処理のほとんどがI/O待ちなので効果が大きいです。

そこで、PHPとかSVNとか設定がめんどくさいものはApacheに任せておいて、静的なファイルだけをnginxに処理させてみると、Apacheへのリクエスト数は激減するはずです。

例えば、このブログのトップページの場合PHPで生成されるHTMLが一個にたいして、CSSや画像等の静的ファイルが20個近くあります。単純計算で21個のリクエストのうち1個だけがApacheで処理されるのでApacheへのリクエストは約95%削減されます。

では設定してみましょう。OSはUbuntu Server 10.04(64bit)です。Apacheは既にインストール済みで運用されているとします。設定後はnginxがポート80で待ち受けて、Apacheはポート8080で待ち受けるということにします。

(記事の最後でキャッシュファイルをRAMに置くというのもやってみます)

nginxのインストール

そのままaptitudeでインストールすると0.7.65がインストールされてしまうので、nginxのPPAを追加してからインストールします。

$ sudo add-apt-repository ppa:nginx/stable
$ sudo apt-get update
$ sudo install nginx

設定ファイルは /etc/nginx/ にあります。sites-enableとかApacheに似た構造になっています。

リバースプロキシの設定

ではこの sites-enabled/default をこのように設定しましょう。

upstream backend {
server 127.0.0.1:8080;
}

server {
listen 80;
server_name _;
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;
proxy_pass http://backend;

}
}

これはリバースプロキシに必要な設定だけです。すべてのアクセスをローカルのApacheに引き渡してます。

Apacheの方はports.confでリッスンポートを80から8080に変更し、各サイトの設定も80から8080に変更してください。そして、Apacheとnginxを再起動させます。(Apacheを先に8080にしてからnginxを起動させる)

$ sudo /etc/init.d/apache restart
$ sudo /etc/init.d/nginx restart

これでブラウザからアクセスすると、nginxを経由してApacheが処理します。ので、今までとかわらないはずです。

ところが、問題があって、Apacheのアクセスログを見るとアクセス元が127.0.0.1になっちゃってるはずです。これを解消するためにmod_rpafをインストールします。

$ sudo apt-get install libapache2-mod-rpaf

これでApacheを再起動すると正しくアクセス元が扱われているはずです。実はこのためにnginxの設定に X-Real-IP をHTTPヘッダに追加する設定やらを書いているのです。mod_rpafはプロキシサーバーが追加した X-Real-IP ヘッダをアクセス元として扱うモジュールです。

mod_rpafは127.0.0.1からのアクセスだけに対して処理をするのでもし、リバースプロキシが他のホストにあるのであれば /etc/apache2/mods-enabled/rpaf.conf の RPAFproxy_ips をリバースプロキシサーバーのIPアドレスに変更してください。(すべてのX-Real-IPを信用するとアクセス元の偽装ができてしまうためです)

プロキシキャッシュ

では、元々の目標であった静的ファイルをnginxでホストする設定をしましょう。本来はnginxが静的ファイルを直接ディスクから取ってくるのがいいのですが、nginxがApacheと違うホストにある場合も考えられますのでその場合でも対応できるように、静的ファイルへのアクセスをキャッシュしておき、2回目以降の同じファイルへのアクセスはApacheに引き渡さないように設定してみます。

defaultをこのように編集してみます。

proxy_cache_path /var/cache/nginx/static_file_cache levels=1:2 keys_zone=cache_static_file:128m inactive=7d max_size=512m;
proxy_temp_path /var/cache/nginx/temp;

upstream backend {
server 127.0.0.1:8080;
}

server {
listen 80;
server_name _;
location / {
proxy_redirect off;

set $do_not_cache 0;
if ($request_method != GET) {
set $do_not_cache 1;
}
if ($uri !~* ".(jpg|png|gif|jpeg|css|js|swf|pdf|html|htm)$") {
set $do_not_cache 1;
}
proxy_no_cache $do_not_cache;
proxy_cache_bypass $do_not_cache;
proxy_cache cache_static_file;
proxy_cache_key $scheme$host$uri$is_args$args;
proxy_cache_valid 200 2h;
proxy_cache_valid any 1m;

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;
proxy_pass http://backend;
}
}

この設定ではメモリ128M,ファイル最大512Mで、7日間キャッシュするファイルを /var/cache/nginx/static_file_cache に作成してます。

そして、do_not_cache 変数を用意して、0にしておき、GETでのアクセスでない場合と、静的ファイルでは無い場合にキャッシュしないようにその場合は do_not_cache を1にして、proxy_no_cacheを有効にしてます。静的ファイルの判断は正規表現でURLの拡張子を見ています。(注意しなければいけないのが、WordPressのページをパーマネントリンクで.htmlにしている場合です。その場合はキャッシュされないように外しておく必要があります。)

つまり、静的ファイルにGETでアクセスしたものだけキャッシュされます。

proxy_cache_valid はどのステータスのレスポンスをどの期間キャッシュするかを設定する項目で、この場合200なら2
時間、それ以外なら1分キャッシュすることになります。

あとは /var/cache/nginx/ ディレクトリを作成し nginx を再起動するだけです。

$ sudo mkdir /var/cache/nginx
$ sudo /etc/init.d/nginx restart

それでしばらくブラウザからアクセスしてみると、キャッシュディレクトリの容量が増えているはずです。

$ sudo du -ch /var/cache/nginx/static_file_cache
(中略)
91M /var/cache/nginx/static_file_cache
91M 合計

本当にApacheへのアクセスが減っているのかは、Apacheのアクセスログをみてみてください。

さらに一歩

もう一歩高速化してみましょう。いまキャッシュファイルは/var/cache/nginxに置かれているので、結局キャッシュからの呼び出しのためにHDDアクセスすることになります。こいつを全部メモリ上においてしまいましょう。

間違えたり、問題が発生するとシステムに問題が起きるかもしれないのでわからないor不安ならやらないほうがいいです。

tmpfsを使えば、メモリ上の領域をファイルシステムにマウントすることができます。

/etc/fstab に次の一行を追加してOSを再起動します。

tmpfs /var/cache/nginx tmpfs defaults,noatime,mode=1777 0 0

そうすると、/var/cache/nginx ディレクトリはRAM上に配置されます。

が、うちのサーバーはSSDにしてあったので効果はわかりませんでした。が、SSDの寿命を延ばす効果はあると思います。

6 Comments

  1. ななし より:

    ソース引用部で余分なspanが露出してしまっているように見えます。

    • chibiegg より:

      WordPressの移行作業のボロがいろんなところにでてますね。
      ありがとうございます。

  2. andy より:

    韓国語に翻訳してもいいですか?

    • chibiegg より:

      遅くなってすいません.
      全然かまいませんよ.

      こちらへのリンクも張って頂いてるので.

コメントを残す

メールアドレスが公開されることはありません。

question razz sad evil exclaim smile redface biggrin surprised eek confused cool lol mad twisted rolleyes wink idea arrow neutral cry mrgreen

*