[Apache] mod_cacheで動的なコンテンツをキャッシュする

動的なコンテンツをPHPやPython、Rubyなどで生成しているサービスはたくさんありますが、すべてを毎回最新の情報に書き換える必要は無い場合も多いでしょう。一定時間は許容されたり、同じ情報を複数のユーザーで共有することも場合によっては可能なはずです。

そんなときにApache側で一定時間ファイルにキャッシュしてくれる機能を利用すると大変手軽に実装できます。

準備

試験用サーバの作成

今回は試験環境としてAWS Lightsailで最も安価なインスタンスを作成し、Apache2.4とPHP7.3を入れました。リージョンは東京です。

$ sudo yum update
$ sudo yum install httpd24 httpd24-devel httpd24-tools
$ sudo yum install php73 php73-cli php73-common php73-opcache
$ sudo service httpd start

Apacheの設定

ここでは最低限の設定を行っています。

<IfModule cache_module>
  <IfModule cache_disk_module>
    CacheRoot /tmp/cacheroot
    CacheEnable disk /
  </IfModule> 
</IfModule>
CacheRoot
キャッシュしたデータの保管先のパスを指定します。Apacheのユーザーからアクセスできるようパーミッションの設定をお忘れなく
CacheEnable
キャッシュするURLを指定します。前方一致で特定のファイルやディレクトリだけといった指定も可能です。

試験用スクリプト

ここでは現在時間を表示するだけのスクリプトですが、中身は何でも良いです。

<?php
header('Cache-Control: max-age=3600');
echo date('Y-m-d H:i:s');

ちなみにデフォルトの設定だと、PHPの場合Cache-Controlヘッダを出力しないとmod_cacheがキャッシュしてくれないようなのでご注意を。以下はApacheのログレベルをDebugにしCache-Controlを出力しない場合のメッセージです。

[Tue Apr 30 11:07:48.815915 2019] [cache:debug] [pid 31469] mod_cache.c(1235): [client 13.114.112.121:53380] AH00768: cache: http://13.231.154.12:80/info.php? not cached for request /info.php. Reason: No Last-Modified; Etag; Expires; Cache-Control:max-age or Cache-Control:s-maxage headers

試験結果

キャッシュなし

同時接続10、合計1000リクエストをApache Benchで投げてみました。

$ ab -n 1000 -c 10 http://example.com/info.php

Concurrency Level:      10
Time taken for tests:   0.291 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      250000 bytes
HTML transferred:       19000 bytes
Requests per second:    3434.87 [#/sec] (mean)
Time per request:       2.911 [ms] (mean)
Time per request:       0.291 [ms] (mean, across all concurrent requests)
Transfer rate:          838.59 [Kbytes/sec] received

キャッシュあり

1秒間にどれだけリクエストできるかを表すRequests per secondを見ると、17%程度パフォーマンスが向上しているのがわかりますね。

$ ab -n 1000 -c 10 http://example.com/info.php

Concurrency Level:      10
Time taken for tests:   0.248 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      258000 bytes
HTML transferred:       19000 bytes
Requests per second:    4028.59 [#/sec] (mean)
Time per request:       2.482 [ms] (mean)
Time per request:       0.248 [ms] (mean, across all concurrent requests)
Transfer rate:          1015.02 [Kbytes/sec] received

備考

RAMディスクを利用

メモリ上にRAMディスクを作成し、キャッシュ置き場とすることで高速化が期待できます。 blog.katsubemakito.net

その他の設定項目

詳細はドキュメントを参照ください。

# キャッシュ"しない"パス
CacheDisable /nocache

# キャッシュに保管する最大ファイルサイズ(byte)
CacheMaxFileSize  1000000

# キャッシュに保管する最小ファイルサイズ(byte)
CacheMinFileSize  1

# キャッシュに保管"しない" HTTPヘッダーを指定
CacheIgnoreHeaders Set-Cookie

# 最終更新日が存在しないファイルもキャッシュする (デフォだとされない)
CacheIgnoreNoLastMod On

# クエリー文字列を無視してキャッシュする
# (例えば /foo, /foo?a=1, /foo?b=2 などこれらはすべて同じキャッシュが利用される)
CacheIgnoreQueryString On

# 特定のクエリー文字列を無視してキャッシュする
CacheIgnoreURLSessionIdentifiers foo

# デフォルトのキャッシュ時間(秒数)
CacheDefaultExpire 3600

# キャッシュ時間の最大|最小値(秒)
CacheMaxExpire 86400
CacheMinExpire 0

mod_mem_cache

Apache2.2まではメモリ上にキャッシュできるmod_mem_cacheがあったのですが、2.4で廃止されてしまいました。

These modules have been removed: mod_authn_default, mod_authz_default, mod_mem_cache. If you were using mod_mem_cache in 2.2, look at mod_cache_disk in 2.4.

http://httpd.apache.org/docs/2.4/upgrading.html

参考ページ