Drupalはバージョンが上がるたびに高機能になり、重くなってきています。静的サイトとは比較にならないくらい負荷がかかります。
Drupal内部における対策としては、データベースアクセスを中心にスロークエリ解消やボトルネック対策を行うことになります。
しかし、Drupal内部だけで対策しても限界があります。
ここでは、Drupal周辺の負荷対策を紹介します。
WebサーバーをApacheからNginxに変更する
高速・軽量なWebサーバーとして定評のあるNginxに切り替えることでパフォーマンスを向上させます。
DrupalはNginxで動く?で「Nginx1.4+Fastcgi+Apc+Mysql5.6+Drupal7.23」で実験した内容を紹介しています。
特殊な拡張モジュールを使っていない限りでは問題なく動作するようです。
Nginxをリバースプロキシサーバーとして利用する
「Nginx(リバースプロキシ)+Apache(Webサーバー)」という構成で静的キャッシュを行います。
要求メモリが少ないため、Webサーバー内に追加することで実験できる。Webサーバー以下の変更がポート番号くらいなのでリリース間際のチューニングに最適。など、導入障壁画が低いです。
Nginxだけでフロントキャッシュ&Webサーバーにする方法もありますが、WebサーバーをNginxにするためには上記のようにFastcgiを導入する必要があります。また、Nginxは.htaccessを理解しませんので、.htaccessで定義している内容をNginxの設定に置き換える必要があります。
また、Apacheで利用しているExtension(mod_xxxx)も置き換える必要があります。
以下はNginxを簡単にリバースプロキシとして利用する際のconfファイルの例です。
Nginx標準では部分キャシュクリア機能を持たないため、下記「location ~ /purge(/.*)」を機能させるためにはngx_cache_purgeモジュールをincludeしたNginxをmakeする必要があります。
http { server_tokens off; # キャッシュ 〜 proxy_cache_path /var/cache/nginx/cache levels=1 keys_zone=zone1:4m inactive=1d max_size=50m; proxy_temp_path /var/cache/nginx/temp; proxy_ignore_headers X-Accel-Redirect X-Accel-Expires Cache-Control Expires Set-Cookie; 〜 include mime.types; default_type application/octet-stream; access_log /var/log/nginx/access.log; sendfile on; keepalive_timeout 65; # バーチャルドメイン server { listen 80; server_name my-public-nginx-server; index index.php; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_max_temp_file_size 0; location / { set $do_not_cache 0; if ($request_method = "POST") { set $do_not_cache 1; } if ($request_uri ~ ^/system/) { set $do_not_cache 1; } if ($request_uri ~ ^/node/add/) { set $do_not_cache 1; } if ($request_uri ~ ^/node/[0-9]+/edit) { set $do_not_cache 1; } if ($request_uri ~ ^/node/[0-9]+/delete) { set $do_not_cache 1; } if ($request_uri ~ ^/node/[0-9]+/delete) { set $do_not_cache 1; } if ($request_uri ~ ^/user) { set $do_not_cache 1; } if ($request_uri ~ ^/admin) { set $do_not_cache 1; } if ($request_uri ~ ^/contact) { set $do_not_cache 1; } if ($request_uri ~ ^/inquiry) { set $do_not_cache 1; } 〜 proxy_no_cache $do_not_cache; proxy_cache_bypass $do_not_cache; set $dbg_v "get $host$uri"; access_log /var/log/nginx/debug.log debug_log_fmt; proxy_pass http://my-local-apache-server:8080; proxy_cache zone1; proxy_cache_key $host$request_uri; proxy_cache_valid 200 302 10m; proxy_cache_valid 404 5m; } location ~ /purge(/.*) { set $dbg_v "prg $host$1"; access_log /var/log/nginx/debug.log debug_log_fmt; proxy_cache_purge zone1 $host$1; } } }
Drupalのコンテンツ更新に応じたページ単位のPurgeを行う
上記例は、Nginx単独のキャッシュとして機能し、設定値に応じた固定のキャッシュ期間で動作します。
能動的にキャシュをクリアするには(上記設定では)「http://ドメイン名/purge/キャシュクリアしたいURI」のような形でHTTPアクセスするしかありません。
それでは不便、ということで、Drupal内から、コンテンツの更新/削除などをきっかけにPurgeをキックする仕組みも用意されています。
Purgeモジュール
https://www.drupal.org/project/purge
expireをHookし、変更されたコンテンツに関連するページをPurgeするためのHttpコールを行います。
Cache Expirationモジュール
https://www.drupal.org/project/expire
PurgeモジュールのためのExpire Hookを生成します。