2016 Drupal Advent calendar 22日目の記事です。
ホワイトハウスやNASAのWEBサイトでも利用されているセキュリティ性が高いCMS Drupal。今回はDrupalを高速化する一般的な方法と、CDNを利用した場合の設定ポイントについて解説したいとおもいます。

CMSで共通の欠点

cms cdnまず始めに「CMSは遅い」と言われる理由の一つとして、ページの読み出し方による問題があります。
CMSは、ページやプラグインにアクセスする度に、DBへのアクセスが発生してしまいます。一般的にDBへのアクセスはIOや内部構造によりレスポンスが遅いケースがあり、HTTPサーバーであるApacheやNginxなどのチューニングを行うよりも、まずはDBチューニングを行った方が効果があるといわれるのはこのためです。

Drupalも同様に管理画面で保存したコンテンツはDBに保存されるため、サイトにアクセスされる度にDBからコンテンツを抽出しブラウザに返却します。また、Drupal以外にもCMSは様々存在しますが、どのCMSもDBからコンテンツを読み出すという動作の他に、ボトルネックになりやすいウイークポイントが存在するケースもあります。

標準機能でお手軽高速化

Drupalは標準で既に高速化できる機能が備わっており、まずはこちらのご紹介からしたいとおもいます。こちらを利用すれば無料である一定のパフォーマンスを得ることができます。

CSSやJSの圧縮

DrupalはJSやCSSをなるべくまとめて1つのファイルにしてから配信するという機能が備わっています。

管理画面から 開発 → パフォーマンスと進むと、下の方に帯域幅最適化という項目が存在します。こちらのチェックを入れることにより、複数のJSやCSSを1つのファイルにまとめ1ページあたりのリクエスト数が減少し読み込み待ちが削減出来ます。

cdn-drupal1

本機能を有効にした場合のパフォーマンスを比較すると以下の通りロード時間が短縮されました。

帯域幅最適化 無効

Requests 36
Transerred 387 kB
Load 703ms

帯域幅最適化 有効

Requests 13
Transerred 191 kB 
Load 505ms

 

このように本機能を有効にするだけで、ページ読み出し時のリクエスト数や転送される容量を圧縮することができます。

しかし、テーマやモジュール内のCSSでimportを利用している場合や、圧縮ファイルの保存先の命名規則が特殊だった場合など、ページのレイアウトが崩れてしまうケースもあるため有効にする場合は事前にレイアウトが崩れないかなど確認する必要があります。

キャッシュ機能を利用する

Drupalにはページ自体のキャッシュを作成し、次回以降キャッシュした静的ページを出力し高速化を行うことが出来ます。先ほどと同じパフォーマンスページのキャッシュという項目にて「匿名ユーザー向けページをキャッシュする」にチェックを行い、キャッシュの存続期間とキャッシュされたページの期限を指定します。

drupal-cdn2

これにより、動的コンテンツを静的コンテンツに変換したデータがDB内に格納され、次回以降アクセス時にDB内にキャッシュされたコンテンツを返却します。期限の設定を行うと、自動的に Cache-Control:public, max-age=秒数 が付与されるため、一般的な外部CDNを利用している場合、CDN側のキャッシュ時間もコントロールする事が可能です。

Drupal標準のキャッシュ機能を有効にした場合、劇的にロード時間が短縮されたのが分かると思います。

キャッシュ無効

Requests 15
Transerred 138 kB
Load 857ms

キャッシュ有効

Requests 15
Transerred 138 kB 
Load 107ms

 

キャッシュする上での注意点

Drupal標準のキャッシュ機能を有効にするだけで、ページレスポンスが高速化出来ることが分かりましたが、いくつか注意点もあります。

コンテンツ更新時の反映

ページやブロックを更新した際にキャッシュ機能を利用していると直ぐに反映がされず古いコンテンツを返却してしまうことがあります。更新されたコンテンツを反映させるためには、先ほどの画面上にある「全てのキャッシュをクリア」ボタンを都度押すか、指定したキャッシュ時間の経過をまつしかありません。

認証済みユーザーのキャッシュ

Drupal7ではログインしていないユーザーに対してのみキャッシュ機能を有効にすることが可能です。そのため、ログインが必須である会員制などの高速化は行うことが出来ません。
※Drupal8については、標準機能で認証済みユーザーのキャッシュもサポートされています。

DBへの負荷

動的コンテンツを静的コンテンツに変換するのでレンダリングは高速になりましたが、キャッシュされたコンテンツはDB内に格納されているため、DBへの負荷がゼロになるわけではありません。読み込みは常に発生しますし、書き込みもコンテンツ更新時に常に発生します。

このように、動的な要素を可能な限り静的にするという作業を行うことによってページ表示速度が速くなります。CDNサービスもDrupalと同じように動的コンテンツを静的コンテンツとしてキャッシュし、高速配信する仕組みは同じです。

