テクノロジー

CDN入門 Fastlyをメインで見てみる ウェブDBプレスvol.109より

WEBサービスでやっぱり速度は重要な指標です。
ウェブDBプレスvol.109にてFastlyが特集されていたので学習がてら流れをおいつつちょっとだけまとめてみました。

ウェブDBプレスvol.109

とはいえ、文字量はだいぶ多くなってしまいもう少しシンプルにまとめられるようになりたい…

CDNって?

Content Deliverly Networkの略。
コンテンツを配信するためのネットワークシステム。

画像、動画、HTMLファイルなどWebで使われる様々なファイルを大量配信する為の機能を備えている。

通常はCDNプロバイダ各社のサービスを利用することが多い。
一部の事業者は自社でCDNを構築することもある。

使われはじめたのは2000年頃。
当初はWebページの配信に使われていたと考えられる。
現在はゲーム、パッチファイルなどにも使用されている。

その1 CDNのしくみ

基本は、分散ネットワークによるキャッシュと配信。
CDNを利用すると自身で管理しているサーバーではなく、分散ネットワーク上のサーバー群がキャッシュされたコンテンツを配信する。

CDNが組み込まれたシステムにおける「サーバー」とは、下記2タイプ。

  • オリジンサーバー:自身で管理しコンテンツを配信する元となるサーバー
  • エッジサーバー:CDNの分散ネットワーク上にありクライアントからリクエストを受けてコンテンツを代理配信するサーバー

エッジサーバーの働きの例

URLが https://www.example.com にCDNを適用するとする。

1.www.example.comのCNAMEにCDNに提供されるホストを指定。

2.CDNの設定でオリジンサーバーの情報を入力。

3.CDNのエッジサーバーがオリジンサーバーへのリバースプロキシとして振る舞う。

一般的にプロキシはクライアントとサーバーの間に入り、通信を経由させる役割を指す。リバースプロキシは特定のサーバーへのリクエスト時に必ず経由するようにおかれたプロキシ。

CDNは独立したリバースプロキシとして動作する為、オリジンサーバーの動作環境を問わず利用することができる

CDNの分散ネットワーク

CDNの分散ネットワークは世界中に置かれたエッジサーバーにより構成される。
CDNはクライアントからリクエストがあると、分散ネットワーク上でクライアントと物理的に近いエッジサーバーからコンテンツを配信。

選択されたエッジサーバーはキャッシュあり・なしに紐付いて下記対応を実施する。

キャッシュがある!→即座にコンテンツを配信
キャッシュがない!→オリジンサーバーにリクエストしてコンテンツを取得・配信

CDNのメリット

  • キャッシュによるレスポンスの高速化
  • 伝送距離の短縮による遅延提言
  • アクセス集中時や大量配信の安定化
  • 運用費用の節約

キャッシュ以外のエッジサーバーで行える処理

CDNプロバイダにとってキャッシュ以外にどのような機能を追加するかは競争上重要なポイントとなっている。

主要なCDNプロバイダ

Amazon CloundFront

Amazon CloudFront は、データ、動画、アプリケーション、および API をすべて開発者にとって使いやすい環境で、低レイテンシーの高速転送により視聴者に安全に配信する高速コンテンツ配信ネットワーク (CDN) サービス。
Amazon CloudFront

Google Cloud CDN

Cloud CDN(コンテンツ配信ネットワーク )は、世界各国に分散している Google のエッジ接続拠点を使用して HTTP(S) 不可分散されたコ>ンテンツをユーザーの近くにあるキャッシュに保存します。Google のネットワーク エッジのキャッシュにコンテンツを保存すると、コストを削減しながら、ユーザーにより速くコンテンツを配信できます。
Google Cloud CDN

Azure CDN

最高のエクスペリエンスのために速度を優先
オンライン コンテンツ配信では、ユーザー エクスペリエンスがすべてです。Azure Content Delivery Network (CDN) を使用すれば、読み込み時間の短縮、帯域幅の節約、応答性の向上が可能です。Web サイトやモバイル アプリの開発と管理のほか、ストリーミング メディアやゲームのソフトウェア、ファームウェアの更新プログラム、IoT エンドポイントのエンコードと配信など、用途を問いません。

Azure CDN

Akamai

スピードとインテリジェンス、そしてセキュリティをEdgeで
Akamai はデジタル体験をユーザーに近づけ、攻撃や脅威をユーザーから遠ざけます。

Akamai

