
2026/03/10 17:41
Cloudflare で FFmpeg をオフロードする
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Summary
チームは、FFmpeg ベースの音声処理を共有 Fly.io インスタンスから Cloudflare のサーバーレス スタックへ移行し、CPU ボトルネックを排除して Kent Cdodds のポッドキャストアップロードの信頼性を向上させました。
- 重要性: 3 月 6 日のエピソードが主要マシンの CPU を 400–500 % に逼迫させ、スロットリングと共有インスタンスからパフォーマンス‑CPU Fly.io インスタンスへの緊急アップグレードを招きました。
- 変更点: エピソードは現在、ドラフト ID と R2 キーでキューに入れられ → Cloudflare Queue → Worker → コンテナが R2 から音声を取得し FFmpeg を実行、結果を再び R2 にアップロードし署名付きコールバックを投稿します。アプリはエンキュー後すぐにレスポンスを返し、トランスクリプション/メタデータ処理はコールバック後に主要サーバーで実行されます。
- 技術詳細:
- Queue worker は
でメッセージを確認し、FFmpeg を非同期で起動して本当のキュー利点を回復します。202 Accepted - コンテナは短い
、ハートビート ping、および「終了」シグナルを使用してアイドルインスタンスを迅速に停止させます。sleepAfter - 失敗時にローカルで FFmpeg を実行していたフォールバックパスは削除され、アプリはエンキュー失敗時に例外を投げて隠れた障害を防止します。
- Queue worker は
- 影響: 移行後の CPU 使用率は約 60–80 % に保たれ、ピーク負荷は約 85 % 削減されスロットリングは発生しません。 Cloudflare のコストモデル(操作ごとの Queue コスト、アクティブ時のみの Container コスト)は専用 Fly.io パフォーマンス‑1x マシン($31/月)よりも安価です。
- 今後の作業: トランスクリプションとメタデータ抽出を Cloudflare キューパイプラインに移動し、重いジョブをコアアプリから完全に分離することを検討します。
ユーザーはより滑らかで高速なエピソードアップロード体験ができ、開発者は音声集約ワークロードのスケールとインフラコスト削減の実証済み戦略を手に入れます。
本文
Call Kent Podcast – FFmpeg をプライマリサーバーから外す
226話目まで、私は
kentcdodds.com をホストしている Fly.io のインスタンス上で
FFmpeg をインライン実行していました。パイプラインはシンプルで問題なく動作していたのですが、2026年3月6日に 超長時間放送が発生し、アプリが極端な CPU スロット化に陥りました。
- ロード平均が 400–500 % に急上昇(FFmpeg 実行全体で)。
- マシンの CPU クォータ残量はスロットされており、割り当て済みバジェットを 消費したため scheduler が抑制しました。
- サイトは劣化し、共有 CPU からパフォーマンス CPU にインスタンスをアップグレードせざるを得ませんでした。
この事象により、プライマリマシンで FFmpeg を走らせることができなくなりました。
まずインラインで FFmpeg を実行するのは悪い考えではない理由
- 単純さ – エピソードごとにジョブを一つ、キュー構造は不要。
- 安全性 – 私だけがトリガーし、アプリサーバーは既に Web トラフィック用に 適切なサイズであったため、FFmpeg はその容量を利用したのみ。
- 競合なし – 音声長や CPU クォータが上限を超えるまで。
エピソードが十分に長くなると、共有 CPU クォータはプライマリインスタンス で応答性が求められる書き込み操作と衝突します。レプリカは読み取り専用で FFmpeg を走らせることができず、唯一実行可能なのはプライマリでした – しかしそれこそ最悪の場所です。
新しいアーキテクチャ
解決策は FFmpeg 作業をすべて Cloudflare にオフロードすることです。
[Call Kent 提出] → Cloudflare Queue にジョブ(draft ID + R2 キー)を enqueue ↓ Cloudflare Worker がキューを消費し、Cloudflare Container へ転送 ↓ Container が R2 から音声を取得し FFmpeg パイプライン実行、 処理済み音声を R2 にアップロード、署名付きコールバックをアプリに POST
- アプリは即座にレスポンスを返し、FFmpeg のブロッキングがありません。
- 署名付きコールバックで draft 状態を更新します:
。GENERATING_AUDIO → TRANSCRIBING → GENERATING_METADATA → DONE - 管理 UI に段階的進捗ラベルが表示されます。
文字起こしとメタデータ生成はまだプライマリサーバーで実行しており、 キュー化は将来の作業です。FFmpeg の即時課題は分離によって解決されました。
コア enqueue 呼び出し(アプリ側)
// app/utils/call-kent-audio-processor.server.ts const res = await fetch( `${env.CALL_KENT_AUDIO_CF_API_BASE_URL}/accounts/${env.CLOUDFLARE_ACCOUNT_ID}/queues/${queueId}/messages`, { method: 'POST', headers: { Authorization: `Bearer ${env.CLOUDFLARE_API_TOKEN}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ content_type: 'json', body: { draftId, callAudioKey, responseAudioKey }, }), signal: AbortSignal.timeout(10_000), } );
署名付きコールバックルート(アプリ側)
// app/routes/resources/calls/episode-audio-callback.ts const signature = request.headers.get('X-Signature'); if (!verifyCallKentAudioProcessorCallbackSignature(signature, rawBody)) { return new Response('Invalid signature', { status: 401 }); } const event = parseCallKentAudioProcessorEvent(rawBody); await handleCallKentAudioProcessorEvent(event); return Response.json({ ok: true });
署名は HMAC‑SHA256 を用い、タイミング安全な比較で検証します。
パフォーマンスへの影響
オフロード後:
- ロード平均が 60–80 % までに抑えられました(400–500 % から)。
- CPU スロットイベントはなく、メモリも安定。
- プライマリマシンはジョブ全体を通じて健康状態を保ちました。
これはエピソード処理中のアプリサーバーにおけるピーク負荷が 約 85 % 低減したことを意味します。
コスト比較
| サービス | 価格メモ |
|---|---|
| Fly.io performance‑1x | 約 $31/月 + ストレージ/出口。自動停止でコストは削減されますが、ライフサイクル管理とコールドスタートが必要です。 |
| Cloudflare Queues | 1 メッセージあたり 3 操作(書き込み・読み取り・削除)。個人ポッドキャスト向けに無料で、月間 1 M オペレーションは含まれます。 |
| Cloudflare Containers | CPU 時間・メモリ・ディスク使用量で課金。Standard‑1 インスタンス(約 ½ vCPU, 4 GiB)+ Worker と Durable Object の追加料金。アイドル時はスケールダウンしてゼロになります。 |
| Workers / Durable Objects | 小規模課金。ハートビート/停止ロジックに便利です。 |
ポッドキャストが月に数話程度の場合、Cloudflare は低頻度の ワークロードに対しゼロまでスケールダウンできるため、コンテナは 実際に転送・処理中のみ課金されます。専用 Fly.io マシンを使用するより もコスト効率が高くなります。
変更点・改善点
- ローカルフォールバック – コンテナ失敗時にローカルで FFmpeg を実行していたものを削除。障害を隠さないようにしました。
- コンテナライフサイクル –
の代わりに Worker / Durable Object から送られるハートビートと、明示的な “finished” 信号でアイドル時に即座に停止します。sleepAfter - キューワーカーのブロッキング削除 – 今は
を即時返し、FFmpeg はバックグラウンドで実行されます。ワーカーがジョブ全期間をブロックすることはありません。202 Accepted
まとめ
- シンプルに始める。現実が要求すればキューへ移行します。
- 運用上の分離(重い計算をプライマリサーバーから切り離す)は、わずかなコスト節約よりも優先されます。
- Cloudflare Queues/Containers は低頻度で高負荷なタスク(ポッドキャスト転送など)に対し、 ゼロアイドルスケールモデルを提供します。
完全実装を見るには、公開リポジトリ
kentcdodds.com の PR #720 をご確認ください。質問があればいつでもお問い合わせください!