Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

ポコロンダンジョンズとリアルタイム通信 -サーバサイド編-

12,535 views

Published on

Node.js、Socket.IOを利用したリアルタイム通信の開発と運用

https://atnd.org/events/76070
の発表資料です

Published in: Engineering
  • Be the first to comment

ポコロンダンジョンズとリアルタイム通信 -サーバサイド編-

  1. 1. 2016/04/20 株式会社グレンジ 塚原 裕也 ポコロンダンジョンズと リアルタイム通信 -サーバサイド編-
  2. 2. ‣名前 塚原 裕也 ‣所属 株式会社グレンジ ‣経歴 ・2008/04 SIのベンチャー企業に入社 ・2012/02 Cyber X入社 - アイドルレボリューション - メジャーリーグオールスターズ - NBA2Kオールスターズ - サカつくSワールドスターズ ・2014/11 グレンジへ異動 - ポコロンダンジョンズ 自己紹介
  3. 3. アジェンダ ‣ポコダン概要 ‣利用技術 ‣サーバ構成 ‣データ ‣機能 ‣発生した問題と対応
  4. 4. ポコダン概要
  5. 5. ポコダン概要 ‣リリース iOS:2014年6月 Android:2014年8月 ‣最新バージョン 3.6.1 ‣ダウンロード数 500万
  6. 6. ‣マルチプレイ導入 2015年3月 開発期間は8ヶ月位 当初は2014年内に導入予定だった ‣チーム人数 45人弱 サーバーサイド:3.5人 クライアントサイド:6.5人 ポコダン概要
  7. 7. •Nginx(1.4.4) •PHP(5.5.7) •Phalcon(1.2.6) •MariaDB(5.5.38) •Redis(2.8.4) •Memcached(1.4.15) 利用技術-非リアルタイム通信部分-
  8. 8. • Nginx(1.4.4) • Node.js(v0.10.32) • Socket.IO(0.9.17) クライアントのライブラリに合わせて0.9.17を選択。 接続時にハンドシェイクが遅延した場合に一定期間 ハンドシェイクを待つパッチを当てて利用している 。 https://github.com/tico8/socket.io/tree/0.9.16-patched • Redis(2.8.4) 利用技術-リアルタイム通信部分-
  9. 9. ‣ Socket.IOとは • Websocket、xhr-polingをサポート クライアントの環境次第で自動的に切り替え • Websocket通信を数行で始められる • 接続確立は2段階方式 1.ハンドシェイク 2.接続要求 3.接続確立 利用技術-リアルタイム通信部分-
  10. 10. ‣ RedisのPub/Subとは • publish(発行)、subscribe(購読)の略 • イベントが発行されると、購読者へ通知される ‣ マルチプレイでの利用場面 • データ更新通知 • プレイ情報の同期 利用技術-リアルタイム通信部分-
  11. 11. ・・・ ロードバランサ ・・・ データ用pub/sub用 ロードバランサ websocket https サーバ構成-全体-
  12. 12. • BIG-IP製 • SSL対応 • ラウンドロビン+IP persistence設定 - 同じIPアドレスは、同じnodeサーバへ - persistenceのキャッシュ削除間隔を1秒程度 - マスクは255.255.255.255 最近まで255.0.0.0になってて偏りが・・・ • sticky sessionを利用 Socket.IOのコネクション確立通信(2発目)を同サー バに振るため サーバ構成-ロードバランサ-
  13. 13. ロードバラン サ ② ① 同じIPは同じサーバへ振れるが、Socket.IOで問題が・・・ ‣ persistenceありの場合 サーバ構成-ロードバランサ-
  14. 14. ‣ サブネットマスク • 255.0.0.0の場合 第1オクテットのみで振り分け 192.0.0.0~192.255.255.255 IPアドレス数:16777216 →均等に割り振られない • 255.255.255.255の場合 第4オクテットまで振り分け IPアドレス数:1 →均等に割り振られる サーバ構成-ロードバランサ-
  15. 15. ロードバラン サ ‣ sticky sessionなしの場合 ①handshake ②connect handshakeとconnectで違うサーバーへ振られてしまう可能性が (MemoryStore利用時) サーバ構成-ロードバランサ-
  16. 16. ロードバラン サ ①handshake ②connect ③connected handshakeとconnectが同じサーバーへ振られるため、コ ネクションが確立できる。 (MemoryStore利用時) ‣ sticky sessionありの場合 サーバ構成-ロードバランサ-
  17. 17. ‣ Nginx • 80番ポートで受け • 3000番ポートでNode.jsに流し込む • リバースプロキシでサブドメインを割り当てた Node.jsに振る ‣ Node.js • 1マスタープロセス、1ワーカプロセス ※ワーカプロセスがCluster構成にできなかった • foreverを利用しプロセス永続化 サーバ構成-Webサーバ-
  18. 18. server { listen 80; server_name localhost; index index.php index.html index.htm; set_real_ip_from 10.0.0.0/8; real_ip_header X-Forwarded-For; underscores_in_headers on; location ^~ /pocolon_dungeons_node/ { proxy_pass http://127.0.0.1:3000/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } location ^~ /pocolon_dungeons_node/socket.io/ { … } /etc/nginx/conf.d/pocolon_dungeons_node.conf サーバ構成-Webサーバ-
  19. 19. • pub/sub用とデータ用の2種類 • pub/sub用はルーム単位で振り分け • データ用はPHP側からも利用する サーバ構成-Redisサーバ-
  20. 20. データ-Redisのキー- 1.マッチング検索用(ソート済みセット型) 位置情報、ルームIDを登録 2.ルーム情報用(ハッシュ型) ルーム詳細情報を登録 ・ダンジョン情報 ・ステータス管理(マッチング中、クエスト中) ・位置情報 ・アプリバージョン 3.メンバー情報用(ハッシュ型) デッキ情報(装備/モンスター)などを登録
  21. 21. 4.ロック用(文字列型) ルーム情報、メンバー情報のキーを更新 する際のロックに利用。 SETNX()+EXPIRE SETNX=“SET if Not eXists” キーが存在したらセット出来ないのを利 用し、キーのセットと削除でロックを実 現。 データ-Redisのキー-
  22. 22. 機能-処理の流れ- • ルーム作成/参加 PHP⇒Node.jsの一連の処理が完了して、Websocketのコネク ションが確立出来たら処理完了。 • クエスト開始 PHP側でDBに登録後、Node.jsで待ち合わせ処理をし 、マルチプレイ開始。 • クエスト中 基本的にWebsocket通信だが、DB操作が必要な場面は PHP側で処理される。(コンティニュー等) • クエスト終了 Websocketのコネクション破棄後、PHP側でDB更新 が行われる。
  23. 23. •マルチプレイ以外の機能全て •ルーム作成、参加 ※websocketのコネクション確立部分はNode.js •ルーム検索 •その他(シングルプレイ共通部分) プレイヤー情報取得、ドロップ抽選、 ログなどDB操作が絡む処理 •RedisのデータはNode.js側と共有 機能-非リアルタイム通信部分-
  24. 24. 機能-リアルタイム通信部分- •クエスト開始後のほぼ全ての処理 コンティニューなどDB操作をする際はPHPの通信も行っている •コネクション確立、破棄 コネクション時のユニークIDをRedisに登録している •クライアントから送られたデータを受け流す ゲームロジックは持たない。 •同期 フロア待ち合わせ、盤面復旧。 •ソケット切断 一定時間応答のないプレイヤーを切断。 •ソケット再接続
  25. 25. ‣PHP側 •位置情報、合言葉などを受け取り •Redisデータ登録 マッチング検索用、メンバー情報用などキーを 複数に分けている。 •デッキ情報など表示に使うデータを返す ‣Node.js側 •ユーザID、ルームIDなどを受け取り •Redisデータ更新 ルーム情報のステータスをマッチング中に。 ソケット接続完了ステータスに。 •デッキ情報など表示に使うデータを通知 機能-ルーム作成-
  26. 26. ‣PHP側 •位置情報、合言葉などを受け取り •Redisデータ取得 •絞り込み条件 -同一アプリバージョン 機能やバグに差異が生じ、盤面がズレる原因になるた め。 -位置情報が近いルーム 上限数になるまで、徐々に距離を延ばして検索を繰り 返す(距離の上限もある) •ルームのリスト及び表示用データを返す 機能-ルーム検索-
  27. 27. ‣ PHP側 • ルームIDなどを受け取り • Redisデータ更新 メンバー情報に自身を追加 ※ソケット未接続ステータス • ルーム内のユーザのデッキ情報など表示用データを 返す ‣ Node.js側 • ユーザID、ルームIDなどを受け取り • Redisデータ更新 ソケット接続済みステータスに更新 • 更新情報など表示に使うデータを全メンバーへ通知 機能-ルーム参加-
  28. 28. 機能-同期/待ち合わせ- ‣ Node.js側 1.各端末から準備完了イベントを発行 2.自身の状態を準備完了ステータスに更新 3.一定時間応答のないユーザーの切断処理 4.全員が揃うまでは待機を全メンバーへ通知 5.全員が揃ったら同期完了を全メンバーへ通 知
  29. 29. 機能-ソケット切断- ‣ Node.js側 • 生存確認イベントが一定時間来ないプレイ ヤーのソケットを切断 • Redisデータ更新 - ホストが離脱した場合は解散or権限委譲 - ゲストの場合、ホストに権限委譲 • 切断情報を全メンバーに通知
  30. 30. ‣ Node.js側 一定時間内の再接続要求は再度ルームに紐 付けし直す。 • ユーザID、ルームIDなどを受け取り • Redisデータ更新 自身のコネクションIDを書き換える • 更新情報など表示に使うデータ全メンバー へ通知 機能-ソケット再接続-
  31. 31. 機能-その他イベント- •生存確認 •なぞり •クエスト開始通知 •プレイヤーターン終了 •コンティニュー •リタイヤ •スキル使用 •コミュニケーション
  32. 32. ‣プロセスをCluster構成にできない 【原因】 Redis周りの独自実装が原因。 MemoryStoreを利用してセッション管理をしていたため、 別のプロセスに振られると処理できない。 【一次対応】 1サーバにつき1マスタープロセス、1ワーカプロセスにし た。 ➡︎1コアだったため、別プロセスの影響を受け、Nodeの処 理が詰まることがあった 【恒久対応】 素直にRedisStoreを利用すれば別のサーバ/プロセスに振ら れても問題なくセッション維持ができる。 (今週リリースします) 発生した問題と対応
  33. 33. LB ①handshake ③connect ④connected handshakeとconnectが別サーバーへ振られても、コネク ションが確立できる。 つまりsticky sessionも不要になる。 ‣ RedisStoreを利用した場合 ②セッション共有 ④セッション情報取得 発生した問題と対応
  34. 34. ご静聴ありがとうございました 。

×