Cloudflare

Cloudflareはインターネットに接続した膨大な数のWebサイト、API、SaaSサービス、その他の資産を高速化して保護します。拡大を続けるCloudflareのデータセンターに追加されるすべてのサーバーで、エニーキャスト技術によるスケールメリットを可能にします。

Cloudflare

Fastly

Behind the best of the web.
Empower your developers, connect with your customers, and grow your business with today’s leading edge cloud platform.

Fastly

Fastlyの特徴。

  • 優れたキャシュパージの速度
  • Vanishベースのカスタマイズ性

キャッシュパージとはエッジサーバーに対し、特定のキャッシュの破棄を指示する操作。通常キャシュパージは少なくとも秒単位を要するが、Fastlyは150ミリ以下でパージする。
キャッシュされた、更新頻度の高い動的生成コンテンツに対してもす速くパージできるため、更新頻度の高いコンテンツに対しても適用しやすい。

更に、パフォーマンスやセキュリティの面で付加価値を提供する機能も豊富に備えている。

CDN検討のポイント

  • 費用
  • 機能
  • PoPの分布

※PoPの数が全てを決めるわけではない

複数のCDNを使い分ける方法もあり

用途に応じて複数のCDNの使い分ける方法もある。
DNSによるGSLBを切り分けるなどで実現できる。

その2 HTTPキャッシュの基礎知識

キャッシュの分類

  • HTTPキャッシュ
    ブラウザ内のようなクライアント内、CDNのようなプロキシサーバー内で保持するHTTPの仕様

現在の主要な仕様はRFC 7234として規格化されている。
HTTP/2でもキャッシュのメカニズムはRFC7234を引き続き参照している。

HTTPキャッシュとして保持される場所は大きく分けて下記2つ。

  • ローカルキャッシュ
  • シェアードキャッシュ

ローカルキャッシュ

ブラウザが実行されている端末内に保持されるキャッシュ。
キャッシュとして機能するのは一度リクエストしてレスポンスを受け取ったあとに2回目以降。ログイン中に生成されるプライベートな情報が含まれるHTMLを無闇にキャッシュさせるべきではない。

シェアードキャッシュ

ブラウザとオリジンサーバーの間にあるプロキシサーバーなどのWebサーバーが保持するキャッシュ。
ローカルキャッシュ同様2回目以降に有効になるが、共用な為、1人目の誰かがリクエストしたあとの2人目以降の全員に有効。

注意!

このキャッシュは共用になる為、プライベー トな情報は一切保持してはいけない!

独自ロジックなキャッシュ

HTTPキャッシュの仕様に依存しない独自ロジックのキャッシュもある。
しかし全体構成を複雑してしまう傾向がある。

Webアプリケーションが配信するキャッシュ対象

対象は大きく分けて下記2つ。

  • ナビゲーションリソース
    HTMLやAPIレスポンスなど。
    ナビゲーションリソースはページを表示するために最初に必要になる為遅延させることはできない。

  • 静的リソース
    CSSやJavaScript、画像など。
    ナビゲーションリソース以外でWebページの表示必要な内容なものが対象。

HTTPキャッシュの制御

主にCache-Controlレスポンスヘッダで制御される。
このヘッダで指定した内容を解釈し、キャッシュを処理する。

Cache-Controlヘッダの記述例

Cache-Control: public,max-age=604800

→このリソースは公開されたものである為、604800秒(7日間)は有効なものとして扱うことを指定。

キャッシュ制御は大きく分けて3つ。

  • 1.キャッシュの可否
  • 2.キャッシュのリソース有効期限
  • 3.キャッシュの有効性の検証

それぞれ詳しくみていく。

1.キャッシュの可否

対象のリソースがどんな公開範囲でキャッシュするのか・しないのかに関する制御。

例えば、下記のような指定がある。

  • publicとprivate:キャッシュの公開範囲を指定
  • no-store:キャッシュさせたくない内容を制御

2.キャッシュのリソース有効期限

RFC 7234におけるFreshness、つまり鮮度を制御する。

例えば、下記のような指定がある。

  • max-ageとs-maxage:有効期限を指定
  • immutable :永続的キャッシュ→全体に変更されないことが前提な為、無闇に指定してはいけない
  • Expiresヘッダ:有効期限を指定する、Cache-Controlより古くからある指定→古い為、Cache-Controlと両方指定されていたらCache-Controlヘッダが優先される

3.キャッシュの有効性の検証

