日本語版
最新ニュース
科学&テクノロジー

スケーリングWebSocketの隠された複雑さ

同期エンジンとリアルタイム機能の需要の高まりにより、WebSocketsは最新のアプリケーションにとって重要なコンポーネントになりました。 Composeでは、WebSocketsは当社のサービスのバックボーンを形成し、開発者がバックエンドコードのみで低レイテンシーインタラクティブアプリケーションを提供できるようにするバックエンドSDKに電力を供給します。しかし、スケーリングWebSocketsは、予想よりもはるかに複雑であることが証明されています。以下は、私たちが学んだ最も重要な教訓のいくつかです。展開を優雅に処理しますユーザーは展開が発生したときに気付かないでください。そのため、WebSocket接続は展開全体で持続する必要があります。これは繊細なプロセスであり、予期しない問題に対処するために堅牢な再接続ロジックが必要です。 Composeでは、これらの手順に従うことで、ゼロ近くのダウンタイムを達成します。新しいサーバーをスピンアップします。新しいサーバーが健康になると、古いサーバーが返され始めます 503 Service Unavailable 健康チェックへの応答。4連続後 503 応答、ロードバランサーはサーバーを不健康に宣言し、プールから古いサーバーを削除します。ロードバランサーの健康は5秒ごとにチェックされるため、このプロセスには最大25秒かかります。古いサーバーは、再接続の急増を避けるために、カスタムWebsocket Closeメッセージクライアントにランダム間隔で再接続を遅らせるように指示するメッセージを指示します。カスタムクローズメッセージを使用すると、クライアントがクライアントが切断される〜10秒の期間中、ユーザーにより正確なメッセージをユーザーに表示できます。ランダムな遅延は、すべてのクライアントが一度に再接続する群れの問題を防ぐのに役立ちます。また、クライアントは、予期しない問題を説明するために、展開関連の再接続の指数関数的なバックオフを2倍にします。ロードバランサーがトラフィックをシフトするのにかかる時間を考慮するために、緊密なメッセージは20秒遅れます。すべてのクライアントが切断されると、古いサーバーは完全にシャットダウンします。レンダリングや鉄道などのマネージドサービスを使用している場合は、展開中にクライアント接続が優雅に転送されることを特に認識する必要があります。サーバーをシャットダウンする前に、すべての未解決のリクエストが処理されるまで、ゼロダウンタイムの展開を宣伝する多くのマネージドサービスが待機します。 WebSocket接続は永続的であるため、これは、マネージドサービスがプロセスを強制的に終了するまで、展開後数分または数時間、古いサーバーがアクティブになる状況につながる可能性があります。一貫したメッセージスキーマを確立しますHTTPには組み込みのルーティングコンベンションが付属しています(GET /user、 POST /company、 PUT /settings)、WebSocketsでは、開発者がメッセージを整理するための独自のスキーマを定義する必要があります。Composeでは、すべてのWebSocketメッセージは固定2バイトから始まります type メッセージを分類するためのプレフィックス。スペース効率の良い(2バイトのみ)、65,536種類のタイプにスケーリングしています。クライアントは確実にスライスできます type プレフィックスは常に2バイトであるため、残りのデータに影響を与えることなくメッセージからプレフィックスがあります。メッセージタイプをバージョンすることにより、APIをアップグレードする簡単な方法が提供されます。 const MESSAGE_TYPE_TO_HEADER = { RENDER_UI: "aa", UPDATE_UI: "ab", SHOW_LOADING: "ac", RENDER_UI_V2: "ad", }さらに、デリミターを使用して、メッセージ内部の異なるフィールドを分離します。これは、Encode/Decodeがより速く、JSONよりもメモリ効率が高くなります。 const DELIMITER = "|"; function…

スケーリングWebSocketの隠された複雑さ

1738526718
2025-01-29 09:04:00

同期エンジンとリアルタイム機能の需要の高まりにより、WebSocketsは最新のアプリケーションにとって重要なコンポーネントになりました。 Composeでは、WebSocketsは当社のサービスのバックボーンを形成し、開発者がバックエンドコードのみで低レイテンシーインタラクティブアプリケーションを提供できるようにするバックエンドSDKに電力を供給します。

しかし、スケーリングWebSocketsは、予想よりもはるかに複雑であることが証明されています。以下は、私たちが学んだ最も重要な教訓のいくつかです。

展開を優雅に処理します

ユーザーは展開が発生したときに気付かないでください。そのため、WebSocket接続は展開全体で持続する必要があります。これは繊細なプロセスであり、予期しない問題に対処するために堅牢な再接続ロジックが必要です。 Composeでは、これらの手順に従うことで、ゼロ近くのダウンタイムを達成します。

  1. 新しいサーバーをスピンアップします。

  2. 新しいサーバーが健康になると、古いサーバーが返され始めます 503 Service Unavailable 健康チェックへの応答。

  3. 4連続後 503 応答、ロードバランサーはサーバーを不健康に宣言し、プールから古いサーバーを削除します。ロードバランサーの健康は5秒ごとにチェックされるため、このプロセスには最大25秒かかります。

  4. 古いサーバーは、再接続の急増を避けるために、カスタムWebsocket Closeメッセージクライアントにランダム間隔で再接続を遅らせるように指示するメッセージを指示します。

    • カスタムクローズメッセージを使用すると、クライアントがクライアントが切断される〜10秒の期間中、ユーザーにより正確なメッセージをユーザーに表示できます。

    • ランダムな遅延は、すべてのクライアントが一度に再接続する群れの問題を防ぐのに役立ちます。また、クライアントは、予期しない問題を説明するために、展開関連の再接続の指数関数的なバックオフを2倍にします。

    • ロードバランサーがトラフィックをシフトするのにかかる時間を考慮するために、緊密なメッセージは20秒遅れます。

  5. すべてのクライアントが切断されると、古いサーバーは完全にシャットダウンします。

