読者です 読者をやめる 読者になる 読者になる

しばやん雑記

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

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

Azure

f:id:shiba-yan:20151126210626p:plain

Fastly | Real-time CDN

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

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

The rise of event-driven content (or how to cache more at the edge) | Fastly

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

Enabling API caching - API Caching | Fastly Help Guides

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

f:id:shiba-yan:20151126210459p:plain

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

f:id:shiba-yan:20151126235343p:plain

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

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

f:id:shiba-yan:20151126211617p:plain

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

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

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

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

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

f:id:shiba-yan:20151126235709p:plain

作成した 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 クッキーを必ず書き出すのでキャッシュされていませんでした。

f:id:shiba-yan:20151127000406p:plain

というわけで 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 を使ってクライアントアフィニティをオフにすると書き出されなくなります。

f:id:shiba-yan:20151127000712p:plain

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

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

f:id:shiba-yan:20151127001015p:plain

キャッシュはされましたが、このままだと 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 に処理を投げた方が楽そうです。