動的なコンテンツを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