クラウドとインフラ

Cloudflare HyperdriveにおけるMySQLキャッシュ障害:機能不一致が原因

Cloudflareは、HyperdriveのMySQLサポートにおいて、ノード間のプロトコル機能不一致により共有CDNキャッシュが空の結果を返すという稀なバグを修正しました。

Illustration of data flowing through a filtered network connection
この記事用に生成されたイラスト

英語の原文から自動翻訳されました。

Cloudflareは、Workers向けデータベース接続プールツールであるHyperdriveのMySQLサポートについて、一般提供(GA)を開始したと発表しました。このリリースは、ベータ期間中にエンジニアが特定し解決した、時折クエリの応答が空になる微妙なキャッシュバグへの対応を経て行われました。この修正により、MySQLワークロードに対する99.99%の可用性目標を達成できることが保証されました。

何が起きたか

Hyperdriveは当初Postgresサポートで開始され、サーバーレスのWorkersが温かいデータベース接続を共有し、クエリ結果をグローバルにキャッシュできるようにしました。昨年MySQLサポートがベータ段階に入った際、チームはPostgres実装と同レベルの信頼性を目指していました。このテストフェーズ中、高ボリュームの顧客から、期待されるデータではなく空の結果を返す一貫性のある、しかし稀なエラー率についての報告がありました。この問題は約0.001%のリクエストで発生しており、再現や追跡が困難でした。

調査の結果、問題はキャッシュを有効にしたHyperdriveインスタンスに特有であることが判明しました。エンジニアは、問題がHyperdriveによるMySQLクライアント/サーバープロトコルの処理方法、特に機能ネゴシエーションに関連していることを突き止めました。Postgresとは異なり、MySQLは結果セットのフォーマットと終了方法を決定するために機能フラグを使用します。Workerのドライバーが期待するものと、Hyperdriveがキャッシュしたものの間に不一致が生じ、ノード間でキャッシュを共有する際に、破損または読み取り不能な応答が発生していました。

一般提供に至るまで、チームは文字セットエンコーディングや接続リセット動作の修正を含む20件のバグ修正を実装しました。最も重要な修正は、すべての保存されたクエリ結果が正規形式(canonical format)を使用するようにキャッシュロジックを確保することでした。これらの変更がデプロイされると、空の応答エラーは消え、サービスは信頼性の目標を達成しました。

仕組み

Hyperdriveは、ClientノードとEndpointノードからなる分割アーキテクチャを使用しています。ClientはWorkerの近くに配置され、ローカルリクエストとキャッシュを処理し、Endpointは元のデータベースに近い場所に配置され、接続プールを管理します。両方のノードは、ローカルのCloudflare CDNキャッシュを利用します。ClientとEndpointが同じデータセンターにある場合、データベースにアクセスせずに繰り返しクエリを提供することでパフォーマンスを向上させるため、このキャッシュを共有します。

MySQLプロトコルは、接続フェーズ中の機能ネゴシエーションに依存しています。主要な機能の一つにCLIENT_DEPRECATE_EOFがあり、これは結果セットの終了方法を変更します。この機能がネゴシエートされると、モダンなサーバーは列定義後のEOFパケットを省略し、最後のEOFをOKパケットに置き換えます。しかし、Node.js用のmysql2など、一部のクライアントライブラリはこのフラグをサポートしていません。Hyperdriveは、元のサーバーのフォーマットとWorkerが期待するフォーマットの間で応答を変換する必要があります。

バグは、キャッシュ層がWorkerに送信された正確なバイト列を保存できると仮定していたために発生しました。EndpointがHyperdriveの内部機能を使用して応答をキャッシュした場合、Clientがそれを取得し、異なるフォーマットを期待するWorkerに生のバイト列を送信すると、Workerはデータを誤解釈します。逆に、Clientが変換済みのバイト列をキャッシュした場合、Endpointがそれを取得しても正しく処理できない可能性があります。修正により、共有キャッシュに書き込まれるのは、Hyperdriveの機能でエンコードされた応答の正規バージョンのみであることが保証されます。

主な詳細

  • Hyperdrive for MySQLはベータ版から卒業し、現在一般提供されています。
  • サービスは、Workersからのクライアント接続に対して99.99%の可用性を目標としています。
  • 稀なバグにより、キャッシュされたクエリの0.001%が空の結果を返すか、ハングアップしていました。
  • この問題は、CLIENT_DEPRECATE_EOF機能の取り扱いの不一致に起因していました。
  • バグの修正には、共有CDNキャッシュでの正規バイトエンコーディングの確保が必要でした。
  • 追加の修正では、utf8mb4エンコーディングとCOM_RESET_CONNECTIONの状態リセットに対応しました。

なぜ重要なのか

サーバーレスプラットフォーム上で開発を行う開発者にとって、データベース接続管理は継続的な課題です。すべてのリクエストに対して新しい接続を確立することは、大きな遅延を追加し、リソースを消費します。Hyperdriveのような接続プールツールは、接続を温かい状態に保つことでこれを緩和しますが、プロトコル変換における複雑さを導入します。これらのツールがワイヤープロトコルをどのように処理するかを理解することは、異なるクライアントライブラリやデータベースバージョンを混在させた際に生じる不明瞭な問題をデバッグするのに役立ちます。

このインシデントは、異なるデータベースシステム間でのプロトコルの均一性を前提とすることのリスクを浮き彫りにします。PostgresとMySQLの両方がSQLを使用していますが、その基盤となるネットワークプロトコルは大きく異なります。マルチプロトコルインフラストラクチャと統合するエンジニアは、キャッシュ層が非同期化を防ぐためにデータフォーマットを正規化する必要がある可能性があることを認識しておく必要があります。これらのニュアンスを無視すると、ローカル開発環境で再現することが難しい断続的な障害につながる可能性があります。

さらに、分散システムにおける共有キャッシュへの依存は、厳格な整合性保証を必要とします。複数のコンポーネントが同じキャッシュに対して読み書きを行う場合、それらはデータスキーマについて合意していなければなりません。今回のケースでは、正規形式が存在しなかったため、キャッシュはパフォーマンス向上ではなく、破損の原因となりました。この教訓は、プロトコル変換のために中間キャッシュを使用するあらゆるシステムに広く適用できます。

推奨事項

  • 安定性修正の恩恵を受けるため、Hyperdrive for MySQLの一般提供版にアップグレードしてください。
  • 絵文字や特殊文字に関する文字エンコーディングの問題を避けるため、使用しているMySQLクライアントライブラリがutf8mb4をサポートしていることを確認してください。
  • アプリケーション内で結果セットがどのように終了されているかを理解するため、クライアントドライバーがCLIENT_DEPRECATE_EOFをサポートしているかどうかを確認してください。
  • カスタムまたは古いMySQLドライバーを使用している場合は、断続的な空のクエリ結果についてアプリケーションを監視してください。
  • PlanetScaleなどのMySQL互換データベース用に新しいHyperdriveインスタンスを作成するために、wrangler CLIを使用してください。
  • リソースプールの状態がリセットされる際の挙動を確認するため、接続リセットの設定を見直してください。

Bytechapストアのツール

続きを読む

クラウドとインフラ

Cloudflare、レプリケーションの遅延と早期集約によりデータパイプラインのトラフィックを削減

Cloudflareは、サンプリング、レプリケーション、および集約処理をデータパイプラインのより上流側へ移行することで広域ネットワーク(WAN)トラフィックを削減し、ハードウェア拡張を数年分先送りすることに成功しました。

すべての記事