いわくら君が書いてくれた通り 、トラベルブックではFastlyを導入しました。Fastlyについて初めて分かったことがたくさんありました。列挙してみたら30個もあったので、一個ずつ紹介してみることにします。
そもそもFastlyとは
そもそもFastlyとはCDNのサービスです。現在では後述するCompute@Edgeを主力としたサーバーレス環境を推していますが、とにかくCDNです。今回は www.travelbook.co.jp
ドメイン全てに対して適応し、全てのHTMLページをFastly経由にしました。
もともとVarnishでページをキャッシュしていた部分をFastlyに置き換えることで冗長化・安定化、また、パフォーマンスアップを図ります。
加えて、これまでキャッシュの対象外だったページも、この際TTL付きでキャッシュする、というのが今回やったことです。
詳しくはいわくら君の書いた記事を参考にしてください。
では、「Fastlyについて知らないかもしれない30のこと」を紹介していきましょう。
1. 速い
とにかく速いです。そりゃCDNですから、速いんですが、他のCDNと比べても速いです。 例えば、僕の個人ブログはCloudflareでホストしていますが、手元の環境で比較すると僕のブログが「36ms」と十分速いのに対して、トラベルブックのページは「10ms」とめちゃくちゃ速いです。
2. 料金
料金について、詳しいことは避けますが、想定してたより「安い」というのが印象です。 Fastlyのページにかかれている通り 、最初の10TBが「$0.19/1GB」という従量課金がベースになります。加えて、リクエスト数ごとの料金が追加されます。
従量課金だけではなく「エッセンシャル」「プロフェッショナル」「エンタープライズ」といったある一定のバジェットの含まれたパッケージがあるので、これらも考慮しつつ、プランを決めました。
3. Image Optimizer
同時に提案してもらったのが「 Image Optimizer 」です。オリジンに置いた画像をリサイズしたりリアルタイムで最適化して配信してくれるFastly内のサービスです。今現在、トラベルブックでは同等のことをAWSの「CloudFront + Lambda@Edge」で行っていますが、今後、Image Optimizerも導入するかもしれません。
4. サポート体制
サポートがほんと手厚くて助かりました。「Fastlyを検討しています」という連絡をしたら、すぐに打ち合わせをセッティングしてくれて、セールスエンジニアの方も含めて3人で対応してくれました。契約までも非常にスムーズです。また、技術的な不明点はサポートデスクが対応してくれるのですが、今のところ無料。対応も素晴らしいです。
5. USチーム
後ほど紹介する通り、導入後しばらく立ってから「HTTP/3 + QUIC」の対応を入れました。 その切り替えの際に「万一に備えて、Fastlyのエンジニアが対応できる米国のビジネスアワーに切り替えを実施する」ことを勧められました。 【米国のビジネスアワー】って何時だ?っていわくら君と笑いましたが、とにかくグローバルなはからいもありがたいです。 ちなみに深夜「0時」に作業して、大きな事故なく無事切り替えができました。
6. DNS切り替え
サービスをFastlyに乗せるにはどうするか? いくつか方法がありますが、「DNSのCNAMEを利用する」ことで実現しました。 具体的には、こういうことです。
$ dig cname www.travelbook.co.jp
;; ANSWER SECTION:
www.travelbook.co.jp. 9 IN CNAME n.sni.global.fastly.net.
CNAMEの切り替えをすれば、たったそれだけで「Fastly」になるのです。
7. /etc/hosts
といっても、本番適応の前に www.travelbook.co.jp
ドメインでFastlyを試したい。
これ、どうやるかというと自分のマシンの /etc/hosts
を書き換えるという「なるほど」なやり方を教えてもらいました。
- CNAME先のホストに
dig
をしてIPを取得 - その
IP
とwww.travelbook.co.jp
を/etc/hosts
に追加する - ブラウザで確認
これで、ホスト・ドメイン名そのままでFastlyを試すことができました。
8. インスタントパージ
Fastlyの特徴がインスタントパージです。その名の通りパージ=キャッシュの削除が速いのです。
トラベルブックでは「記事を書いて、それを公開する」というフローが多いのですが、 この際「ページを予めキャッシュしておいて、更新をフックとしてキャッシュをパージする」ということをしています。 インスタントパージのおかげで、「すぐに公開の状態を確認する」ことができます。
9. Purge API
パージは管理画面からもできますが、それ用のAPIもあります。 Fastly APIエンドポイントに対して「PURGE」HTTPメソッドを投げれば、そのURLのキャッシュが削除されます。
PURGE /example/path?parameters
しかしこれ、興味深いのはデフォルトでは「認証なし」でできちゃうので危険です。 なので、キーがないと「PURGE」できないようにしました。
10. サロゲートキー
URLをキーにするだけではなくもう少し凝った「ページの指定」をしたくなります。
例えば、(これはあまりやらないのですが)/topic/
以下のページをパージするとかです。
Fastlyでは正規表現など文字列によるマッチができないので、この場合、サロゲートキーを使います。
例えば「 https://www.travelbook.co.jp/topic/62892 」のページにはサロゲートキーが2つ設定されています。
- topic
- topic-62892
「topic-62892」を指定すれば、この記事単体。「topic」を指定してパージをリクエストすると「topic」をサロゲートキーとして持つページ、つまり/topic/
以下のページをパージできます。
ちなみにこれは上記の「PURGE」APIとはまた別のエンドポイントなんですが、これらのおかげで、管理画面のプログラムからリソースを指定しつつパージを実行できるようになりました。
11. ソフトパージ
ソフトパージという仕組みがあって、これを使うと、いきなりキャッシュを削除するのではなく、古い=「STALE」コンテンツとみなすことができます。オリジンからレスポンスを待つ間はSTALEのコンテンツが返り続けるので、その分、オリジンへの負担が軽減されます。
12. Datadogログストリーム
Fastlyへのアクセスは全てログとして取得できます。 ただ膨大かつストリームですので、どこかに流し込まなくてはいけません。 トラベルブックではDatadogにログストリームを流しています。 これがすごく便利。ひとつひとつのリクエスト・レスポンスが一覧とグラフで見ることができます。 支障のないようにGoogle Botのアクセスの詳細をみるとこんな感じです。 下の方にもっとプロパティがあります。
アクセスはプロパティごとに絞り込むことができます。
例えば、上記の場合「fastly_info_state」がHIT-STALE-CLUSTER
になっています。
これはキャッシュにヒットせず「失効済み=STALEにヒットして返している」ことを表しています。
他にもHIT
やMISS
などがあります。
それをHIT-STALE-CLUSTER
だけに絞ってアクセスを列挙するってことが可能です。
さらにレスポンスタイムでの絞り込みができるので、「100ms以上」のアクセスとかも抽出できます。
実際、導入後はキャッシュの挙動を確認するためにDatadogが活躍しました。 また、例えばですが「同一IPからの過度なアクセス」を把握しやすくなったりしました。
13. Varnish
Fastlyでは、Varnishの2.x系からフォークしたものを独自に手を加えて使っています。 トラベルブックでは、以前からVarnishをページキャッシュに使っています。 そこで、Fastlyを「どでかいVarnish」と捉えるれば、分かりやすかったです。
14. VCL
Varnishは「Varnish Configuration Language = VCL」で設定を書きます。 これがFastlyにも踏襲されていて、Varnishのそれを拡張した「Fastly VCL」で設定を書くことになります。
もちろん管理画面からポチポチと設定できるのですが、基本的にはVCLを使います。 というか管理画面のポチポチした結果は最終的にひとつのVCLに反映されます。
便利なのは、バージョニングされることで、戻すこともできたりします。diffも管理画面で見られます。
今見たら、もう「Version 272」になっていましたね。
15. Terraform
いわくら君の書いた記事 が詳しいですが、VCLを基本とした構成はTerraformで管理しています。トラベルブックでは、管理画面は使用せず、このTerraformを使うことにしています。
16. ACL
ある程度の規模のサイトになると、悪質なエージェントに過度なアクセスをされることがあります。 Fastlyではベーシックな対策としてIPによるブロックができます。 それが「アクセスコントロールリスト=ACL」です。
17. パスベース
www.travelbook.co.jp
全部をFastly経由にしたわけですが、コンテンツによって挙動を変えたいことがあります。
特にキャッシュの設定です。
多くにページに対して、TTLを指定したキャッシュを適用しているわけですが、パスごとにTTLを変えています。
もしくはコンタクトフォームなどはキャッシュしないようにしています。
VCLで記載するわけですが、どうしてもこの方法しかなく、パスを上から正規表現でマッチさせています。
if (req.url.path == "/") {
# TOP
set beresp.ttl = ${default_ttl};
} elseif (req.url.path ~ "^/topic/") {
# まとめ
set beresp.ttl = ${default_ttl};
} elseif (req.url.path ~ "^/new_path/") {
# 新しいパス
set bresp.ttl = ${default_ttl};
# 直接TTL指定する場合
set bresp.ttl = 1h;
}
パスベースで設定ができるので、あくまで例ですが、更新頻度が高い/topic/
以下はTTLを300s
にするとかできます。
18. Stale-While-Revalidate
TTLが過ぎてキャッシュが消滅すると、オリジンからレスポンスが返る間、アクセスが常にオリジンにいってしまいます。
そこで、Stale-While-Revalidate
という仕組みが活きています。
キャッシュを生成する間は古いコンテンツ=STALEを返し続けるのです。
Stale-While-Revalidate
を理解するために、僕が以前「Varnish」のケースで図を書きました。
それを掲載します。Varnishを「Fastly」に置き換えてください。
トラベルブックではSTALEを保持する時間を長めに取ることで、なるべくオリジンに行かないようにしてパフォーマンス向上を狙います。
19. LRU
困ったのが、キャッシュがTTL手前で消える現象がたまに発生することです。
特にSTALEが消滅するので、Stale-While-Revalidate
が意味なくなってしまいます。
サポートに連絡したところ、「LRUでメモリからキャッシュが追い出されている可能性がある」との返答をもらいました。
そこで解決策として、TTLを「3700s以上」に設定するといいかもとのこと。
というのも、TTLが3700s以上のものはディスクに書き込まれるから、消滅しにくいのです。
STALEもまた同じくです。
3700sは1時間ちょいと結構長いのですが、可能なところはTTLを3700sにして様子を見ています。
それでもコンテンツによっては、Stale-While-Revalidate
しないものもありますが、
概ねパフォーマンスが出てます。
20. POP
CDNというからには世界の各地にコンテンツを保持し、返却するための拠点があります。 それをFastlyではPOPと呼びます。 これ、Datadogのログで把握できるので、そのキャプチャを貼っておきます。 面白いです。
21. オリジンシールド
Fastlyにはオリジンシールドという仕組みが備わっています。 オリジンの手前にひとつPOP=オリジンシールドを設けて、キャッシュが存在する限りは他のPOPに対してオリジンに代わってオリジンシールドが返却する、という仕組みです。
Users <=> POP / POP / POP <=> Origin Shield <=> Origin
この場合、オリジンに一番近いPOPをオリジンシールドにするのが常套手段です。
トラベルブックはAWSの日本のリージョンを使っているので、tyo-tokyo-jp
をオリジンシールドにしています。
22. デバグ
Fastlyが返却するレスポンスをデバグするのに、便利なのがリクエストヘッダに「Fastly-Debug:1
」を付加する方法です。
このフラグが立つと通常では見られない値を見ることができます。
fastly-debug-digest
fastly-debug-path
fastly-debug-ttl
Fastlyを導入してるサイトなら、意図的に無効にしていない限りFastly-Debug:1
付きでアクセスするとデバグできたりします。
23. 他サイト調査
事前に、Fastlyを導入している・してそうなサイトを徹底的に調べました。 レスポンスヘッダを見たり、ChromeのdevToolのNetworkをみたりです。 また、以下の記事も非常に参考になりました。
- CDNを使って表示速度を2倍に 日経電子版リニューアルの舞台裏 - ログミーTech
- Coding CDN in Moneyforward - Speaker Deck
- Fastlyのパスベースルーティングで実現するWEARのゆるやかなクラウド移行 - ZOZO TECH BLOG
- 一休レストランの店舗ページをSPA化して Fastly で段階的リリースした話 - 一休.com Developers Blog
24. デバイス判定
何も考えずにキャッシュさせると、スマホでPC用のページが出たり、PCでスマホのページが出てしまったりします。
キャッシュキーにデバイスの情報、つまり「mobile」「desktop」を含めないといけません。
トラベルブックのバックエンドサーバーでは、単純にUser-Agent
の文字列を見て、マッチさせて判定しているので、
同じ仕組みをVCLで記載しました。
if (req.http.User-Agent ~ "iPhone" || (req.http.User-Agent ~ "Android" && req.http.User-Agent ~ "Mobile")){
set req.http.X-device-type = "mobile";
} else {
set req.http.X-device-type = "desktop";
}
バックエンドと同じ判定ロジックになるので、齟齬がなくなるのです。
25. ヘッダの正規化
返却するボディのエンコード(gzip、brotliなど)によってキャッシュが変わります。
それを要求するのがリクエストのAccept-Encoding
ヘッダなのですが、これが表記によっては同じgzipを返してほしいのに、いくつか存在してしまいます。
Accept-Encoding: gzip
Accept-Encoding: gzip, br, deflate
Accept-Encoding: gzip,br,deflate
これではキャッシュが複数存在してしまい、効率が非常に悪い。 Fastlyはこのあたりをいい感じに正規化してくれます。
26. Brotli
Fastlyがコンテンツの圧縮しています。そこでBrotliを入れました。 この効果については いわくら君の記事 が詳しいです。
27. HTTP/3 + QUIC
「攻めたポイント」としてBrotliに加えて、HTTP/3(QUIC)を導入しました。 これらは標準では使うことができず、どちらも「Limited Availability」です。 僕が「使いたい!」とメールしました。
こちらも いわくら君の記事 を参考にしてもらいたいのですが、 なんというか、HTTP/3をしているメディアサイトは少ないので、先端行ってる感がしていいですね。
28. Signal Sciences
アプリケーションレベルのWAFはデフォルトでは付きません。 しばらく前、Fastlyは「Signal Sciences」という会社を買収したのですが、 そこの会社の仕組みを使ってWAFを組んでいます。
29. Early Hints
トラベルブックでは運用していませんが、Fastlyだと、VCLに書くだけで、すぐさま「103 Early Hints」ができます。
sub vcl_recv {
if (req.url ~ "^/topic/") {
h2.early_hints("link: </images/logo.png> rel=preload");
}
}
「103 Early Hints」についてはCloudflareでも試してみたので、そちらも参考にしてください。
30. Compute@Edge
VCLに置き換わるものとしてCompute@Edgeに注目しています。これなら、JavaScriptやRustで書けます。 またサーバーレスの環境としても優秀で、これまでVCLだけではできないこともできるようになりそうです。
例えばですが、 Signed ExchangesのCompute@Edge実装 なんてものもあり、ユースケースにピッタリだなって思いました。
Compute@Edgeについて、詳しくは以下に書きました。
まとめ
ふぅ。これで30個紹介しました。 だいぶ出し尽くした感あります。これから導入を考えている人の助けになると嬉しいです。 これからもトラベルブックではFastlyを使い倒したいと思います。
エンジニア募集中
トラベルブックでは一緒にFastlyを使っていくエンジニアを募集中です。 それに限らず、フロント、バックエンドともにエンジニア来てください。 興味のある方はぜひ、応募を。