Kinstaはスピードにこだわり、アプリケーションホスティングデータベースホスティングWordPress専用マネージドホスティング、すべてのサービスでGoogle Cloud Platform最速のプレミアムティアネットワークとC2マシンを採用。Cloudflare統合によって、速度とセキュリティを強化し、数万人を超える世界中のお客様のサイト配信を支援しています。

これを実現するまでの道中、静的および動的コンテンツに最適化されたキャッシュルールを設定するために、Cloudflare WorkersとWorkers KVを活用する方法を学びました。

2023年初頭、Cloudflareのキャッシュ管理をより一層強化し、顧客側の設定変更に対するキャッシュの応答性を高めるとともに、社内のバックエンドエンジニアが担当していた機能の更新という重労働をCloudflare Workersに移行。これによって、顧客サイトのキャッシュヒット率が2022年10月から2023年3月までの間に56.3%増加しました。

2023年1月に行ったCloudflare Workersを利用した最適化の結果
2023年1月に行ったCloudflare Workersを利用した最適化の結果

Cloudflare WorkersとWorkers KVによって、作業量の軽減と低レイテンシを実現し、すべてのリクエストとレスポンスをプログラムで編集できるように。新たな機能を実装する際に、何十万ものコンテナに変更をデプロイする必要がなくなりました。Cloudflare Workersで機能を複製または実装し、数回のコマンドとクリックであらゆる場所にデプロイできるため、作業とメンテナンスにかかる日数が削減されました。

Cloudflare WorkersとWorkers KVを使用したリクエストルーティング

Kinstaが運用するドメインはすべてキーとして設定され、キー値にはオリジンのIPやポート、一意の無作為なIDのようなコア設定が最低限含まれています。このデータは、Workers KVで簡単に使用できるため、Workersを使用してリクエストを分析・操作し、想定されるバックエンドにルーティングすることができます。Kinstaでは、Workers KVでPolish、Image Resizing(画像最適化)、Auto Minify(自動圧縮)のような機能も使用しています。

独自IPとポートにリクエストをルーティングするには、Cloudflare固有のRequestプロパティ、resolveOverrideを使用します。以下はその例です。

// KV値を変数に割り当てる
const { customBackend } = kvdata.kinstaConf;

// バックエンドを上書きする
cf.resolveOverride = customBackend;

Workers KVがリクエストのルーティングにうまく機能したものの、キャッシュに一貫性のないレスポンスがあることにすぐ気がつきました。また、時に顧客がPolish機能を有効化することがあり、Workers KVの1分間のキャッシュの関係で、Workers KVが完全に変更を伝播する前に別のリクエストが到着し、最適化されていないアセットをキャッシュすることに。このような状況では、手動でキャッシュを再びクリアしなければならず、好ましくありません。顧客側ではイライラが募り、私たちの方ではAPIの操作とGCP帯域幅を浪費し、常にキャッシュをパージする結果となりました。

キャッシュキーの重要性

常にドメインのWorkers KVデータを読み込んでいたことから、リクエストをルーティングし、ドメインのIDやPolishのようなアセットに影響を与える可能性のある機能などを追加して、キャッシュキーを変更しました。現在のKinstaのキャッシュキーは、パネルやAPIで顧客が加えた変更を素早く反映するため、大幅にカスタマイズされています。Workers KVのデータを利用してキャッシュキーを変更することで、キャッシュのクリアに関する懸念が解消されました。Workers KVが変更を伝えるとすぐにキャッシュキーも更新され、アセットを新たにリクエストしてキャッシュします。

キャッシュキーをカスタマイズする最も簡単な方法は、query paramsを追加すること。以下はその例です。

let cacheKey = `${request.url}?custom-cache-param-polish=lossy`

なお、URLの既存のパラメータを確認して、?または&のどちらのコネクタを使用するかを決定し、一意の識別子を使用してください。

その後、このキャッシュキーを使って、Cache APIまたはFetch(または両方)でレスポンスを保存します。

Workers KVのキャッシュ

Workers KVの操作は比較的容易ですが、毎日何十億もの読み取り操作をトリガーすると、その数はすぐに膨れ上がります。

キャッシュキーのカスタマイズによって、Workers KVデータをCache APIでキャッシュし、読み取り操作を効率化し、訪問者ごとに複数のWorkers KVのGETリクエストを回避することで、待ち時間を短縮することができます。キャッシュされたレスポンスは、リクエストのURLとKVデータの組み合わせに基づいているため、古いコンテンツのキャッシュを心配する必要もありません。

Workers KVデータのキャッシュを含む処理の流れ
Workers KVデータのキャッシュを含む処理の流れ
シナリオ別のTTFB
シナリオ別のTTFB

とは言え、多くのアプリケーションとは異なり、長い期間Workers KVをキャッシュすることはできません。顧客は常に新機能を試し、PolishやAuto Minify機能の設定を変更し、時にページや拡張機能をキャッシュから除外しています。

そこで、Workers KVのデータを「マイクロキャッシュ」することに。動的コンテンツや常に更新されるコンテンツを、60秒未満という短期間でキャッシュします。

Workers KVに独自のキャッシュロジックを実装する方法は、非常にシンプルです。

const handleKVCache = async (event, myCustomDomain) => {
  // まずキャッシュからKVを取得する
  const cache = caches.default;
  let site_data = await cache.match( `https://${myCustomDomain}/some-string-ID-kv-data/` );

  // 有効なKVキャッシュの一致
  if (site_data && site_data.status === 200) {
    // 必要に応じてキャッシュされたデータを修正して返す
    return site_data;
  }

  // 無効なキャッシュ(期限切れ、ミスなど)、KV名前空間からデータを取得する
  site_data = await KV_NAMESPACE.get(myCustomDomain.toLowerCase());
  
  // Cache APIで有効なKV レスポンスをキャッシュする
  if (site_data) {
    let kvResponse = new Response(JSON.stringify(site_data), {status: 200});
    kvResponse.headers.set("Cache-Control", "public, s-maxage=30");
    event.waitUntil(cache.put(`https://${myCustomDomain}/some-string-ID-kv-data/`, kvResponse));
  }
  
  return site_data;
};

FlareUtilsのBetterKVを使用することも可能)

Kinstaでは、Workers KVデータに30秒のキャッシュTTLを実装し、読み取り操作を約80%削減しています。

Workers KVデータのキャッシュに30秒のTTLを実装した後の読み取り操作
Workers KVデータのキャッシュに30秒のTTLを実装した後の読み取り操作

補足

Cloudflare WorkerstとWorkers KVに関する詳しい情報は、Cloudflare Workers KVの開発者向けドキュメント、またはCloudflareのWorkers KV専用サイトをご覧ください。

※この記事はCloudflareの公式サイトに掲載されたものです。

Paulo Paracatu

ウェブホスティングと最適化を得意とするKinstaの熟練DevOpsエンジニア。BashとJavaScriptの専門知識を持ち、Cloudflare Workersでホスティングにおけるユーザー体験を継続的に改善している。