1738526718
2025-01-29 09:04:00
同期エンジンとリアルタイム機能の需要の高まりにより、WebSocketsは最新のアプリケーションにとって重要なコンポーネントになりました。 Composeでは、WebSocketsは当社のサービスのバックボーンを形成し、開発者がバックエンドコードのみで低レイテンシーインタラクティブアプリケーションを提供できるようにするバックエンドSDKに電力を供給します。
しかし、スケーリングWebSocketsは、予想よりもはるかに複雑であることが証明されています。以下は、私たちが学んだ最も重要な教訓のいくつかです。
展開を優雅に処理します
-
新しいサーバーをスピンアップします。
-
新しいサーバーが健康になると、古いサーバーが返され始めます
503 Service Unavailable健康チェックへの応答。 -
4連続後
503応答、ロードバランサーはサーバーを不健康に宣言し、プールから古いサーバーを削除します。ロードバランサーの健康は5秒ごとにチェックされるため、このプロセスには最大25秒かかります。 -
古いサーバーは、再接続の急増を避けるために、カスタムWebsocket Closeメッセージクライアントにランダム間隔で再接続を遅らせるように指示するメッセージを指示します。
-
カスタムクローズメッセージを使用すると、クライアントがクライアントが切断される〜10秒の期間中、ユーザーにより正確なメッセージをユーザーに表示できます。
-
ランダムな遅延は、すべてのクライアントが一度に再接続する群れの問題を防ぐのに役立ちます。また、クライアントは、予期しない問題を説明するために、展開関連の再接続の指数関数的なバックオフを2倍にします。
-
ロードバランサーがトラフィックをシフトするのにかかる時間を考慮するために、緊密なメッセージは20秒遅れます。
-
-
すべてのクライアントが切断されると、古いサーバーは完全にシャットダウンします。
レンダリングや鉄道などのマネージドサービスを使用している場合は、展開中にクライアント接続が優雅に転送されることを特に認識する必要があります。
サーバーをシャットダウンする前に、すべての未解決のリクエストが処理されるまで、ゼロダウンタイムの展開を宣伝する多くのマネージドサービスが待機します。 WebSocket接続は永続的であるため、これは、マネージドサービスがプロセスを強制的に終了するまで、展開後数分または数時間、古いサーバーがアクティブになる状況につながる可能性があります。
一貫したメッセージスキーマを確立します
HTTPには組み込みのルーティングコンベンションが付属しています(GET /user、 POST /company、 PUT /settings)、WebSocketsでは、開発者がメッセージを整理するための独自のスキーマを定義する必要があります。
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 30秒ごとにメッセージを送信し、a pong 応答。クライアントが受信しない場合 ping 45秒ごとに、すぐに接続をドロップし、再接続しようとします。同様に、サーバーは逃す接続を閉じます pong 45秒以内の応答。
両端のハートビートを監視することにより、クライアント側のネットワークが機能的に見えるが、サーバーが応答を受信しないまれなケースを検出および処理します。
HTTPフォールバックがあります
SSEはHTTPベースであるため、制限された環境で信頼できる代替品を提供する可能性がはるかに低くなります。加えて、特に短inのソリューションと比較して、依然として遅延が低くなっています。
結論の考え
-
標準ツールの欠如:ほとんどのフレームワークには、レート制限、データ検証、エラー処理用の組み込みツールが含まれていますが、通常、これらの機能をWebSocketsに独自に実装する必要があります。
-
応答をキャッシュできない:Edgeネットワークにより、ユーザーの近くでHTTP応答を簡単にキャッシュできますが、WebSocketsでこれを達成する標準的な方法はありません。
-
認証ごと:処理する前に、各メッセージがそのユーザーに有効であることを確認することにより、虐待から守ります。
しかし、複雑さに関係なく、ユーザーは最新のアプリケーションが高速、リアルタイム、および共同作業であると期待しています。そして、今のところ、WebSocketsほどそれを達成するためのより良い方法はありません。
#スケーリングWebSocketの隠された複雑さ