レンダリングや鉄道などのマネージドサービスを使用している場合は、展開中にクライアント接続が優雅に転送されることを特に認識する必要があります。

サーバーをシャットダウンする前に、すべての未解決のリクエストが処理されるまで、ゼロダウンタイムの展開を宣伝する多くのマネージドサービスが待機します。 WebSocket接続は永続的であるため、これは、マネージドサービスがプロセスを強制的に終了するまで、展開後数分または数時間、古いサーバーがアクティブになる状況につながる可能性があります。

一貫したメッセージスキーマを確立します

HTTPには組み込みのルーティングコンベンションが付属しています(GET /user POST /company PUT /settings)、WebSocketsでは、開発者がメッセージを整理するための独自のスキーマを定義する必要があります。

Composeでは、すべてのWebSocketメッセージは固定2バイトから始まります type メッセージを分類するためのプレフィックス。

  • スペース効率の良い(2バイトのみ)、65,536種類のタイプにスケーリングしています。

  • クライアントは確実にスライスできます type プレフィックスは常に2バイトであるため、残りのデータに影響を与えることなくメッセージからプレフィックスがあります。

  • メッセージタイプをバージョンすることにより、APIをアップグレードする簡単な方法が提供されます。

const MESSAGE_TYPE_TO_HEADER = {
  RENDER_UI: "aa",
  UPDATE_UI: "ab",
  SHOW_LOADING: "ac",
  RENDER_UI_V2: "ad",
  
}

さらに、デリミターを使用して、メッセージ内部の異なるフィールドを分離します。これは、Encode/Decodeがより速く、JSONよりもメモリ効率が高くなります。

const DELIMITER = "|";

function createDelimitedMessage(type: string, args: any[]) {
  return [MESSAGE_TYPE_TO_HEADER[type], ...args].join(DELIMITER);
}

function parseDelimitedMessage(message: string) {
  const [type, ...args] = message.split(DELIMITER);
  return { type, args };
}

バックエンドとフロントエンドがTypeScriptで記述されていることが幸運であり、2つの間でメッセージスキーマを共有し、どちらも同期しないようにすることができます。

心拍でサイレント切断を検出します

接続は、aをトリガーせずに予期せずにドロップする可能性があります 閉じるイベント、クライアントが接続していると思う状況につながりますが、実際にはそうではありません。古い接続を防ぐために、堅牢なハートビートメカニズムを実装することが不可欠です。
定期的に送信します ping/pongメッセージ クライアントとサーバーの間で、ハートビートが何らかの間隔で受信されない場合に再接続します。

サーバーはaを送信します ping 30秒ごとにメッセージを送信し、a pong 応答。クライアントが受信しない場合 ping 45秒ごとに、すぐに接続をドロップし、再接続しようとします。同様に、サーバーは逃す接続を閉じます pong 45秒以内の応答。

両端のハートビートを監視することにより、クライアント側のネットワークが機能的に見えるが、サーバーが応答を受信しないまれなケースを検出および処理します。

HTTPフォールバックがあります

特に制限的なパブリックネットワークでは、WebSocket接続を予期せずブロックできます。そのような問題を軽減するために、使用を構成します サーバーセントイベント(SSE) 更新を受信するためのフォールバックとして、HTTPはクライアント間通信を処理します。

SSEはHTTPベースであるため、制限された環境で信頼できる代替品を提供する可能性がはるかに低くなります。加えて、特に短inのソリューションと比較して、依然として遅延が低くなっています。

結論の考え

ここではカバーしなかったWebSocketをスケーリングすることには、さらに多くのことがあります。例えば:

  • 標準ツールの欠如:ほとんどのフレームワークには、レート制限、データ検証、エラー処理用の組み込みツールが含まれていますが、通常、これらの機能をWebSocketsに独自に実装する必要があります。

  • 応答をキャッシュできない:Edgeネットワークにより、ユーザーの近くでHTTP応答を簡単にキャッシュできますが、WebSocketsでこれを達成する標準的な方法はありません。

  • 認証ごと:処理する前に、各メッセージがそのユーザーに有効であることを確認することにより、虐待から守ります。

しかし、複雑さに関係なく、ユーザーは最新のアプリケーションが高速、リアルタイム、および共同作業であると期待しています。そして、今のところ、WebSocketsほどそれを達成するためのより良い方法はありません。

Composeでは、WebSocketsは、データベースからメインUIスレッドまで、プラットフォーム全体に電力を供給します。 SDKを介して、開発者はバックエンドロジックから完全なWebアプリを生成できます。これらのアプリが速くて大規模なパフォーマンスがあることを確認するには、WebSocketが必要です。あなたがもっと学ぶことに興味があるなら、 ドキュメントをご覧ください。 SDKをインストールして最初のアプリを構築するのに5分もかかりません。

#スケーリングWebSocketの隠された複雑さ

執筆者について: nipponese

Nipponese News編集部は、国内外のニュースを日本語で分かりやすくお届けします。