しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Fastly CDN が便利そうだったので Azure と使ってみた

The edge cloud platform behind the best of the web | Fastly

Azure にも EdgeCast を使った CDN が用意されていますが、未だにキャッシュしたコンテンツの Purge すら出来ないので、150ms 以下という超高速でキャッシュの Purge が可能な Fastly を試しました。

Fastly の Instant Purge はとても速いので、これまでは CDN が使えなかった動的に変化するコンテンツでもキャッシュ出来るようになります。それらを Fastly ではイベント駆動コンテンツと呼んでいるようです。

The Rise of Event-Driven Content | Fastly

利用する上で、この記事は必読です。ドキュメントには API でも CDN を有効にする手順もあります。

Enabling API caching | Fastly Help Guides

まずは Azure CDN の一般的な利用方法だと思われる Blob との組み合わせを試しました。と言ってもエンドポイントとして Blob の URL を入れるだけで CDN のセットアップ完了です。

エンドポイントを追加すると数分で CDN が有効になるので、すぐに使い始めることが出来ました。

HTTP レスポンスヘッダーにはキャッシュの状態が色々と返ってきています。今回のリクエストはキャッシュにヒットしてくれたようです。

今回 Fastly を試そうと思ったきっかけになるキャッシュの Purge に関しては、管理画面のメニューから簡単に実行可能です。メニューからは 3 種類の Purge が行えるようになっています。

実行すると一瞬でキャッシュが Purge されることが確認できます。本当にリアルタイムでした。

Fastly ではサロゲートキーと呼ばれる任意のキャッシュキーを、HTTP レスポンスヘッダーで返すことが出来ます。複数のサロゲートキーを組み合わせて使えば、キャッシュのグルーピングも可能ですね。

Surrogate Keys: Part 1 | Fastly
Surrogate Keys: Part 2 | Fastly

上のように実際にキャッシュの Purge は管理画面からも行えますが、Fastly の力を発揮させるためには API を使って自動的にキャッシュの削除を行うように作ることが重要です。

Blob だと静的コンテンツなので、次は Azure Web Apps 全体を Fastly に追加してみました。

作成した Web Apps に適当な MVC 5 アプリケーションをデプロイして、キャッシュの状態を確認してみましたが、全くキャッシュされていませんでした。

Fastly を使ってキャッシュを上手く使うためのまとめが、ブログで公開されているので読んでおきます。

A Cache Recipe for Success | Fastly

よく考えれば当然ですが、Fastly はデフォルトで Cache-Control: private や Set-Cookie がレスポンスヘッダーに含まれるコンテンツをキャッシュしないようになっています。

ASP.NET アプリケーションはデフォルトで Cache-Control: private が付くのと、Web Apps は ARRAffinity クッキーを必ず書き出すのでキャッシュされていませんでした。

というわけで Web.config に Cache-Control ヘッダーを出力しない設定を追加します。これで Cache-Control: private がアプリケーション全体で出力されなくなります。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.6"/>
    <httpRuntime targetFramework="4.6"/>
    <caching>
      <outputCache sendCacheControlHeader="false" />
    </caching>
  </system.web>
</configuration>

Web Apps が書き出す ARRAffinity クッキーは、Azure Resource Explorer を使ってクライアントアフィニティをオフにすると書き出されなくなります。

特殊な HTTP レスポンスヘッダーを返す方法ではなく、ARMExplorer 上で clientAffinityEnabled を false に書き換えるだけなので簡単です。

この状態で再度試すと、MVC 5 の出力も Fastly でキャッシュされていることが確認できます。

キャッシュはされましたが、このままだと MVC 5 アプリを修正しても古いコンテンツがキャッシュされたままになるので、API を使ってキャッシュを Purge する処理を追加します。

API と言っても、一番簡単な特定の URL だけキャッシュを Purge する方法は、その URL に PURGE メソッドでリクエストを投げるだけです。API キーなども必要ありません。しかし、めんどくさいので簡単に C# でクライアントを作りました。

https://gist.github.com/shibayan/23425f9f68a91937b7ad

実際にとあるアクションに上のクライアントを使って Purge を行う処理を追加してみました。

var fastly = new Fastly("...");

await fastly.Purge("http://***.global.prod.fastly.net");

こんな感じで書くと、ルートのキャッシュが Purge されます。PurgeAll を実行すると全てのキャッシュが Purge されますが、基本的には URL 単位かサロゲートキーを使って制御するべきです。

データの更新時に関係するページのキャッシュを Purge しておけば、OutputCache と同様のことを CDN レベルで行えるようになるわけです。複数インスタンスでの運用時は、OutputCache と Redis を組み合わせたキャッシュを組むより、Fastly に処理を投げた方が楽そうです。