外部CDNを利用した高速化

cdn

さて、Drupal内部キャッシュを有効にするだけでも十分効果が期待できましたが、外部CDNサービスを利用すると更に様々なメリットがありますので代表的な点をいくつかピックアップします。

ファイル別にキャッシュ時間を指定

拡張子別にCDNでキャッシュ

頻繁に更新しないjpgやpngなどの画像はキャッシュ時間を長くするといったことが可能です。これにより極力負荷を軽減しつつ、コンテンツ更新時もそこそこ早めに反映させることが出来ます。

キャッシュさせるコンテンツとキャッシュさせないコンテンツの指定

Drupalでは個別にキャッシュさせるものと、キャッシュさせないコンテンツの指定が出来ませんが外部CDNを利用すると例えば、特定のディレクトリ(admin以下)のコンテンツはキャッシュさせない、URLのパスに特定の名称が入っている場合はキャッシュするといった柔軟なキャッシュコントロールが可能です。

個別にキャッシュ削除が可能

fast-purge

 

Drupalでは一括でキャッシュ削除をおこなっていましたが、これでは削除しなくてもいいコンテンツも消されてしまい、一時的に負荷が増加してしまいます。CDNサービスを利用すると、特定のファイルだけキャッシュを個別削除できたり、正規表現で特定のディレクトリ以下のJPGファイルだけ全て削除するといった指定が可能です。

 

 

弊社で提供しているエッジキャッシュCDNも正規表現・即時キャッシュ削除ができるFastPurgeという機能が標準で付属しており、APIの提供もしているためそのような柔軟なキャッシュ削除を行えるベンダーを利用すれば、システム的に組み込みやすいので便利です。

トラフィック負荷軽減

DrupalはキャッシュをDrupalと同じサーバーに保持し、そこからコンテンツを配信します。そのため、大容量データや大きめのコンテンツを利用している場合は、トラフィック(回線の帯域)の問題により遅延が発生する場合があります。外部CDNを利用すると、Drupalサイトの前段でキャッシュを保持するためトラフィック負荷の軽減が可能です。特に、共有サーバーやVPSなどを利用している場合や、月間転送量に制限があるクラウドを利用している場合外部CDNを利用することによりコスト削減につながる場合もあります。

サーバー自体の負荷軽減

Drupalがキャッシュしたデータは基本DrupalのDB内に格納されます。そのため、アクセスが発生する度にDBへのアクセスも行われますが、CDNを利用するとCDNベンダーが保持しているエッジサーバーにコンテンツが格納され、アクセス時もエッジサーバーから配信されるため、元々のDrupalサーバー(オリジンサーバー)へのアクセス自体を軽減し、結果サーバーやネットワーク負荷の軽減につながります。

ある意味手軽

CDNはサイトドメインにCNAMEレコード設定し、外部CDNサービスのサブドメインに向けるだけで完了します。そのため、万一なにか問題が生じた場合切り戻しも容易ですし、サイト側の設定を一切変更することなく利用できるというメリットがあります。

外部CDNのデメリット

CDNはとにかくイイ!!ということばかりではなく、勿論デメリットも存在しますのでいくつかご紹介したいとおもいます。

お金がかかる

Drupalの標準機能を利用する場合、当たり前ですが無料で今すぐ行う事ができます。CDNサービスの場合、無料サービスもいくつか存在しますが、高速化という点で効果が期待できるのはやはり有料プランの場合が多いです。

登録や設定が一手間かかる

CDNサービスは外部サービスのため、各ベンダーへの申込みや登録が必要です。また、Drupal標準機能と異なり、様々な負荷分散に対応できるよう設定項目も多く、初めてCDN化を行おうとしている方によっては若干敷居が高い場合があります。

キャッシュしてはいけないものをキャッシュしてしまう

Drupalが認証ユーザーと非認証ユーザーでキャッシュ機能を分けられる(Drupal8の場合)のは理由があります。それは、例えば、Aさんのログイン画面がキャッシュされてしまい、その後Bさんが同じURLにアクセスするとAさんのキャッシュされた情報が表示されてしまうという事故を避けるためです。これらはCDN利用時でも内部キャッシュ利用時でも言えることですが、闇雲にキャッシュすると痛い目にあう可能性があります。

外部CDNをDrupalに最適化する方法

それでもCDNを利用してみたい!という方のために、CDN側でどういった設定を行えば一般的な事故を防ぎ安全にサイトの高速化ができるのか、テクニカル的な面でご紹介したいとおもいます。

キャッシュさせないコンテンツの精査

まずは何でもキャッシュすればいいというわけではありません。CDNを利用する上での事故防止は、キャッシュしてはいけないコンテンツの把握です。まずは、CDN全般的に言えることですが、メソッド毎にキャッシュを行わない動作を指定します。

メソッド別キャッシュ動作

