リアルタイムチャットの処理を Azure 上でどう閉じるか ― SignalChat を例に
リアルタイム処理を触っていると、どの層で処理が完結しているのかが気になってくる。特にメッセージ送受信まわりは複数の処理が重なり、流れの粒度がつかみにくい。構成を変えながら挙動を追ってみると、クライアント側に秘密情報を置いた瞬間に流れが不安定になることが分かった。接続キーや署名が端末に残るだけで、全体の動きがざらつく。
そこで、チャット・認証・ストレージを小さなバックエンドに寄せ、Managed Identity 経由で Azure の各サービスに渡す構成を試した。すると、処理の境界が自然に揃い、役割が終わる場所が明確になる。スケール時の負荷の散り方も読みやすく、クライアント側に何も残らないため流れが一本にまとまる。SignalR の接続も挙動が素直で、スケールアウト時の再接続は一定のパターンで起きる。Hub にロジックを寄せすぎると詰まりやすいため、配信専用にして API 層で前処理を終わらせる構成が安定した。Hub をステートレスに保つことで、後から構成を変えた際の揺れも小さくなる。
Cosmos DB はパーティション設計の影響が大きく、チャットルーム単位で切ると RU の揺れが抑えられる。ユーザー単位にするとホットパーティションが発生しやすく、スパイク時に RU が跳ねる。負荷をかけて比較すると、この差ははっきり出た。画像や動画は Blob に投げるだけで流れが途切れず、Content Safety の判定も安定していた。同期で挟むとレイテンシが跳ねるため、軽い同期判定と重い非同期判定を分ける構成が最もスムーズだった。大きいファイルはクライアント直送にすると負荷が偏るが、SAS を直接渡すのは危険なので、Managed Identity で一時トークンを発行する方式が扱いやすい。
いろいろ試していく中で、リアルタイム処理の安定性は “秘密情報の置き場所” と “処理をどこで閉じるか” の設計で大きく変わることが分かった。最終的には、バックエンドに責務を寄せて Managed Identity を中心に流れをまとめる構成が、一番落ち着いた動きをしていた。