キャッシュを使ってよいかオリジンサーバーに問い合わせる有効性検証をを行う。

例えば、下記のような指定がある。

  • no-cacheとmust-revalidate:検証ルールを指定
    →max-ageによる期限切れ以外で有効性検証を必須にする

  • EtagとIf-None-Matchヘッダ:検証子と条件付きリクエスト

  • Last-ModifiedとIf-Modified-Sliceヘッダ:有効性検証のHTTP/1.0における仕様

  • stale-whilerevalidateとstate-if-error:期限ぎれキャッシュの再利用
    →期限切れ(stale)キャッシュを利用できるようRFC5861「HTTPCache-Control Extensions for Stale Content」として規格されている。
    ただし、2019年1月時点ではどのブラウザも未対応。

キャッシュのバリエーションをコントロール

同じURLでも異なるリソースを配信する場合は、バリエーションを制御する必要がある。

例えば下記のような例が想定される。
– ユーザーエージェントによりモバイル向けとデスクトップ向けで異なるリソースを配信する
– Accept-Languageリクエストヘッダを元にした国際化対応
– Accept-Encodingリクエストヘッダを元にしたgzipの適用

バリエーション制御にはVaryレスポンスヘッダを使用する。

CDNを利用する際はキャッシュヒット率が重要で、Varyヘッダを適切に制御することで全体的なパフォーマンス向上を期待できる。

その3 Fastlyの基本的な使い方

Fastlyの導入

配信設定には下記が必要。
– 自身が管理するオリジンサーバー
– 公開URL
– Fastlyを通して配信するドメイン及びDNS設定手段

導入にあたっては大まかに下記の流れがある。

1.アカウント作成
2.Webページの配信設定
3.Webページの配信確認

それぞれ詳しくは下記。

1.アカウントの作成

50ドル分の試用枠があり、試用時点ではクレジットカードの情報を登録する必要はない

2.「設定」Webページの配信

Fastlyでは配信するWebページのドメインごとに設定をまとめたものを「サービス」として作成・管理する。

サービスの作成

下記を登録する。
– Fastlyを通して配信するドメイン
– オリジンサーバーのIPアドレスorホスト名
– 証明者のホスト名(Certificate hostname)※TLSを利用する場合

DNSにCNAMEレコードの追加

※ホスト名はTLSの利用の有無で変わる

3.「確認」Webページの配信

PoPやキャッシュヒット状況はレスポンスヘッダで確認できる。

キャッシュが使われた!

x-cache: HIT
x-cache-hits: 7
x-served-by: cache-nrt6138-NRT

キャッシュが使われていない!

x-cache: MISS
x-cache-hits: 0
x-served-by: cache-nrt6133-NRT

オリジンサーバーを保護しよう!

オリジンサーバーに自由にアクセス可能な状態にしておくとセキュリティなどへの懸念が想定される。
制限にあたっては下記のような方法がある。

  • 認証情報を利用したアクセス制限

  • IPアドレスを利用したアクセス制限

TLSを用いたセキュアな配信をするには?

TLSで配信を行うには下記のような方法がある。

  • 無料の共有TLSを使用する
  • 共有TLS証明書サービスを使う
  • 共有TLSワイルド証明書サービスを使う
  • 所有済みTLS証明書のホスティングサービスを使う

Fastlyのコントロールパネルでできること

  • 基本設定
  • 配信の詳細なカスタマイズ
  • 配信状況のモニタリング
    などがWeb上のコントロールパネルで設定できる。

Fastlyのコントロールパネル HOME画面

すでにサービスを作成している場合、ログイン後まず表示される画面。

Fastlyのコントロールパネル STATS画面

各サービスへのリクエスト数やキャッシュヒット率などさまざまな数値をグラフで確認できる。
STATSはstatistics(統計)の略。
表示は下記2つのタブで分かれている。
– Real-timeタブ:現在の配信状況を確認できる
– Historicタブ:過去の配信状況を確認できる

Real-timeタブでは下記のような指標を確認することができる。

項目 説明
GLOBAL POP TRAFFIC PoPごとのトラフィック
REQUESTS リクエスト数
ERRORS エラー数

Fastlyのコントロールパネル CONFIGURE画面

サービスの配信設定やキャッシュ操作ができる。
設定はバージョン管理され、「過去のバージョンに切り替える」といったこともできる。

キャッシュの仕様と機能

Fastalyでは多くの機能が提供されている。

