Edge computing for everyone.

ちょうど1年前の今日、Cloudflareは私にあるミッションを与えました。ユーザーがCloudflareのエッジ環境でコードを実行できるようにすることです。当時、私たちにはそれが何を意味するのかわかりませんでした。コンテナベースになるのか?新しいチューリング完全な領域の固有の言語か?Lua?「Functions」?たくさんのアイデアがありました。

最終的には、今では当たり前のように思える選択に落ち着きました。JavaScriptです。標準的なService Workers APIを使用してV8で構築された新しい環境で実行します。5ヶ月前、私たちは当社が構築しているものをお客様にプレビューで提供し、ベータ版を開始しました。

現在では、Cloudflare Workersは何千ものスクリプトがデプロイされ、何十億ものリクエストが処理されているような、誰でも利用できるものになっています。

「VCLから離れ、Cloudflare Workersを採用することによって、創造的なルーティングができるようになるでしょう。そうすることで、NPMの数百万ユーザーに現在よりももっと高速にJavaScriptを提供できるようになります。 当社の次世代サービスはCloudflareのプラットフォーム上に構築するつもりです。もちろんJavaScriptでです!」

— CJ Silverio, CTO, npm, Inc.

そもそもクラウドとは?

歴史的に見ても、Webアプリケーションのコードは、サーバー側とブラウザ側で分離されてきました。両者の間にはダムネットワークがあり、広大ではあるものの基本的には単にデータを点から点へと渡しているだけです。

これでは、「クラウド」のうたい文句を実現しているとは思えません。

私たちは、クラウドコンピューティングの真の夢は、お客様のコードがネットワーク自体の中に存在することだと考えています。お客様のコードは、「アメリカ西部4州」や「南中央アジア (ムンバイ)」などで実行されるものではなく、あらゆる場所で実行されるのです 。

より具体的に言うと、コードは最も必要とされる場所で実行されるべきです。例えば、ニュージーランドのユーザーに対応する場合、コードはニュージーランドで実行されるべきです。データベースでデータを処理するとき、コードはデータを保存するマシン上で実行されるべきです。サードパーティのAPIとやりとりする場合、コードはそのAPIがホストされている場所で実行されるべきです。人類の探検家が火星に到着したとき、お客様のアプリケーションの応答に30分も待つことに彼らは満足しないでしょう -- お客様のコードは火星で実行されるべきです。

Cloudflare Workerは、このビジョンに対する当社の第一歩です。Workerをデプロイすると、30秒以内に世界中の100以上のロケーションからなるCloudflareのエッジネットワーク全体にデプロイされます。お客様のドメインへの各リクエストは、エンドユーザーに近いCloudflareのロケーションにあるWorkerによって処理され、お客様が個々のロケーションについて考える必要はありません。より多くの場所をオンライン化すればするほど、お客様のコードは「どこでも実行できる」ようになります。

まあ、いいでしょう。火星では実行しません。まだね。イーロンさん、そこにいますか?

Workerとは?

Cloudflare Workersの名前はWeb Workersに由来しており、より具体的には、Webブラウザのバックグラウンドで動作してHTTPリクエストをインターセプトするスクリプトのW3C標準APIであるService Workersに由来しています。Cloudflare Workersは同じ標準APIに対して書かれていますが、ブラウザではなく、Cloudflareのサーバー上で実行されます。

ここでは、そのツールをご紹介します。

  • 最新の標準的な言語機能を使用して、任意のJavaScriptコードを実行する。
  • HTTPリクエストとレスポンスのURL、ステータス、ヘッダー、ボディの内容をインターセプトして変更する。
  • お客様のWorkerからのリクエストに直接対応、または他の場所に転送する。
  • サードパーティのサーバーにHTTPリクエストを送信する。
  • 複数のリクエストをシリアルまたはパラレルで送信し、そのレスポンスを使用して元のリクエストに対する最終的なレスポンスを作成する。
  • レスポンスがすでにクライアントに返された後に非同期のリクエストを送信する(例:ロギングや分析)。
  • キャッシングの動作など、Cloudflareの他の機能を制御する。

