Socket.IOをスケールアウトする時のELBでの問題点
Socket.IOはv1.0以降はpollingからwebsocketにアップグレードする方式になったのですが、ELBを経由させると以下の問題点があります。
- ELBのhttpモードではそもそもwebsocketが使えないためpollingのみになってしまう。
- ELBのtcpモードではstickyセッションの機能が使えないためアップグレード時に別サーバーにリクエストが振られてしまいweboskcetにアップグレードできない。
これではどの設定でもwebsocketを使用することができません。従ってELBではなくstickyセッションが使えるNginxが使用されることがあります。
実現するだけならNginxでもいいのですが、ELBはサーバーの追加が楽で、ヘルスチェックも自動で行ってくれるなど非常に便利なので使いたいところです。
Socket.IOサーバーをELBでスケールアウトする方法
websocketで直接
上記問題点の解決方法ですが、要はtcpモードでアップグレードを挟まなければよいのでいきなりwebsocketで接続すればいいのです。
Socket.IOのコンセプトとしてどんなブラウザでもリアルタイムな通信を実現するというコンセプトのためpollingとwebsocketの2つの接続方式が採用されています。
スマホアプリの場合
スマホアプリであればwebsocketの使えないブラウザを考慮しなくていいのでpollingからアップグレードせずに最初からwebsocketで接続するようにすれば上記2つの問題は解決します。
以上の方法であればELB配下にEC2をいくつでも配置できるようになります。次の問題として別サーバー間でのデータ共有をどうやるかがあります。
Redis Pub/Subを使ったデータ共有とスケールアウト
上記の方法だけでは、別サーバーに接続したクライアント同士は接続情報の共有ができません。その解決方法としてRedisのPub/Subを使います。RedisはElastiCacheを使うのがいいかと思います。
また、Socket.IOにはroomという同じ部屋番号に接続していればデータを共有できる機能があります。websocketの負荷分散を行う場合は下記構成のようにroomの奇数番号が左側のELB、偶数番号が右側のELB経由で接続するようにすれば楽に行うことができます。
どのELB経由で接続するかは事前にアプリケーションサーバーから取得できるようにするといいかと思います。

まとめ
- ELBをtcpモードに設定し、アップグレードをせずに最初からweboskcetで接続しに行く
- データの共有はRedisのPub/Subで行う
- スケールアウトはELBとRedisのセットを増やす
今回はネイティブのスマホゲームに特化するのでブラウザを気にしない解決策を説明しました。現在、スマホアプリでゲームを作る場合Unityが主流となっています。UnityのHTTPクライアントでbestHTTPというライブラリがSocket.IOに対応しているのでオススメです。
最後に、Socket.IO関連の記事を他にも書いているので是非読んでください。
おすすめ本
AWS初心者の方には下記の入門書がすごくわかりやすいのでおすすめです。
髙妻智一
最新記事 by 髙妻智一 (全て見る)
- Polkadot(Substrate)のアドレスとトランザクションについて - 2023-03-09
- 【無料公開】「Goで始めるBitcoin」3章 Bitcoinノードとの通信 技術書典8 - 2020-03-08
- エンジニアがゼロから技術ブログを書くための方法をまとめました - 2019-05-25
コメントを残す