キャッシュの制御

オリジンサーバーから配信されるコンテンツをどうキャッシュするかは前述したCache-Controlヘッダに基づき行われる。
また、より複雑な設定ができるSurrogateヘッダもFastlyではサポートされている。
Fastlyは独自でSurrogate-Keyヘッダを実装しておりこれが便利。
Surrogate-Keyヘッダは任意のキーに従い、それらのキーとリクエストURLを関連づける。キャッシュの有無自体を制御するものではなく、キャッシュ削除においてキーごとにグルーピングされたURLに対し操作できる。

「Surrogate」は代理の意。

Fastlyがキャッシュしない条件
  • リクエストメソッドがGET、HEAD以外の場合
  • レスポンスヘッダにCache-Control:privateが含まれる
  • レスポンスヘッダにSet-Cookieが含まれている「
キャッシュの有効期限

シェアードキャッシュはCache-Controlなどの値に基づいてコンテンツの有効期限を設定する。複数のヘッダにより指定されている場合は次の優先順位に従う。

  • 1.Surrogate-Control
  • 2.Cache-Control:s-maxage
  • 3.Cache-Control:maxage
  • 4.Expires

キャッシュパージ

有効期限を待たずにキャッシュを削除する機能のことを「パージ機能」という。
Fastlyでは、コントロールパネルのCONFIGURE画面や、Fastlry APIを使い削除できる。

Fastlyではキャッシュパージの速度がはやい

Fastlyにおいては、インスタントパージとも呼ばれ文字通り即座にキャッシュの削除が可能。キャッシュパージ後、すべてのPoPでのキャッシュは150ミリ秒以内で完了する。
その為、CDNの恩恵が受けにくいとされるデータ更新を即反映させたいコンテンツにおいてもCDNの恩恵をすぐ受けることができる。

期限切れの状態にするソフトパージ

キャッシュを期限切れ、即ちTTLを0にする。
期限切れキャッシュを配信する設定をしたうえでソフトパージを行うと指定期間の間は古いキャッシュを配信し、その間にオリジンサーバーから新しいコンテンツを取得しキャッシュを生成する

キャッシュパージの対象

Fastlyでは次の3種がある。

  • 指定したURLコンテンツ
  • 指定したkeyをSurrogate-Keyヘッダに持つコンテンツ(Purge key)
  • すべてのコンテンツ(Purge all)

「すべてのコンテンツ」に対してはソフトパージ機能を利用できない。

オリジンシールド

オリジンサーバーへ直接リクエストを行うPoPをシールドPoPとして任意に選び、その他のPoPからのリクエストをすべてシールドPoP経由にするもの。

通常:オリジンサーバーへのリクエストもPoPの数だけ行われる
オリジンサーバーを利用した場合:シールドPoPにキャッシュがあればそれを利用する
→キャッシュヒット率の向上&オリジンサーバーの更なる負荷軽減が見込める。

より詳細な配信設定のカスタマイズーVCLを利用する

詳細なカスタマイズはVCLを利用して設定できる

VCL

Varnish Configuration Languageの略。
Varnishで利用される。
Varnish は、HTTP アクセラレー。Web サーバのリバースプロキシとして動作する。

コントロールパネルでの設定は裏側ではすべてVCLに反映されている。

サブルーチン

VCLの記述にはサブルーチンごとの処理を理解することが重要。
クライアントのリクエストを受けてから、レスポンスを返すまで、例えば下記のようなサブルーチンに分けられる。

サブルーチン名 説明
vcl_recv クライアントからのリクエストをうけたとき
vcl_hash キャッシュの有無を確認するとき
vcl_pass キャッシュしないコンテンツのとき
vcl_miss キャッシュが存在しないとき
vcl_hit キャッシュがヒットしたとき
vcl_fetch オリジンサーバーからの取得のあと
vcl_error エラーが発生したとき
vcl_deliver クライアントに配信する前
VCLで利用可能な変数

よく利用される変数は大きく下記に分けられる。

  • クライアントからのリクエスト情報に関するreq.*
  • オリジンサーバーからのレスポンシブに関するberesp.*
  • Fastlyからのクライアントへのレスポンシブに関するresp.*
