Edge ランタイムの活用とバックアップについて考える
業務では Next.js を活用しています。この Next.js の開発元である Vercel 社の Vercel の提供する機能はWebフロントエンドパフォーマンスについてエポックメイキングなもの変化を起こしたものが数多くあります。
例えば Revalidate 期間を設定して SSR を常にキャッシュした状態でユーザーにレスポンスを返すことのできるISR、柔軟な Caching 制御 そして、Edge ランタイムを使用して、動的でパーソナライズされたコンテンツをキャッシュと共存させて配信できる Edge Functions などです。
これらのアプローチは理論上オリジンサーバーで HTML を配信するよりもレイテンシーを短くすることができます。
こうした、パフォーマンスのみならず、動的でパーソナライズされたコンテンツをキャッシュするというにニーズはオリジンサーバーへの負荷を下げることにもつながります。
しかし、大規模サービスであればあるほど、この Vercel をはじめ特定の CDN ベンダーにロックインされてしまうことを躊躇することでしょう。
また、ベンダーの障害発生時にはその復旧を待つほか対処の方法がなくなります。パフォーマンスの劣化やコストの高騰などが生じるとしても、バックアップを持っておきたいというニーズはあるでしょう。
本稿はそうしたロックインされない利用法や、バックアップについてどうするについて考えるものです。
主な Edge ランタイム
まず、著名な Edge ランタイムは以下などが挙げます。
| ベンダー | サービス名 |
|---|---|
| Cloudflare | Cloudflare@Workers |
| Fastly | Compute@Edge |
| AWS | Cloudfront Functions |
| Akamai | Edge Workers |
Cloudflare や Fastly は Web 上に日本語コンテンツも豊富そうなので、本稿では Akamai の Edge Workers にフォーカスを当てていきます。
Akamai Edge Workers
Akamai Edge Workers は Akamai のEdge サーバーでロジックを実行できる環境です。また、これと組み合わせて、キーバリューストアである Edge KV なども存在します。
プロダクションでの事例としては「BUYMA」で「Akamai EdgeWorkers」早期採用、エニグモが語る評価などが注目されており、ピークタイムにファーストパーティー Cookie を用いて配信のパーソナライズを実現しているとのことです。
Edge で動かす場合、クラウド上で実行させる Web アプリケーションと異なり、デプロイできるコードサイズや 実行環境も独特です。
これらの制約はProduct limitsにまとめられています。
コードサイズの制約が 512 KB ですから、あまり大きなライブラリなどは使えません。JavaScript ランタイムの内訳は V8 で、そのためサポートされている言語は JavaScript のみです。
実装は、イベント駆動のサーバーレスアプリケーションのように記述でき、
onClientRequest,onClientResponse,onOriginRequest,onOriginResponse,responseProviderなどのイベントハンドラーを用いて,これらの JavaScript APIを利用して、ロジックを実装する形になります。
当然ながら ブラウザ依存の API や Node.js のパッケージなどは利用できませんが、
cookie を制御するメソッドなどは提供されており、シンプルなロジックを記述するには事足りそうでした。
利用したいライブラリなどもバンドルツールなどを利用して利用することもできます(前述の通りサイズの制約を気にしなければなりませんが...)
ユースケース
Edge でどんなロジックを実装できるか。多くのWebサービスで使えそうと思った、ユースケースをいくつか紹介します。
サンプルは edgeworkers-examples などで紹介されています。
例1 ログインが必要なページにアクセスがあった際に、ログインしていなければリダイレクトする
cookie のセッションIDの有無を確認して、存在しなければログイン画面にリダイレクトします。
プロダクションで使う場合はオリジンサーバーでも同様のログインチェックの実装を組み込む必要はあると思いますが、オリジンサーバーへの負荷は軽減できるメリットがあるでしょう。
例2 AB テストの振り分け
AB テストユーザーを振り分けます。より詳細な設定値管理や複数の AB テストを同時実現したい場合は Edge EV を用いて、設定値管理をすると柔軟なシステムを実現できそうです。
例3 細かいキャッシュKey制御
基本的には HTML のキャッシュは URL をキャッシュのキーとしてますが、以下の実装ではデバイスごとにキャッシュキーを設定することで同一URLでも別キャッシュを実現できます。
これを利用して、Cookie の値の有無や Cookie の値をバリデーションしてキャッシュを分けるということも可能です。また、ログインステータスを Cookie に保存しておけば、ログインユーザーとそれ以外でキャッシュを分けるということもできそうです。
ポータビリティーの獲得
ベンダーロックインを避けるためにある程度のポータービリティーは獲得したいです。
他のベンダーのサービスでは WebAssembly (WASM) や WASM がコンパイルされる言語などもサポートされていますが、基本的にはどのサービスでも JavaScript がファーストサポート言語です。ポータビリティーを獲得するためには、今のところ JavaScript コードで記述するの良いでしょう。また、V8 は WASM を実行可能なはずなので Akamai Edge Workers でも近いうちに WASM での実行をサポートする可能性も高いと思われます。
そうなれば例えば Go(tiny Go),Rust,Kotlin などのWASMをビルドできる、他の言語で実装したコードも実行可能です。
つまりロジックそのものは JS か WASM サポート言語のいづれかが実装言語の候補となります。先ほどのイベントハンドラーのような組み込み API が実装されている場合は、それを再実装しパッケージとして利用するようにすれば、自前でホスティングあるいは別のクラウドサービスで実行も可能でしょう。
これでポータビリティーを獲得できるのではと考えます。
バックアップ
次にEdgeランタイムに障害が起きた際のバックアップをどうするかです。
実装にポータービリティーを獲得できていれば、2つの異なる実行環境に常にデプロイしておいて、基本は片方を使い、片方はバックアップという使い方も可能です。
選択肢1オリジンの前段にNode.jsプロキシーサーバーを配置する
JavaScript で Edge ロジックを実装した場合、それをそのまま、Node.js で実行します。
WASMをビルドできる言語で実装した場合も、Node.js で WebAssembly を実行できます。
運用としては edge を通らない経路などをあえて開発環境などで作っておき、
このNode.jsのプロキシーソフトウェアを配置しておきます。
常に動作させている状況にして、いつのまにか不具合が起きていたということを防ぎます。
Edge が落ちたはこちらを100%のトラフィックを流し利用します。
選択肢2サービスメッシュのプロキシーを利用する
オリジンサーバーを istio などのサービスメッシュで動作させている場合は、istio で WASM を実行することができるので、ここにバックアップのロジックを配置することもできるでしょう。
しかし、この場合だと JavaScript は実行できないので制約に生じます。
まとめ
本稿では Edge ランタイムの活用とバックアップについて考えてみました。
正直バックアップについてはかなり妄想に近い構想で、コストと効果が釣り合わない気もしますが、実現してみたい気持ちも湧きました。
大規模テック企業であればコスト削減効果も高いでしょうし、チャレンジしてみてもいいのではないかと感じました。
Discussion