基本的にはGETとHEAD以外はキャッシュさせないほうがトラブルが少ないです。

キャッシュさせないメソッド PUT・POST・TRACE・OPTIONS・DELETE(GET・HEAD以外)

Authorization情報が付与されている場合

Authorization情報が付与されている場合認証情報をキャッシュしてしまうと、問題となるためこちらもキャッシュ対象外とします。

次に、Drupalの管理画面セッションで利用されるパスをキャッシュ対象外とします。

パスによるキャッシュ動作

■キャッシュさせないパス一覧(正規表現)

^/status\.php$
^/update\.php
^/install\.php
^/apc\.php$
^/admin
^/admin/.*$
^/user
^/user/.*$
^/users/.*$
^/info/.*$
^/flag/.*$
^.*/ajax/.*$
^.*/ahah/.*$
^/system/files/.*$

可能な限りキャッシュさせるチューニング

キャッシュさせない設定が完了したら、こんどは逆にHIT率を高めるために可能な限りキャッシュさせるチューニングを行います。CDNはリクエストURL毎にキャッシュする動作が一般的ですが、これら以外にもキャッシュキーとなる要素がいくつか存在します。

クエリストリング

query-string-cdn1

リクエストしたURL毎にキャッシュします。クエリが付与されている場合は、クエリを削除後キャッシュするケースと、クエリを含んでキャッシュするケースがあります。前者は一番HIT率が高くなる可能性がありますが、クエリによって出力するコンテンツを判別している場合は不具合が生じるため、その場合は後者のクエリを含んだキャッシュ設定を行う必要があります。

リクエストURLが以下の場合の例:

http://domainname.com/test.jpg
http://domainname.com/test.jpg?cid=xxx&test=1111
http://domainname.com/test.jpg?cid=yyy&test=2222

クエリを含んだURLは別々に(合計3つ)キャッシュします。
クエリを削除したキャッシュの場合は、全て同一コンテンツとして1つだけキャッシュします。

また、弊社エッジキャッシュCDNでは、自動でクエリを正規化してキャッシュすることが可能です。この場合、以下の様なURLでアクセスがあったとしても、同一コンテンツとしてキャッシュが可能となりクエリ別キャッシュ設定においてはHIT率向上が見込めます。

クエリの順番が異なっていても、ソートし同一コンテンツとしてキャッシュ

http://domainname.com/test.jpg?test=2222&cid=yyy
http://domainname.com/test.jpg?cid=yyy&test=2222

Cookieによる判別

cookie-cdn

Cookieはアクセス解析などで利用されることが多いですが、一般的なCDNはリクエストヘッダにCookieが付与されている場合、Cookieを含めてキャッシュするか、それとも正規化してキャッシュするか、または削除してキャッシュするか選択することが出来ます。ページに付与されているCookieは削除してしまうと問題となる場合があるため、Drupalでは代表的なStaticコンテンツだけリクエストヘッダに付与されているCookieを削除するというチューニングを行うのが安全です。

対象ファイル例: jpg png zip css js 等

ユーザーエージェント

user-agent-os

こちらはリクエストヘッダにVary User-Agentヘッダが付与されている場合、キャッシュをデバイス毎に分けるかどうかという判定になります。UAはPCスマホを含めると相当な数が存在するため、よくキャッシュHIT率が悪く悩まれている方の代表的な原因の一つです。UAに関しては、CDNベンダ側でグループ化に対応していればこちらを行う事によりHIT率向上が期待できます。

例:Android → グループ1 Iphone → グループ2  その他PCなど → グループ3

逆にサイト側でUAを判別しモバイルページとPCページを切り替えていたり、異なる画像を出力している場合は、必ずUAの設定をCDN側で行う必要があります。

まとめ:高速化はシンプルISベスト

今回はDrupal標準機能を利用した高速化と、CDNを利用した高速化を行う場合どのような点に気をつけなければいけないのかをご紹介しました。この他にも様々なTIPSはありますが、高速化する上で重要なのはシンプルであれ!ということです。

たとえば、Drupalの標準の機能であるキャッシュを有効にしつつ、さらにCDNを利用してもスピードはほとんど変化がありません。にもかかわらず、どの領域でどれだけキャッシュを保持しているか管理がしづらくなり、トラブルが発生した際の対応も複雑になります。様々なプラグインをいれて高速化をはかったりそもそもキャッシュをせずに他の部分で高速化を図ることは可能ですが、弊社では動的コンテンツを静的コンテンツに変換する方法ほど早いレンダリングはないと考えています。

しかしながら、キャッシュは最初にアクセスしたその時の情報をキャッシュするため、ニュースサイトの用に頻繁に記事が更新されるようなケースでは、十分なキャッシュコントロールプランを検討し通常運用に支障がない程度の設定を検討しなければいけません。

以上、弊社としては初となるDrupal Advent カレンダー2016でした。