変数名 説明
req.url リクエストされたURL /dir/index.html?lang=ja
req.url.path リクエストされたURLからクエリ文字列を除いたもの /dir/index.html?lang=ja
beresp.* オリジンサーバーから返却された情報。 beresp.satusなど
beresp.ttl エッジサーバーでキャッシュする時間 120s、1m、30dなど
resp.* Fastlyからクライアントへのレスポンス情報。 主にvcl_deliverサブルーチン内で利用。|resp.statusなど
resp.status クライアントに返却するステータスコード 200、404、500、503など
Fastly VCL boilerplate

VCLの基本的な設定はboilerplateとして公開されている。

sub vcl_recv {
#FASTLY recv
# HTTPリクエストメソッドがHEAD、GET、FASTLYPURGEではない場合は
# キャッシュしない

if(req.method != "HEAD" &&
req.method != "GET" &&
req.method != "FASTLYPURGE" &&{
return(pass);
}

# キャッシュがあるかチェック、あれば使う
return(lookup)
)
sub vcl_recv {
# FASTLY fetch

(間は省略)

# オリジンサーバーのレスポンスヘッダのCache-Controlに
# privateがある場合にはキャッシュしない

if (beresp.http.Cache-Control ~ "private"){
set req.http.Fastly-Cachetype = "PRIVATE";
return(pass);
} 

(間は省略)

# オリジンサーバーのキャッシュ系のレスポンスヘッダの値に
# 応じてキャッシュ時間を設定する
if (beresp.http.Expires ||
    beresp.http.Surrogate-Control ~ "max-age" ||
    beresp.http.Cache-Control ~ "(s-maxage|max-age)"){
    #keep the ttl here
    }else{
# apply the default ttl
set beresp.ttl = 3600s;
}
return(deliver);
}
sub vcl_hit{
# FASTLY hit
if(!obj.cacheble) {
return(pass);
}
return(deliver);
}
}
sub vcl_miss{
# FASTLY miss
return(fetch);
}

sub vcl_deliver{
# FASTLY deliver
return(fetch);

}
}

その4 Fastlyにおける実践的なキャッシュ設計

5G規格のように成長を続けるインターネット環境に適応する為、CDNはよりその重要度を増している。
CDNを利用しパフォーマンス向上の戦略を考える場合、CDNの利用を想定した戦略設計が不可欠。

CDNを前提とした設計の重要性

CDNは重要な役割を持つパーツと考える

CDNは重要な役割をもったパーツといえる。
FastlyはVCLによってリクエストやレスポンスを詳細に制御できる。
エッジサーバーはクライアントからのリクエストを最初に受け取る窓口として重要な役割を持ち、例えば下記のような処理はエッジサーバーに委譲するようにする。
– ユーザーエージェントの判定
– キャッシュのバリエーションの制御

キャッシュやエッジサーバー処理の初期設計が重要

キャッシュ設計やエッジサーバーへの処理の移譲はアプリケーション設計の根幹に関る。

一度できあがったWebアプリケーションに対しCDNによる効果を最大化しようとするとコンテンツやコードに大幅な変更が必要になりがち。

凝った制御の後付けは難しいと考えておいたほうがよい。

Fastlyを利用したナビゲーションリソースのキャッシュ戦略とは?

ナビゲーションリソースのキャッシュ設定例について記してみる

ナビゲーションリソースのキャッシュは更新頻度やコンテンツ設計に大きく依存する。
その為、複雑性も高いが適切に設定すればパフォーマンスへの効果も高い。

動的に生成されるナビゲーションリソースはレスポンスに数百ミリ秒かかることもある。

パブリックコンテンツとプライベートコンテンツの分離

ここではパブリックコンテンツ・プライベートコンテンツはそれぞれ下記のように定義する。

  • パブリックコンテンツ:誰に対しても同じ情報を返す
  • プライベートコンテンツ:ユーザーによって異なる情報を含む

プライベートコンテンツを含むリソースは**シェアードキャッシュに保持してはならない***。

リソースをURL単位でプライベートなものとパブリックなものに分離する必要がある。

例として、下記条件の場合の例について記す。

  • HTMLを返すWebサーバーはFastlyがキャッシュを保持してもよいパブリックコンテンツのみを返す
  • ユーザー依存情報を含むプライベートコンテンツはAPIサーバーから取得する
  • プライベートコンテンツの取得に必要なアクセストークンはJWT(JSON Web Token)としてCookieのキー名tokenに保持されるものとする。

パブリックコンテンツのキャッシュ制御