Workersの使い方は無限にあり、お客様からどのようなアイデアが出てくるか楽しみです。ここでは、ベータ版で見られたアイデアをいくつか紹介します。

  • 異なるタイプのリクエストを異なるオリジンサーバーにルーティングする。
  • HTMLテンプレートをエッジで展開し、オリジンでの帯域幅の費用を削減する。
  • キャッシュされたコンテンツにアクセス制御を適用する。
  • 一部のユーザーをステージングサーバーにリダイレクトする。
  • 全く異なる2つのバックエンド間でA/Bテストを実施する。
  • Web APIに完全に依存する「サーバーレス」アプリケーションを構築する。
  • カスタムセキュリティフィルターを作成し、アプリに固有の不要なトラフィックをブロックする。
  • キャッシュヒット率を向上させるためにリクエストを書き換える。
  • カスタムの負荷分散とフェイルオーバーロジックを実装する
  • 本番サーバーを更新することなく、アプリケーションに迅速に修正を適用する。
  • ユーザーのブラウザでコードを実行することなく、分析結果を収集する。
  • その他多数

ここで例を紹介します。

// A Worker which:
// 1. Redirects visitors to the home page ("/") to a
//    country-specific page (e.g. "/US/").
// 2. Blocks hotlinks.
// 3. Serves images directly from Google Cloud Storage.
addEventListener('fetch', event => {
  event.respondWith(handle(event.request))
})

async function handle(request) {
  let url = new URL(request.url)
  if (url.pathname == "/") {
    // This is a request for the home page ("/").
    // Redirect to country-specific path.
    // E.g. users in the US will be sent to "/US/".
    let country = request.headers.get("CF-IpCountry")
    url.pathname = "/" + country + "/"
    return Response.redirect(url, 302)

  } else if (url.pathname.startsWith("/images/")) {
    // This is a request for an image (under "/images").
    // First, block third-party referrers to discourage
    // hotlinking.
    let referer = request.headers.get("Referer")
    if (referer &&
        new URL(referer).hostname != url.hostname) {
      return new Response(
          "Hotlinking not allowed.",
          { status: 403 })
    }

    // Hotlink check passed. Serve the image directly
    // from Google Cloud Storage, to save serving
    // costs. The image will be cached at Cloudflare's
    // edge according to its Cache-Control header.
    url.hostname = "example-bucket.storage.googleapis.com"
    return fetch(url, request)
  } else {
    // Regular request. Forward to origin server.
    return fetch(request)
  }
}

本当に高速

時々、ユーザーからJavaScriptは「遅い」という声を聞きます。これほど事実とかけ離れたことはないでしょう。

Workersは、GoogleがChrome用に開発したV8 JavaScriptエンジンを使用しています。V8はJavaScriptの最も高速な実装の1つであるだけでなく、動的型付けの言語の最も高速な実装の1つでもあります。V8の最適化には膨大な作業が費やされているため、C/C++、Rust、Goを除く、一般的なサーバープログラミング言語を凌駕しています。(ちなみに、これらの言語はWebAssemblyによって近々サポートされる予定です)。

結論として、典型的なWorkerスクリプトは1ミリ秒以下で実行されます。 ほとんどのユーザーはWorkerを有効にしても遅延の差を測定することはできません。もちろん、Workerが実際にエッジ環境から直接応答することで遅延を改善する場合は例外です。

もう一つ、スピードに関して言うと、Workerのデプロイも高速です。Workerはスクリプトを保存して有効にしてから30秒以内にグローバルにデプロイされます。

料金設定

Workersは、Cloudflareの有料アドオンです。価格はできるだけシンプルにしたかったので、以下のようにしました。

$0.50 per million requests, with a $5 monthly minimum (covers your first 10 million requests)

開始する

「Cloudflare Workersのおかげで非常に時間を節約できています。 Workersなしでボットトラフィックを管理しようとすると、別の有意義な目的に利用できるはずの貴重な開発リソースやサーバーリソースを浪費してしまいます。」

— MaxMind社、シニアシステムアドミニストレーター、John Thompson氏