WordPressの高速化(Azure CDNの利用)

前回の続きとして、連載の10回目ではAzure CDNを使ってWordPressを高速化します。

前回はページキャッシュとブラウザキャッシュを使ってWordPressを高速化しましたが、CDNを使うともっと速くなります。
CDNはJS、CSS、画像等を別サーバにアクセスさせることで、WordPressそのものへのアクセスを減らすことで高速化します。
せっかくAzure App ServiceでWordPressを使っているなら、ほぼ無料で利用できるAzure CDNを活用しない手はありません。

なお、今回の内容は通常のWordPressユーザ(Linux環境)にも需要があると思うので、Linux環境向けの手順も掲載します。

CDN環境の構築

CDNを利用するにはCDN(サーバ)の構築と、プラグインの利用(Azure App Serviceではカスタマイズ)の2段階の対応が必要です。
まずはCDNのサーバ環境を構築します。
困ったことにAzureで利用可能なCDNサービスは複数あり、どれを使うのか迷ってしまいまいます。

Azureで利用可能なCDN

Azureで利用可能なCDNは3種類あります。
CDNの利用そのものは無料で、クライアントとCDN間の通信費用が有料です。

Verizon(ベライゾン)

Azureで最も古くから取り扱うCDNサービスで、設定の反映が遅い欠点もありますが、機能が豊富で扱いやすいCDNサービスです。
StandardとPremiumの二つの価格レベルが存在し、Premiumは価格が2倍ですがセキュリティやレポート機能が豊富です。
基本的にはAzureのCDNはVerizonを選ぶことになると思います。
また、企業等でセキュリティや分析を重要視する場合はPremiumを選択します。

Akamai(アカマイ)

Verizonの次に採用されたCDNサービスでStandardの価格レベルが存在します。
設定の反映が速く、パフォーマンスはVerizonより良いかもしれませんが、ファイル削除を一括で実行できず使い勝手が微妙です。

Microsoft

Microsoft自身が提供する後発のCDNサービスで標準の価格レベルが存在します。
MicrosoftのCDNのみ独自のSSL証明書(自分で購入した証明書)を使用できます。
(通常は、それぞれのサービス事業者が発行する無料のSSL証明書を使います)
ただ、CDNの保存期間を変更できない、gzipの圧縮対象を変更できない等、使い勝手は微妙です。

CDN(Verizon)の構築

ここではVerizonのStandard価格レベルを導入することにします。

まずはAzure Portalにアクセスします。
https://portal.azure.com

CDNプロファイルの作成

メニューから「CDNのプロファイル」を選択し「追加」ボタンでプロファイルを追加します。
一つのプロファイルで複数のエンドポイント(複数のWebサイト)に対応できるので、CDNサービスの用途毎にプロファイルを使い分ければ良いでしょう。

CDNプロファイルの作成

以下を入力してプロファイルを作成します。
エンドポイント(CDNのURL)は後から作成できますが、ここでは一括で作成する手順を示します。
※CDNのプロファイルはリソースグループの場所を選べません
※サブスクリプションやリソースグループは自身の環境に合わせて指定してください

  • 名前(リソース識別のための名称なので任意名称を指定する)
  • 価格レベル:この例ではStandard
  • CDNエンドポイント名:CDNのURL
  • 配信元の種類:Webアプリ
  • 配信元のホスト名:App Serviceのホスト名を選択
CDNプロファイルの作成

エンドポイントの設定変更

CDNプロファイルが作成されたら、作成したプロファイルに移動します。
エンドポイント一覧から先ほど作成したエンドポイントを選択し、エンドポイントの設定を変更します。

左のメニューから「配信元」を選択し、プロトコルから「http」のチェックを外します。
連載の過去の記事でWordPressへの通信をSSLに限定していることから、公開するCDNのURLをhttpsに限定しています。

CDNのプロトコルの変更

左のメニューから「圧縮」を選択し、gzip圧縮するMIMEタイプを選択します。
デフォルトでは画像が含まれておらず、説明でも画像は含めない旨の記載がありますが、個人的な経験で画像もgzip圧縮がある程度効くようなので追加しています。
(色をつけるためにチェックボックスをONにしましたが、保存時にチェックを入れる必要はありません)

CDNでのgzip圧縮

