質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Q&A

解決済

1回答

1540閲覧

Node.jsでゲームサーバーを構築し、サーバープログラム更新時にサーバーを停止せず更新したい

hinatahinata

総合スコア29

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

0グッド

1クリップ

投稿2019/03/04 07:23

オンライン対戦ゲームのサーバープログラムをNode.jsで作成しています。
※WebSocketを使用した、1対1の将棋のようなターン制のゲーム
※オンライン接続時にルーム作成。空きルームが存在すればそこに参加。複数のルームでそれぞれ対戦が行われるイメージ。

後々追加したい機能があるため、サーバープログラムもその都度更新する予定です。
その際に、現在対戦中のプレイヤーの処理を中断せずに更新をしたいと考えています。
(もちろん、大幅な修正がある場合は別ですが)

調べたところ、Node.jsはホットデプロイ機能がないためグレースフルリスタートで対応するのが良いとわかりました。
PM2のgracefulReloadを使用すればそのような処理が可能になるのでしょうか。

[参考サイト]
https://qiita.com/ikemura23/items/b3481393d4edca2d5188
https://blog.morugu.com/entry/2018/01/30/222200

npm install -g pm2 pm2 start xxx.js --name appname pm2 restart appname

また、上記参考サイトに

引用テキスト「pm2 restart:稼働中のプロセスを正常に(処理が終了してから)終了して再読込する.」

とありましたが、例えばサーバープログラムが以下の場合

var ws = require ('ws').Server; var wss = new ws ({port: (process.env.PORT||3000)}); var socketList = []; wss.on ('connection', function (socket) { socketList.push(socket); socket.on ('message', function (message) { console.log(message); // 実際にはここでマッチング処理や対戦中の処理を行う。 }); socket.on('close', function () { socketList= socketList.filter(function (conn, i) { return (conn === socket) ? false : true; }); console.log("close"); }); });

クライアントがサーバーに接続してきたソケットを保存し、切断時にそれを破棄していますが、
pm2 restart appnameを実行時には以下のどのような挙動になるでしょうか。

  1. 全てのクライアントがサーバーから切断しない限りは古いプロセスは終了しない
  2. コールバックが全て処理された時点で再読み込みされる
  3. その他

挙動が2の場合、socketListにまだ要素が残っている時に再読み込みされた場合には
新しいプロセスで同じ変数に情報は引き継がれるのでしょうか。

ご教授お願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

Node.jsはWebSocketのパイオニア的な存在なので、
凄まじいパフォーマンスを出しそうに見えますが、
コヤツは実は1台のマシンで1万の同時接続を捌けません。

1サーバに同時接続出来る人数を5000人とかに絞って、
縦割りで実装すれば今回の質問のような所まで問題を持っていけると思います。

ですが、そもそも別方向で考えれば質問文の疑問も一発解決出来る妙案があります。


フロントで動くWebSocketのAサーバはロジック部分を持たず、
ユーザとの通信のみに集中します。
つまり、本質問で懸念しているロジックを更新するためにプロセスを落としたら接続どうするねん問題から逃げます。

そしてサーバーサイドにもう一台、WebサーバもしくはWebSocketサーバを立ち上げます。
これをBサーバと名付けます。

Bサーバはロジック部分を受け持ちます。
ゲームの進行状況、対戦者の情報、スコア…といった状態も持たせておきます。

Aサーバからの接続を待ち受けて、リクエスト通りにゲームを進行させ、結果をAサーバに返します。
AサーバはBサーバにお伺いを建てながらプレイヤー達に結果を返します。
つまり、Bサーバはフロントからアクセス出来ないようにしつつ、1台サーバを噛ませる事でフロントからの接続を切らせずにバックエンドを更新する事が可能になるでしょう。


この場合、ゲームのアップデートの為にBサーバを落とすとなると、
プレイ中のデータが全て消えてしまいます。

なので極力Bサーバの変数領域やメモリ空間等にゲームのデータを持たせてはいけません。
RedisやMySQL等のデータベースに持たせるような作りにしましょう。

後はAサーバ→Bサーバへお伺いを立てるリクエストが失敗したら、
再度通信するような仕組みを作っておけばBサーバは更新し放題になるでしょう。

投稿2019/03/04 08:00

miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hinatahinata

2019/03/04 09:21

まさに知りたいことドンピシャで目から鱗でした! ご提案頂いた方法について質問なのですが、 ゲームデータをデータベースに持たせる場合のイメージは以下のような感じでしょうか? (もちろんゲーム内容によって変わるとは思いますが) ` テーブル:rooms カラム:room_id, is_matching, turn ロジック部分 フロントから参加リクエストがあったら roomsから空室を探し参加させる 空室がなければ新たな部屋を作り(insertし)roomsに追加。そこに参加させる。 ターン数なども毎回roomsから取り出して加算し、roomsのroom_idのturnをupdateする ` また、そのデータベースの構成自体を大幅に変更する場合は スマホゲームによくある「メンテナンス時間」をあらかじめ通知して サービスを一旦停止する、という実装方法がメジャーでしょうか。
miyabi-sun

2019/03/04 09:56 編集

ソシャゲとか開発したこと無いですし、そういったDBを専門職としてチューニングした経験はないですが、 (億近いレコードのテーブルを触った経験はあり) データベースに持たせるイメージは大体そんなもんですね。 とはいっても、この辺は作りながらああでもないこうでもないと転がしながら設計していく感じになるでしょう。 しかし何でもかんでもMySQLで出し入れすると速度面で辛いと思うので、 ユーザのID、パス、レーティング情報なんかの紛失したら会社を畳みかねないようなデータは紛失しないようMySQLへ、 ルーム情報や対戦中のデータ(将棋でいう棋譜)なんかはRedisなんかの高速軽量なNoSQLで管理することを考慮に入れましょう。 まぁ、リリースするまでは全てMySQLで良いと思います。 実際どこがボトルネックになるかはサービスをリリースしないと見えてこない部分もありますからね。 > スマホゲームによくある「メンテナンス時間」をあらかじめ通知してサービスを一旦停止する 設けたほうが良いですね。 膨大なログファイル、各対戦データ等の情報は凄まじい速度でサーバのHDD領域を奪っていくはずです。 いくらMySQLみたいなサーバの性能が優れているからといって何年も積み上げるだけだとどんどん速度が劣化してしまうので、3ヶ月より前のデータは別にバックアップとして移動する等した方が良いです。 そうなると、1週間に数時間メンテナンスの時間が欲しくなるんじゃないですかね?
hinatahinata

2019/03/04 10:40

非常にわかりやすい説明で助かります。 データベースへのアクセスによる速度が気になっていましたが それも使い分けることで対応できるのですね。 アドバイス頂いたおかげで次の段階へ進めそうです。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問