nginxを使った簡単快速reverse proxy+cacheサーバ構築法

16th Jan, 2010 | nginx

ここのブログは、nginx(proxyサーバ)が外からのアクセスを受け、それを thin + sinatra (アプリケーションサーバ) と mongoDB (データベースサーバ)で処理する、というWebシステム定番の三層構造で構成している。

ただ、見てわかるようにほぼ静的なコンテンツのサイトなので、アクセス毎にアプリケーションサーバを走らせる意味がない。また、このVPSの一番安いコースにおいているので、あまり贅沢に資源を使いたくない。と言ったことから生成したhtmlをキャッシュして2度目のアクセスからはアプリケーションサーバやデータベースにアクセスしないようにしている。

Webシステムによっては、アプリケーションサーバで静的なhtmlファイルを作成し負荷の軽減をしたりするが、キャッシュファイルを自前で扱うのはvalidation等色々だるいので、このブログシステムではnginxに任せている。

今回はその設定の紹介

基本的にnginxは設定が簡単なので超オススメ。キャッシュの設定はたったこれだけ。全体の設定ファイルはこっちに置いとく。

http {
  proxy_cache_path /usr/local/nginx/cache levels=1:2 keys_zone=cache-space:4m max_size=50m inactive=120m;
  proxy_temp_path /usr/local/nginx/tmp; 

  server {
     location / {
      proxy_cache cache-space;
      proxy_cache_valid  200 302  60m;
      proxy_cache_valid  404 20m;
    }
  }
}

簡単に説明すると、まず、最初のproxy_cache_pathとproxy_temp_pathでキャッシュが格納されるディレクトリとサイズ等を指定する。詳しくはこの辺を見た方が早いが、この設定では、キャッシュ用に、メモリを4M使う、ディスクの最大サイズは50M、120分間アクセスがないキャッシュファイルは削除、の意味。

localtion / 内で、実際にどういうものをキャッシュするか決める。proxy_cache_valid には、httpのレスポンスコードと、そのレスポンスコードを返したときのコンテンツをどのくらいの時間キャッシュするかを書く。

この場合、正常処理である200または302を返した場合、そのコンテンツをnginxが60分間保持し、その後60分間、同じURLでアクセスがあった場合、アプリケーションサーバ(ここの場合はSinatra)に問い合わせずキャッシュをそのまま返す。

追記1:

     Twitterにて: 「なぜ404は20分にしているのか」というのがあったが、正直なところあまり深い意味はないが、設定したときは以下のことを考えていた。

  1. 404を返すだけなら、アプリケーションサーバの負荷はたいしたことなさそう。
  2. 404はエラーなので(相手側のエラーの場合と、実際にファイルがない場合)、何か直す必要がある場合にはすぐ反映されるように。

追記2: 

     Twitterにて: 「データ更新をしても最大60分間は実際の更新が行われないということか」というのがあった、そのままだとそうなる。でも自分は更新時の処理でCacheをクリアしている。ただし、NginxにはCacheを消すという正式な方法がまだ用意されていないのでアンオフィシャルな方法である「単純にcacheディレクトリの下のファイルをすべて消す」というので運用している(cacheディレクトリの下のディレクトリは消してはダメ)。今のところそれで問題は起きてない。追記: 部分的にcacheをpurgeする方法を書いた。

abを使って簡単なベンチマークを取ってみた

nginxのキャッシュなしの場合:

% ab -n 100 -c 20 http://blog.madoro.org/mn/14
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking blog.madoro.org (be patient).....done


Server Software:        nginx/0.8.31
Server Hostname:        blog.madoro.org
Server Port:            80

Document Path:          /mn/14
Document Length:        5844 bytes

Concurrency Level:      20
Time taken for tests:   9.049 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      605444 bytes
HTML transferred:       588577 bytes
Requests per second:    11.05 [#/sec] (mean)
Time per request:       1809.781 [ms] (mean)
Time per request:       90.489 [ms] (mean, across all concurrent requests)
Transfer rate:          65.34 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:      161  174   9.2    173     202
Processing:   450 1522 301.2   1456    2268
Waiting:      224 1090 286.8   1059    1893
Total:        613 1696 306.1   1620    2454

Percentage of the requests served within a certain time (ms)
  50%   1620
  66%   1789
  75%   1808
  80%   1822
  90%   1853
  95%   2439
  98%   2449
  99%   2454
 100%   2454 (longest request)

nginxのキャッシュありの場合

% ab -n 100 -c 20 http://blog.madoro.org/mn/14
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking blog.madoro.org (be patient).....done


Server Software:        nginx/0.8.31
Server Hostname:        blog.madoro.org
Server Port:            80

Document Path:          /mn/14
Document Length:        5844 bytes

Concurrency Level:      20
Time taken for tests:   3.236 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      656124 bytes
HTML transferred:       636251 bytes
Requests per second:    30.90 [#/sec] (mean)
Time per request:       647.157 [ms] (mean)
Time per request:       32.358 [ms] (mean, across all concurrent requests)
Transfer rate:          198.02 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:      162  177  10.1    174     201
Processing:   329  389  74.3    351     791
Waiting:      164  176  16.7    167     234
Total:        494  566  75.5    527     957

Percentage of the requests served within a certain time (ms)
  50%    527
  66%    599
  75%    617
  80%    628
  90%    652
  95%    667
  98%    817
  99%    957
 100%    957 (longest request)

格段にレスポンスがよくなっているのがわかる。

このような並列のアクセスだけなく、単体のアクセスのレスポンスも早くなるので、負荷が高いサイトだけでなく(ここのような)零細なサイトでも恩恵を得ることができる。最近のコンテンツは動的な部分にJavascriptを使うことが多くなっているので、このようなキャッシュがしやすくてよい。


記事の内容についての質問、苦情、間違いの指摘等なんでもtwitterでどうぞ。