左のメニューから「キャッシュ規則」を選択し、グローバルキャッシュルールでデフォルトのキャッシュルールを設定します。
デフォルトの7日はちょっと長いのでCDNにキャッシュする期間を変更します。
カスタムキャッシュルールはパス毎にキャッシュルールを変更したい場合に設定します。

  • キャッシュ操作:オーバーライド(上書き)
  • キャッシュの有効期間:1日(メディアの差し替えを想定)
  • クエリ文字列のキャッシュ動作:一意のURLをすべてキャッシュ(デフォルトの「クエリ文字列を無視」だとjsやcss等の変更が反映されない)
CDNのキャッシュ規則の変更

WordPressでAzure CDNの利用

構築したCDNを利用するには通常はWordPressのプラグインを使用します。
Linux環境であればWP Fastest Cacheを利用すれば良いのですが、残念ながらWindwos環境(IIS)では動作しません。

前回導入したWP Super CacheにもCDN機能はあるのですが、相対パスで構成されたテーマでは殆ど機能しません。
コードを見ると単純に文字列を置換しているだけみたいです。
他のプラグインもWP Fastest Cache以外は似たり寄ったりでした(W3 Total CacheAmazon AWS CDNCDN Enablerも同様)。

本連載はWindows環境(IIS)向けに手順を記載していますが、CDNは通常のWordPressユーザ(Linux環境)にも需要があると思われるのでLinux環境向けにはWP Fastest Cacheの導入方法を、Windows環境(IIS)向けにはカスタマイズ方法を示します。

Linux環境の場合

Linux環境であればWP Fastest Cacheを利用します。
ただ、他のキャッシュプラグインとは共存できないようなのでW3 Total CacheWP Super Cacheを導入済みの場合は併用できません。
その場合は次に示すWindows環境のカスタマイズを参考にしてみてください。

まずは管理画面にアクセスします。
https://作成したドメイン/wp-admin/

手順は省略しますがメニューから「プラグイン」⇒「新規追加」を選択し、WP Fastest Cacheをインストール+有効化してください。

続いて、WP Fastest Cacheの設定を変更してみます。
メニューから「WP Fastest Cache」を選択します。

WP Fastest CacheのCDN機能はページキャッシュを前提にしているようです。
そこで、まずは「Settings」タブからキャッシュを有効化します。

WP Fastest Cacheの有効化

次に「CDN」タブ⇒「Other CDN Providers」を選択します。

wp-fastest-cacheのCDN設定

以下を入力します。

  • CDN Url(Azure CDNのエンドポイントのアドレス)
  • Origin Url(WordPressのアドレス)
wp-fastest-cacheのCDN設定

CDNを利用する拡張子の種類を選択します。
デフォルトから特に変更する必要はありません。

wp-fastest-cacheのCDN設定

以降、次の画面にどんどん進んで設定を完了させます。

wp-fastest-cacheのCDN設定
wp-fastest-cacheのCDN設定

「Cloase」ボタンを押します。
※「Remove integration」ボタンは押さない

wp-fastest-cacheのCDN設定

Windows環境の場合

Linux環境であればWP Fastest Cacheを利用すれば良いのですが、残念ながらWindwos環境(IIS)では動作しません。
※厳密には、CDN機能は動いたり動かなかったりと不安定

また、WP Super CacheにもCDN機能があるのですが相対パスで構成されたテーマでは殆ど機能しないため、Azure App ServiceでCDNを利用するにはテーマをカスタマイズしましょう。
なお、Linux環境でWP Fastest Cacheを導入できない場合でも本手順は適用できます。

Azure PortalのApp Serviceの画面から「App Service Editor」を選択し「移動」ボタンを押します。
(現時点ではApp Service Editorはプレビュー版が使用できます)

利用しているテーマファイル内のfunction.phpに対して以下のようなコードを追加します。
※可能なら子テーマを修正します
「_cdn_base」の部分はCDNのエンドポイントのアドレスに適時変更してください。

class SlowcatCache {

  const _cdn_base = "https://slowcat-cdn-sample.azureedge.net";