パブリックコンテンツは積極的なキャッシュとキャッシュヒット率の向上がポイント。

  • 更新頻度と反映遅延の許容度に合わせたTTLの決定
    FastlyはSurrogate-ControlやCache-Controlレスポンスヘッダのmax-ageディクレティブなどの値を参照してキャッシュのTTLを決定する。
    コンテンツ更新時に反映されるまでの遅延時間の許容度に合わせてmax-ageディレクティブの値を設定しよう。

  • Surrogate-Keyの管理による更新の反映
    動的生成されるコンテンツでTTLを無視して即座に更新を反映したいときはSurrogate-KeyレスポンスヘッダとパージAPIを利用した制御が有効。

  • ESI(Edge Side Include)によるリソースおよびキャッシュの分割
    動的生成されるHTMLに通常のコンテンツに加えて新着情報のような更新頻度が高いコンテンツが含まれているとキャッシュ管理してもパージ頻度が高い為キャッシュヒット率が上がらないことがある。
    その場合はエッジサーバー上でほかのURLのリソースを合成するESIを利用してキャッシュお粒度を分割する手法がある。

<!--通常のコンテンツ-->
<esi:include src="/foo-contents.html" />
<main>
<aside>
<!--新着情報-->
<esi:include src="/bar-updates.html" />
</aside>

が記述された部分には、src属性のURLから取得したHTMLが展開される。

  • キャッシュを保持させたくない場合はmax-age=0
    シェアードキャッシュにもローカルキャッシュにも保持させないようにすることができる。

ただ、max-age=0を指定しても同時に発生したリクエスト間ではキャッシュを共有してしまう可能性がある為プライベートコンテンツの場合は指定するべきではない。

プライベートコンテンツのキャッシュ制御は情報漏洩リスクを考慮しパブリックコンテンツと区別しキャッシュを禁止する必要がある

  • Cashe-Control:privateでシェアードキャッシュを禁止

  • プライベートコンテンツの非同期レンダリング

  • ログイン前提のWebサービスでは劇的な効果は望めない
    グループウェアや金融サービスなど。

パブリックコンテンツでログインの有無をユーザー属性化

ログインの有無によってリンク導線やバナー・レイアウトなどの表示を分岐したい場合がある。

ログインの有無は2通りのユーザー属性としてVaryヘッダによるパブリックコンテンツのバリエーションとして扱うことができる。

  • オリジンサーバーへのリクエストヘッダにログインの有無を付加
    Cookieのtokenに入ったJWTからトークンの有効期限をUNIXタイムで保持したexpireを抽出し、現在の時間と比較・X-Maybe-Loginフラグにてログイン有無を判別する

  • ログインの有無を動的生成時のフラグとして活用

キャッシュのバリエーション制御

  • キャッシュヒット率の向上
  • User-Agentの正規化
  • Accept-Encodingの正規化
  • Varyを設定してキャッシュバリエーション制御
  • クエリ文字列の順序の統一

静的リソースのキャッシュ戦略

静的ロソースのキャッシュは適切にCashe-Controlを指定してローカルキャッシュを活かすことが重要。

CSSやJavaScriptのキャッシュなどの静的リソースは更新頻度が不定でmax-ageディレクティブの指定が悩ましい

更新されるときはHTMLとともに確実にキャッシュを破棄して更新されるようにしたいリソース。
その際に適しているのはrevvingと呼ばれるテクニック。

revvingでは、bundle.v1.jsとして配信していたものを、更新があった際はbundle.v2.jsとして配信する。

算出したハッシュ値をファイル名に挿入するスクリプトを用意すればweebpack以外の自前のプロセスでもrevvingを実現できる。

CSSやJavaScriptのキャッシュなどの静的リソースは更新頻度が不定でmax-ageディレクティブの指定が悩ましい

Service Workerファイルはmax-age=0が確実

Service Workerは機能の強力さから処理の更新時、バグがあった際の悪意のあるコードが混入された際に即座に更新されて欲しいリソース。

revvingを適用すると前のファイル名の古いワーカーを個別にunregister()する必要がある為、revvingの適用は行わないほうがよい。

画像のキャッシュ

JEPG、PNG、WebPなどの画像リソースはファイルサイズが大きい為、キャッシュが有効に働くとパフォーマンス面での恩恵も大きくなる。

UIとして扱われる画像はファイル名で制御

画像を呼び出すコードにより変更が発生するため、HTML、CSS、JavaScriptと同じタイミングで更新する。

画像はファイル名を手もとでコントロールできる為、

  • Cache-Control: max-age=31536000,immutable のように長期指定をする
  • 更新時には必ずファイル名を変えて保持済みのキャッシュを無効にする

