2024のDeveloper Weekは、弊社製品のプロダクションレディの状況に特化してお届けしています。4月1日月曜日、弊社はD1、Queues、Hyperdrive、およびWorkers Analytics Engineがプロダクションレディとなり、一般に利用可能になったことを発表しました。4月2日火曜日には、推論プラットフォームである弊社Workers AIでも同様の発表を行いました。さらに今後も、弊社からの発表が続く予定です。
一方で、プロダクションレディ対応は、構築するサービスのスケールと信頼性にとどまるものではありません。変更を安全かつ確実に行うためのツールも必要になります。Cloudflareが提供するものだけでなく、お客様のアプリケーションのニーズに合わせたCloudflareの挙動を正確に制御および調整できることも大切になります。
本日は、漸進的なデプロイメント、新しいTail Workersでのソースマップスタックトレース、新たなレート制限API、新たなAPI SDK、Durable Objectsのアップデートなど、ミッションクリティカルな本番環境サービスを念頭に置いた構築について5つのアップデートを発表します。弊社は、Workers、Access、R2、KV、Waiting Room、Vectorize、Queues、Streamなど、独自の製品を構築しています。これらの新機能は、弊社自身が本番環境への対応を確実にするに当たり活用しているもので、これを一般開放できるようになったことをうれしく思っています。
WorkersとDurable Objectsに漸次的にデプロイする変更
Workerのデプロイは、ほぼ瞬時で完了します。ほんの数秒で、変更があらゆる場所でライブになります。
本番スケールに到達すると、変更を加えるたびに、量的にも期待値的にもリスクが大きくなります。99.99%のアベイラビリティのSLAを達成する必要があったり、または要求内容が高いP90の遅延のSLOが必要になったりします。トラフィックの100%に対して45秒間ライブになるような質の悪いデプロイでは、何百万ものリクエストが失敗することを意味します。微妙なコード変更であっても、一挙に展開すれば、圧倒されたバックエンドにリトライの大群がどっと押し寄せることになり得ます。これらのリスクは、Workersを基盤とする自社サービスにおいて、弊社自身が対処および軽減しています。
これらのリスクを軽減する方法となるのは、一般にローリングデプロイメントと呼ばれる、変更の段階で来な展開です。
その時点のアプリケーションのバージョンが本番環境で動作を継続。
アプリケーションの新バージョンを本番環境にデプロイするものの、トラフィックのごく一部だけをこの新バージョンにルーティングし、リグレッションやバグを監視しながら、本番環境に「浸透」するのを待つ。もし何か不具合が発生しても、それを早期かつトラフィックのうちに占める割合が小規模(1%など)のうちに把握でき、すぐに元に戻すことが可能。
トラフィックの割合を新バージョンのトラフィックが100%となるまで徐々に増やしていき、その時点で完全にロールアウトします。
本日は、Cloudflare APIまたはWrangler CLI、もしくはWorkersダッシュボードからWorkersとDurable Objectsにコードの変更を徐々にデプロイするファーストクラスの方法を公開します。Gradual Deploymentsは、オープンベータとなります。Workers FreeプランのCloudflareアカウントでGradual Deploymentsを利用でき、まもなくWorkers PaidおよびEnterpriseプランのアカウントでもGradual Deploymentsを利用できるようになります。アカウントがアクセスできるようになると、ダッシュボードにバナーが表示されます。
本番環境でWorkerまたはDurable Objectの2つのバージョンを同時に実行する場合、ほとんどの場合、メトリクス、例外、およびログをバージョン別にフィルタリングできるようにしたいと思うでしょう。これは、新バージョンがトラフィックのごく一部にしかロールアウトされない場合、またはトラフィックを半々に分割した場合のパフォーマンス指標を比較する際、本番環境で発生する問題を早期に発見するのに役立ちます。また、プラットフォーム全体にわたり、バージョンレベルでの可観測性を追加しました。
WorkersダッシュボードおよびGraphQL Analytics APIでは、バージョンによって分析をフィルタリングできます。
Workers Trace EventsとTail Workersイベントには、WorkerのバージョンIDと、オプションのバージョン・メッセージとバージョン・タグ・フィールドが含まれます。
wrangler tailを使用してライブログを表示する場合、特定のバージョンのログを表示できます。
Version Metadataバインディングを設定することで、Workerのコード内からバージョンID、メッセージ、タグにアクセスできます。
また、各クライアントやユーザーがWorkerの一貫したバージョンしか見ないようにしたい場合もあるでしょう。特定の識別子(ユーザー、セッション、または一意のIDなど)に関連付けられたリクエストが、常に一貫したバージョンのWorkerによって処理されるように、Version Affinityを追加しました。Ruleset Engineと一緒に使用すると、Session Affinityは「粘着性」を確保するために使用されるメカニズムと識別子の両方を完全に制御できます。
Gradual Deploymentsは、オープンベータとなります。GAに向け、弊社では次のサポートに取り組んでいます。
バージョンの上書き-本番トラフィックを提供する前にテストするため、Workerの特定のバージョンを起動します。これにより、ブルーグリーンデプロイメントを作成できます。
Cloudflare Pages-Cloudflare PagesのCI/CDシステムに、デプロイを自動的に進行させられるようになります。
自動ロールバック-Workerの新しいバージョンでエラー率が急増した場合、デプロイメントを自動的にロールバックします。
フィードバックをお待ちしています!こちらのフィードバックフォームからご意見をお聞かせいただくか、開発者向けDiscordの#workers-gradual-deployments-betaチャンネルまでご連絡ください。
Tail Workersのソースマップスタックトレース
生産準備とは、エラーや例外を追跡し、それらをゼロにすることを意味します。エラーが発生した際、一般的にはエラーのスタックトレース、つまり、どの関数が、どの順番で、どの行から、どのファイルから、どの引数で呼び出されたかを最初に確認することになります。
ほとんどのJavaScriptコードは、Workers上だけでなくプラットフォーム全体において、本番環境にデプロイされる前にまずバンドルされ、多くの場合トランスパイルされ、そしてミニファイされます。これは、パフォーマンスを最適化するために小さなバンドルを作成し、必要に応じてTypescriptからJavascriptに変換するために、舞台裏で行われます。
例外が/src/index.js:1:342のようなスタックトレースを返すとしたら、関数のミニファイされたコードの342文字目でエラーが発生したことを意味しています。これは、デバッグにはあまり役に立たたないのは明らかです。
ソースマップが、これを解決します。まず、コンパイルされ最小化されたコードを、記述した元のコードにマップします。ソースマップは、JavaScriptランタイムが返すスタックトレースと組み合わされ、人間が読めるスタックトレースを表示します。たとえば、次のスタックトレースは、Workerがdown.tsファイルの30行目で予期しないnull値を受け取ったことを示しています。このように、デバッグのための便利な出発点となるため、スタックトレースを下に移動すればnull値が設定された関数が呼び出されたことが分かります。
仕組みは次の通りです:
Unexpected input value: null
at parseBytes (src/down.ts:30:8)
at down_default (src/down.ts:10:19)
at Object.fetch (src/index.ts:11:12)
wrangler.tomlでupload_source_maps = trueを設定すると、wrangler deployまたはwrangler versions uploadを実行した際、Wranglerが自動的にソースマップファイルを生成してアップロードします。
Workerが捕捉されない例外をスローすると、ソースマップを取得し、それを使って例外のスタックトレースをWorkerの元のソースコードの行にマッピングします。
そして、この難読化されたスタックトレースをリアルタイムログまたはTail Workersで見ることができます。
本日よりオープンベータとして、Workerをデプロイする際にソースマップをCloudflareにアップロードできるようになります。4月15日から、Workersランタイムはソースマップを使用してスタックトレースの難読化を解除します。ドキュメントをお読みになり、さっそくお試しください。4月15日以降、Workersランタイムがソースマップされたスタックトレースを利用し始めます。ソースマップされたスタックとレースが利用可能になった時点で、Cloudflareダッシュボードに通知を掲載し、Cloudflare Developers Xアカウントに投稿します。
新しいレート制限API Workers
APIは、適切なレート制限があって初めて本番稼動が可能になります。そして成長するにつれ、特定の顧客のニーズのバランスを取ったり、サービスの健全性を保護したり、特定のシナリオで制限を実施したり調整したりするために、実施する必要のある制限の複雑さと多様性が増していきます。CloudflareのAPIにはこのような課題があります。Cloudflareの数十の製品それぞれに多くのAPIエンドポイントがあり、それぞれ異なるレート制限を実施する必要があります。
2017年以降、Cloudflareでレート制限ルールを設定できるようになりました。しかし今日まで、ダッシュボードまたはCloudflare APIを介してのみ制御できる状況でした。_ランタイム_中に動作を定義したり、レート制限と直接やりとりするコードをWorkerに書いたりすることはできませんでした。リクエストがWorkerにアクセスする前にレート制限されるかどうかのみしか制御できなかったのです。
本日、オープンベータ版として、Workerからレート制限に直接アクセスできる新しいAPIを発表します。非常に早く、memcachedによって支えらされ、ご利用中のWorkerに非常に簡単に追加できます。例えば、以下は60秒間に100リクエストのレート制限を定義する設定を例示したものです。
次に、Worker内でRATE_LIMITERバインディングのlimitメソッドを呼び出します。上記の設定だと、60秒以内に特定のパスへのリクエストが100回を超えると、このコードはHTTP 429レスポンスステータスコードを返します。
[[unsafe.bindings]]
name = "RATE_LIMITER"
type = "ratelimit"
namespace_id = "1001" # An identifier unique to your Cloudflare account
# Limit: the number of tokens allowed within a given period, in a single Cloudflare location
# Period: the duration of the period, in seconds. Must be either 60 or 10
simple = { limit = 100, period = 60 }
このように、Workers、memcachedのようなデータストアに直接接続できるようになりました。他に、カウンター、ロック、インメモリ・キャッシュなど、実現できるものはあるかと思われるかもしれません。Rate Limitingは、Workerの多くの分離の中でも、今後の提供を検討している多くの初歩的な段階の最初のものとなっています。現在、Workerのグローバルスコープに大きく依存している場合、弊社では特定のユースケースに特化したより良いプリミティブの開発に取り組んでいます。
export default {
async fetch(request, env) {
const { pathname } = new URL(request.url)
const { success } = await env.RATE_LIMITER.limit({ key: pathname })
if (!success) {
return new Response(`429 Failure – rate limit exceeded for ${pathname}`, { status: 429 })
}
return new Response(`Success!`)
}
}
WorkersのRate Limiting APIはオープンベータ化済で、ドキュメントをお読みいただきすぐにご利用いただけます。
CloudflareのAPI用に自動生成された新たなSDK
プロダクションレディ対応とは、ダッシュボードのボタンをクリックして変更を加えることから、TerraformやPulumiなどのインフラストラクチャー・アズ・コード・アプローチを使用したり、独自またはSDK経由でAPIを直接呼び出し、プログラムで変更を加えることを意味します。
Cloudflare APIは大規模のもので、常に新しい機能を追加しています。平均して1日に20~30回APIスキーマを更新しています。一方、これまで弊社のAPI SDKは手作業で構築・保守されてきたため、これを自動化する必要がありました。
そして本日、弊社でこの取り組みが完了し、Typescript、Python、Goの3つの言語で新たなCloudflare API向けクライアントSDKを発表します。
各SDKは、当社の各APIエンドポイントの構造と機能を定義するOpenAPIスキーマに基づき、Stainless APIを使用して自動的に生成されます。つまり、Cloudflare APIに新しい機能が追加されると、どのCloudflare製品においてもこれらのAPI SDKは自動的に再生成され新しいバージョンが発行されるため、正確で最新の状態に保たれます。
以下のいずれかのコマンドを実行し、SDKをインストールできます。
TerraformやPulumiを使う場合、Cloudflare'のTerraform Providerは現在、自動化されていない既存のGo SDKを使っています。terraform applyを実行すると、Cloudflare Terraform ProviderがどのAPIをどの順番で作るかを決定し、Go SDKを使って実行します。
// Typescript
npm install cloudflare
// Python
pip install cloudflare
// Go
go get -u github.com/cloudflare/cloudflare-go/v2
新しく自動生成されたGo SDKは、すべてのCloudflare製品に対して、より包括的なTerraformサポートへの道を開き、最新のAPIの変更に対応した、正確で最新であると信頼できるツールの基本セットを提供します。弊社では、Cloudflareの製品チームがCloudflare APIを介して公開される新機能を構築するたびに、SDKによって自動的にサポートされる未来を描いて構築しています。2024年中の続報にご期待ください。
Durable Objectのネームスペース分析とWebSocketハイバネーションGA
Waiting Room、R2、Queues、そしてPartyKitのなどのプラットフォームを含む多くの弊社製品は、Durable Objects使用して構築しています。新しく追加されたオセアニア向けサポートを含め、グローバルに展開されているDurable Objectsは、一枚岩のWorkersとも言え、単一の調整ポイントを提供するとともに、状態を永続化できます。インタラクティブなチャットや共同編集など、リアルタイムでのユーザー連携を必要とするアプリに最適です。アトラシアンはこれについて、次のように述べています。
弊社で実現した新たな能力として、担当部署がより正式に文書化する前に、ブレーンストーミングや初期計画のような非構造化作業を自由形式で記録できConfluenceホワイトボードが挙げられます。担当部署では、リアルタイムのコラボレーションのために多くの選択肢を検討し、最終的にCloudflareのDurable Objectsの採用を決定しました。Durable Objectsは、インフラストラクチャを大幅に簡素化し、多数のユーザーに簡単に拡張できるユニークな機能性の組み合わせを備えており、この問題領域に見事にフィットすることが証明されました。 - アトラシアン
これまではダッシュボードで関連する分析傾向を公開していなかったため、GraphQL Analytics APIを直接使用しない限り、Durable Objectsネームスペース内の使用パターンやエラー率を理解することは困難でした。Durable Objectsダッシュボードが刷新され、メトリクスをドリルダウンして必要なだけ深く掘り下げることができるようになりました。
Durable Objectsは、初日からWebSocketsをサポートし、多くのクライアントがDurable Objectに直接接続してメッセージを送受信できるようになります。
しかし、時にクライアントアプリケーションはWebSocket接続を開いた後、最終的に何もしなくなることがあります。5時間にわたり、ブラウザーで開いたまま触っていないタブを想像してみてください。メッセージの送受信にWebSocketsを使用している場合、実際には何も使用されていないTCP接続が長時間保たれることになります。この接続がDurable Objectへのものである場合、Durable Objectは実行され続け、何かが起こるのを待たなければならず、メモリを消費し、コストがかかります。
弊社ではこの問題を解決するため、WebSocketハイバネーションを初めて導入し、本日、この機能がベータ版から一般利用可能になったことを発表します。WebSocketハイバネーションでは、ハイバネーション中に使用する自動応答を設定し、状態をシリアライズしてハイバネーションに耐えられるようにします。これによりCloudflareは、クライアントからのオープンなWebSocket接続を維持しながら、Durable Objectをアクティブに実行しないように「ハイバネーション」するために必要なインプットを得ることができます。その結果、実際にステートが必要なときには常にインメモリで利用できるようになり、そうでないときには不必要に保持されなくなります。Durable Objectがハイバネーションしている間は、たとえアクティブなクライアントがその時点でWebSocket経由で接続しているとしても、その間は課金されません。
さらに、Durable ObjectsへのWebSocketメッセージの受信にかかるコストについて、リアルタイム通信のため、より小さくより頻繁なメッセージが好ましいとの開発者からのフィードバックを聞いてきました。本日より、これまでのように1メッセージが1リクエストに相当するのではなく、受信WebSocketメッセージへの課金はリクエストの20分の1相当となります。価格設定の例を以下に示します。
.tg {border-collapse:collapse;border-color:#ccc;border-spacing:0;} .tg td{background-color:#fff;border-color:#ccc;border-style:solid;border-width:1px;color:#333; font-family:Arial, sans-serif;font-size:14px;overflow:hidden;padding:10px 5px;word-break:normal;} .tg th{background-color:#f0f0f0;border-color:#ccc;border-style:solid;border-width:1px;color:#333; font-family:Arial, sans-serif;font-size:14px;font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;} .tg .tg-0lax{text-align:left;vertical-align:top} .tg .tg-4kyp{color:#0E101A;text-align:left;vertical-align:top} .tg .tg-bhdc{color:#0E101A;font-weight:bold;text-align:left;vertical-align:top}
WebSocket Connection Requests | Incoming WebSocket Messages | Billed Requests | Request Billing | |
---|---|---|---|---|
Before | 10K | 432M | 432,010,000 | $64.65 |
After | 10K | 432M | 21,610,000 | $3.09 |
WebSocket接続リクエスト
受信WebSocketメッセージ
課金対象リクエスト
課金リクエスト
使用前
10千
432百万
432,010,000
$64.65
使用後
10千
432百万
21,610,000
$3.09
複雑な本番設定を必要とせず、プロダクションレディ
前世代のクラウドプラットフォームでプロダクションレディになるということは、出荷速度を落とすことを意味しました。つまり、バラバラのツールをつなぎ合わせたり、チーム全体を立ち上げて社内のプラットフォームに取り組ませたりしていました。障害物が立ちはだかるプラットフォームに、独自の生産性レイヤーを後付けしなければならなかったのです。
Cloudflare Developer Platformは成長し、プロダクションレディとなりました。製品が直感的に連動し、同じことをする上で無数の異なる方法を存在させず、連動し合うものを理解するのに役立つ互換性マトリックスが不要な統合プラットフォームであり続けます。アップデートはそれぞれ、Cloudflareの製品やプラットフォームの一部に新機能を統合し、前述の思想を体現しています。
弊社では、お客様に次に求められているものが何かだけではなく、さらにシンプルにできると思う点、もしくは弊社製品がさらに優れた在り方で連携できると思う点について、皆さまからのご意見をお待ちしています。いつでも、Cloudflare Developers Discordにてお知らせください。