  public function __construct() {
    add_filter('get_header_image_tag', array($this, 'replace_multi'));
    add_filter('the_content', array($this, 'replace_multi'));
    add_filter('post_thumbnail_html', array($this, 'replace_multi'));
    add_filter('widget_text', array($this, 'replace_multi'));
    add_filter('template_directory_uri', array($this, 'replace_single'));
    add_filter('stylesheet_directory_uri', array($this, 'replace_single'));
    add_filter('wp_get_attachment_link', array($this, 'replace_single'));
    add_filter('wp_get_attachment_thumb_file', array($this, 'replace_single'));
    add_filter('wp_get_attachment_thumb_url', array($this, 'replace_single'));
    add_filter('wp_get_attachment_url', array($this, 'replace_single'));
    add_filter('post_gallery ', array($this, 'replace_single'));
    add_filter('bloginfo', array($this, 'replace_single'));
    add_filter('style_loader_src', array($this, 'replace_single'));
    add_filter('script_loader_src', array($this, 'replace_single'));
    add_filter('metaslider_resized_image_url', array($this, 'replace_single'));
    add_filter('icon_dir', array($this, 'replace_single'));
    add_filter('icon_dir_uri', array($this, 'replace_single'));
  }

  public function replace_single($content){
    $content = preg_replace_callback("/(.*?)(\/wp-content|\/wp-includes)(.*)/i", array($this, 'relace_single_matches'), $content);
    return $content;
  }

  public function relace_single_matches($matches){
    return self::_cdn_base . $matches[2] . $matches[3];
  }

  public function replace_multi($content){
    $content = preg_replace_callback("/<img.*?src\s*=\s*[\"|\'](.*?)(\/wp-content)(.*)[\"|\'].*?>/i", array($this, 'replace_multi_matches'), $content);
    $content = preg_replace_callback("/<img.*?srcset\s*=\s*[\"|\'](.*?)(\/wp-content)(.*)[\"|\'].*?>/i", array($this, 'replace_multi_matches'), $content);
    $content = preg_replace_callback("/<a.*?href\s*=\s*[\"|\'](.*?)(\/wp-content)(.*)[\"|\'].*?>/i", array($this, 'replace_multi_matches'), $content);
    return $content;
  }

  public function replace_multi_matches($matches){
    $matches[0] = str_replace($matches[1] . $matches[2], self::_cdn_base . $matches[2], $matches[0]);
    return $matches[0];
  }
}

$scche = new SlowcatCache();

実施している内容ですが、WordPressにはフィルタと呼ばれる処理を割り込ませる仕組みがあり、wp-contentやwp-includesのパスが存在するURL系の処理のパスをCDNのパスに置換しています。
フィルタに応じて実行しているメソッドを分けていますが、単純に”/wp-content/xxxxx”の文字列が応答するメソッドにはreplace_single、<img src=”xxx”>のようにタグ付きで応答するメソッドにはreplace_multiでパスを置換しています。

全てのパターンを網羅しているわけではありませんが、ある程度は対応できると思います。
※テーマやプラグインによっては「theme_root_uri」「plugins_url」 をフィルタに追加した方が良いかもしれません
※テーマ「THE THOR」では他に「theme_mod_fit_bsLogo_img」「theme_mod_fit_bsEyecatch_noimg」「theme_mod_fit_bsStyle_bgImg」フィルタにreplace_singleメソッドでの置換が必要

動作確認

WordPressの動作が速くなったか試してみましょう。
F12ボタンを押してブラウザの開発者ツールを有効にした状態でWordPressの公開用のページ等にアクセスしてみます。
どうでしょう?速くなってますか???
いいえ、画面の表示は遅いままですね。
前回の投稿でWP Super Cacheが効いている場合はhtmlの表示は速いですがJS・CSS・画像等は遅いまま

CDN経由でのJS・CSS・画像等のアクセスは、初回はCDNの後ろに控えるWordPressにまでアクセスに行くので遅いままです。
また、CDN上にキャッシュとして有効になるには少し時間がかかります(数十秒程度)。
なので、WordPressの各URLにアクセスしたら、1分くらい休憩します。

さて、それではもう一度アクセスしてみましょう。
メチャクチャ速くなってる!

WordPressのページキャッシュとCDN化後の速度

このように適切にWebサイトを構築すると、AMP化しなくても十分に高速化が可能です。
また、高速化するとサーバへの負荷が相対的に下がり、大量アクセスにも耐えられ、サーバ費用を節約できます♪
ここまで速いと月間100万PVでも500万PVでも出て来いや~って感じです。
まあ、月間1000万PVはシングル構成では厳しいかな…(-_-;)