のような運用手法で実施する。

コンテンツとして扱われる画像は入稿システムによる
  • ユニークなファイル名が保証されているのであれば、revvingと同じ扱いで長期のキャッシュを指定できる
  • 何らかの問題がありすぐ差し替えが必要になる場合のことも想定しておく
フォントは不変なものとしてローカルキャッシュを利用

Webフォントは途中で変更される可能性はほぼないと考えられる為、不変を前提をした指定でローカルキャッシュを活用するとよい。

フォントファイルのアップデートが必要な場合はファイル名を変更することで対応が可能な筈。

その5 CDNの高度な機能

画像の最適化

Webページを通じて配信される画像コンテンツは増え続けている。
一方、利用されるデバイスを増え続けている。

CDNの画像コンテンツ最適配信を利用するとオリジナル画像から各デバイスに最適化された画像を自動で生成し、配信できる

画像最適化配信するCDNの機能例

  • Fastly Image Optimizer
  • Akamai Image Manager

などがある。

最適化機能 指定のサイズに画像をリサイズ・クロップ

  • 画面サイズやピクセル比でリサイズ
    Fastly Image Optimizerでは、画像URLにクエリ文字列を付与すると画像をリサイズできる

  • 長方形や正方形などさまざまな比率でクロップ
    Fastly Image Optimizerでcropパラメーターで横幅と縦幅の比率を、widthで横幅を指定できる

  • 画像の重要な部分が見切れないクロップ
    Fastly Image Optimizerでsmartパラメーターを追加することで写真の内容を認識し適切な中心点を選択してくれる

より快適にWebでやりとりする為に・画像データ容量の削減

近年、カメラの性能アップと共にWebでやりとりされる画像データの容量はどんどん大きくなっている。

対策として画像サイズの変更のほか、画像データの容量をへらす方法がある。

  • 画像圧縮によりデータ容量を削減

クオリティレベルを指定し画像容量を削減する
クオリティレベルは1から100の間で指定可
Fastly Image Optimizerではqualityパラメーターで指定できる

  • Fastly Image Optimizerで圧縮率の高いWebP形式に変換する
    WebP形式はgoogleによってトラフィック量軽減と表示速度短縮を目的として作成された。

Fastly Image Optimizerではauto=webpパラメーターを設定すると、WebP形式で表示可能な場合は自動的に画像形式を変換してくれる。

CDNを利用することで利用できるセキュリティ対策

CDNを利用するとセキュリティ対応の一部をCDNに任せることができる。

  • 脆弱性が公表される前。公表された直後に自動的に対策が実施される
  • セキュリティの設定を変更する場合、即座に世界中のエッジサーバーに反映可能
  • Linuxカーネル・OpenSSLの脆弱性といったセキュリティ対応はどのCDNでも利用可能(程度の差はあり)
  • DDosやbotによる攻撃対応はAkamai・Fastlyなどの独立系CDNで提供されている

新たなセキュリティリスクに対し自動対応してくれるのだ

例えば、LiNuxカーネルのセキュリティ脆弱性の発表からオリジンサーバーの対応完了までタイムラグがあったとしてもCDN側で対応してくれる。

その一例として、Linuxのコミュニティと連携しTCP実装に関する脆弱性について情報開示前から対策を全エッジサーバーに対し講じた事例がある。

DDos攻撃

  • DDosは多数のリクエストによりサーバー・ネットワークに負荷を与えそれらを応答不能にするセキュリティ攻撃。

典型的な攻撃手法である一方、完全な対応が難しい。

DDosに対しCDNは攻撃を検知・不正なリクエストを遮断しオリジンサーバーへの負荷を軽減しサービスを応答不能にしないように運営することが可能になる。

世界中のネットワークで発生していることを把握し、さまざまな攻撃パターンを学習し日々対策を練っているからこそ対応が可能。

実例としてGitHubの例がある。
攻撃中にネットワークの経路をAkamaiに切り替えることで検知から8分間でサービス復旧に成功した。

botアクセスの遮断

botアクセスは日々のアクセスにさまざまに含まれている。
CDNが提供するbotアクセスを遮断する機能を利用すると不正なアクセスによる無駄なサーバー処理を削減できる。

