前回の続き。
前回の大切な前提として、
pub/subはなし(つまり、メモリ内で処理を完結可能)
というのがありました。
実際に対戦ゲームの作成を通して、処理フローを整理しましょう。
別に面白いものを作る必要はないので、
簡単なゲームとして、以下のような仕様とします。
- 2人対戦の神経衰弱
- ゲームの種別として、4×4、4×8、4×12の3種類(使用枚数が16枚、32名、48枚)
- ユーザはマッチング時に、ゲーム種別を選択可能
- マッチングが成立したらゲーム開始
- ゲーム中に離脱した場合、その時点で残っている人の勝利
- 離脱者なしにゲームが終わった場合、自分の取得枚数が多ければ勝利で、少なければ敗北
pub/subはないので、
スケールアウトの手段が現状皆無です。
そこで、URLを絡めて、効果的にスケールアウトができるようにしておきましょう。
URLはこんな感じです。
【マッチング】 /ws/matching/${type}
${type}とは、上記の4×4などをコード化したもの
【対戦】 /ws/round/${pairId}
${pairId}とは対戦者同士を結びつける一意のキーで、形式は0-9a-zの繰り返し
こんな感じでURLを設計しておくことで、
websocketのリバースプロキシ可能なサーバ(nginxやapache2.4など)で、
URLに応じた振り分けが可能となります。
この設計方式だと、マッチングが成立したら、
一旦マッチングサーバとの接続を閉じて、
新たに対戦サーバと接続する必要があります。
※nginxの設定例
vim /etc/nginx/websocket_params
proxy_read_timeout 300; proxy_connect_timeout 300; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Document-URI $document_uri; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade";
vim /etc/nginx/conf.d/game.conf
# マッチング4x4 upstream ws_matching_4x4 { server localhost:8081; server localhost:8082 backup; } # マッチング4x8 upstream ws_matching_4x8 { server localhost:8083; server localhost:8084 backup; } # マッチング4x12 upstream ws_matching_4x12 { server localhost:8085; server localhost:8086 backup; } # 対戦(ペアIDの先頭がcからnまでの12個) upstream ws_round_0b { server localhost:8181; server localhost:8182 backup; } # 対戦(ペアIDの先頭がcからnまでの12個) upstream ws_round_cn { server localhost:8183; server localhost:8184 backup; } # 対戦(ペアIDの先頭がoからzまでの12個) upstream ws_round_oz { server localhost:8185; server localhost:8186 backup; } server { listen 80; server_name game.example.com; charset utf-8; root /var/www/game/public; # エラーページ error_page 404 /404.html; error_page 500 502 503 504 /50x.html; # websocket_paramsのインクルード include /etc/nginx/websocket_params; # マッチング4x4 location ~ ^/ws/matching/4/$ { proxy_pass http://ws_matching_4x4; } # マッチング4x8 location ~ ^/ws/matching/8/$ { proxy_pass http://ws_matching_4x8; } # マッチング4x12 location ~ ^/ws/matching/12/$ { proxy_pass http://ws_matching_4x12; } # 対戦(ペアIDの先頭がcからnまでの12個) location ~ ^/ws/round/[0-9a-b][0-9a-z]+?/$ { proxy_pass http://ws_round_0b; } # 対戦(ペアIDの先頭がcからnまでの12個) location ~ ^/ws/round/[c-n][0-9a-z]+?/$ { proxy_pass http://ws_round_cn; } # 対戦(ペアIDの先頭がoからzまでの12個) location ~ ^/ws/round/[o-z][0-9a-z]+?/$ { proxy_pass http://ws_round_oz; } }
※全部localhostにしてポートを変更していますが、細分化すれば、上記設定で12台に切り分けられます。
※もちろん、もっと細かく分けることも可能です。
という具合で考えると、
ちょっと大げさに以下のようなイメージでインフラが考えられます。
このようにフロントのサーバの機能を利用することで、
pub/subを使わずにwebsocketを通じたメッセージのやり取りができます。
狙いとしては
「同一属性者を同じブロセスに閉じ込めることで、メモリ内の操作で処理を完結させる」
ということになります。
コメントがあればどうぞ