CDNは日々のネットワーク通信からリクエスト元IPアドレスやユーザーエージェント、リクエスト頻度などさまざまな情報を取得しそれらを利用し不正リクエストのパターンを判定、定義する。
不正なbotに返却するレスポンスもカスタマイズできる。
正常レスポンスとよく似た偽ページを返却することで不正botに対策を気付かれにくくすることができる。

Akamaiによる日本航空の例

日本航空にて謎のbotリクエストが多数見られた。
結果、予約エンジンとして利用している外部サービスへ支払う料金が増えてしまった。
IPアドレスによる制御も徐々に効果がなくなり、AkamaiのBot Managerを導入。
導入からBot Managerを根気強くカスタマイズした結果、外部サービスへの支払いを約6割削減することができた。

エッジコンピューティング・エッジサーバーで任意の処理を実行

最近はエッジサーバー上で任意の処理が実行でき、エッジコンピューティングを後押しする機能が追加されてきている。

  • 応答が高速になる
    エッジサーバーは世界中に配置されており利用者に近いサーバーで処理を行い無駄なネットワーク通信を削減できる

  • オリジンサーバーを削減できる
    オリジンサーバーとしてデータベースからデータを返却するAPIサーバー・HTML生成のWebサーバーがあった場合、HTML生成の処理をエッジサーバー上で行うようにするとAPIサーバーだけでWebサービスを運営できる。

Lambda@Edge・AWSで使えるLambda関数での記述

AWSはLambda@Edgeという仕組みにようによりCloud Front上のエッジサーバー上でLambda関数を動かすことができる。

Lambda@EdgeはほかのAWS機能と共通の管理画面で設定することができ、気軽に連携・実行することができる。

Lambda@Edgeでは

  • クライアントからCloudFrontへのリクエストもしくはレスポンス
  • CloudFrontからオリジンサーバーへのリクエストもしくはレスポンス

の4つのタイミングで処理を記述するできる

  • Lambda関数でリクエスト・レスポンスのイベントを利用しさまざまな処理を構築できる

  • Cookieの値を見てレスポンスの内容を変更する

  • ユーザーデバイスに応じ、適切な画像を返却する
# ユーザーの用語に応じて適切なコンテンツを返却する記述例


Cloudflare Workers-Cloudflareで使用できるService Worker形式での記述

Cloudflare Workersはエッジサーバーで処理を記述するCloudflareの仕組み。
FastlyのVCLと同様にHTMLリクエスト、レスポンスの操作ができ、キャッシュの制御を行うのに向いている。

Cloudflare WorkersではVCLではなく、JavaScriptを記述言語にしておりより複雑でダイナミックな操作が可能。

Cloudflare Workersの基本的な動作

Cloudflare WorkersはService Worker APIに基づく。
Service Workerはもともとブラウザ向けに開発されたAPI。

その中のHTTPリクエストを中継・

Cloud Workersは世界中に配置されたエッジサーバー上で動く。
Chromeの安定版と互換性があり、ブラウザと同様の記述動く。

リクエストヘッダに応じてオリジンサーバーを分ける記述
add EventListener('fetch',event =>{
 let url = new URL(event.request.url);

 //リクエストヘッダに"X-Use-Dev-"が含まれる場合ホスト名にdevを追加する
 if(event.request.header.has('X-Use-Dev')){
 url.host = "dev." + url.host;
 }

//プロトコルはhttps固定にする
url.protocol = 'https';

//変更したURLでオリジンサーバーにリクエストする
event.responndWith(fetch(url,event.request));
});

Cloudflare Workerの動作確認

Cloudflareを最も簡単に始める方法:Cloudflare Workers PlayGroundを利用すること。

エッジサーバーに適用するにはダッシュボードなどから適用できる。

WebAssembly

静的なコンパイル言語。
VCL、Service Worker形式よりもダイナミックな操作を行う為に加わった。
javascriptより高速に動作する。
また、RustやGoなどの言語からコンパイルできる為、それらの言語でエッジサーバーの処理を記述できる。

今後は3Dリアルタイムレンダリングやゲームサーバーとしての利用が期待できる。

自分なりのまとめ

他のサービスでも共通ですが使いこなすといいことありそうですがまずは気軽にはじめるにはどうしたらいいのかが分かるといいんだろうなーと思いました。

シンプルにオリジンサーバーエッジサーバーという考え方があるのだなと。

やっぱりこのあたり専属でみれる体制があるとありがたいと思いつつ、まずは気軽に導入するにはどんな方法があるかを見ていきたいと思います。

%d人のブロガーが「いいね」をつけました。