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.

リアルタイムサーバー 〜Erlang/OTPで作るPubSubサーバー〜

12,598 views

Published on

第5回 ゲームサーバ勉強会 で発表した リアルタイムサーバー〜Erlang/OTPで作るPubSubサーバー〜 の資料です。

ArkPS Server としてオープンソース化予定。

Published in: Technology
  • Be the first to comment

リアルタイムサーバー 〜Erlang/OTPで作るPubSubサーバー〜

  1. 1. リアルタイムサーバー Erlang/OTP で作る PubSub サーバー
  2. 2. 自己紹介 @yamionp gumi ってところで R&D をしています サーバーさわりはじめて 15 年 Python 5年 Erlang 6ヶ月
  3. 3. 関わったもの
  4. 4. 今日話す事
  5. 5. リアルタイムサーバーを自作した話
  6. 6. アジェンダ なぜリアルタイムサーバーか なぜ自作なのか PubSubモデル プロトコル
  7. 7. アジェンダ サーバー なぜ Erlang/OTP なのか 負荷試験 実際のゲームでの使われ方
  8. 8. なぜリアルタイムサーバーか
  9. 9. これまでのソーシャルゲーム 非同期コミュニケーション 同時に遊んでいないのに一緒に遊んでいる感覚 ニコニコ動画 技術的制約(モバイルWeb・処理能力・バッテリー)
  10. 10. より濃密なゲーム体験へ より強い連携・一体感 本当の同時プレイ ニコニコ生放送 アプリ化 / 端末性能・ネットワーク環境の向上
  11. 11. リクエスト/レスポンス モデル Request ResponseClient Server
  12. 12. リクエスト/レスポンス モデル Request ServerClient
  13. 13. HTTPの問題 通信はユーザー側からしか開始できない(Serverから送れない) 無いわけではない (それで十分な場合も多い) 高頻度の通信が難しい(毎秒10回通信 オーバーヘッド レインテンシ
  14. 14. ServerClient SYN SYN+ACK ACK 最初に Connection を確立する TCP Connection を直接使う
  15. 15. TCP Connection を直接使う Connectionがある限り自由なタイミングで通信できる ServerClient
  16. 16. HTTPでもTCPは使っているが Response を返したら Connection を破棄する (ステートレス) ServerClient
  17. 17. リアルタイム通信のメリット (準備さえできれば) どちらからでも送り始められる 一回あたりの通信コストが小さい 秒間15回とか送っても全然OK 遅延が少ない
  18. 18. デメリット 負荷が高い・負荷分散しにくい 状態を持つので障害に弱い エラーパターンが多くコードが複雑になりがち 端末のバッテリー消費が激しい (通信頻度が高い)
  19. 19. なぜ自作なのか
  20. 20. いろいろあるが・・・ Windows Server は (我々にとって) 運用コストが高い 機能過多 既存システムとの相性 ゲームでの通信に特有な仕様への対応 落としたくない。土日に寝ていられるシステムを
  21. 21. ちなみに
  22. 22. フルメッシュ
  23. 23. スター ここの話をします
  24. 24. Pub/Subモデル
  25. 25. Pub/Sub(出版/購読)モデルとは 非同期メッセージングモデルの一種 Subscribe (購読) しているユーザーにメッセージを Publish (出版) する Sub側は Topic という単位で購読する Pub側は Topic にメッセージを送る Pub側は Sub側を意識する必要がなく、疎結合になる
  26. 26. Subscribe Broker Topic A Topic B A B C D
  27. 27. Broker Topic A Topic B A B C D
  28. 28. Broker Topic A Publish Topic B A B C D
  29. 29. Broker Topic A Topic B A B C Publish D
  30. 30. Room モデルとの違い Room の作成/削除が必要ない Roomの管理が必要ない Sub側 が 0 の Topic にも Publish できる Pub側が Topic を Subscribe している必要はない
  31. 31. 導入イメージ
  32. 32. ELB App Job MQ Batch log PubSub 既存の仕組みと喧嘩しないシンプルなシステムが欲しい
  33. 33. プロトコル
  34. 34. 目指したもの 数bitを切り詰めるよりシンプルであること 必要十分な拡張性 シリアライズ・パースがしやすい
  35. 35. 概要 TCP を採用 TLV ベースのプロトコル構造 最小限の固定ヘッダと拡張部分のTLV化 4 bytes 単位
  36. 36. 固定ヘッダ 1 bit 1 6 3 2 Type (メッセージの種類) Length (全体の長さ) SenderTimestamp (送信者時間) ※後述 ReceiverTimesamp (受信者時間) ※後述 Payload (送信内容)
  37. 37. Payload も連続した TLV の形をとる 1 1 6 3 2 SectionType SectionLength Value
  38. 38. つまり
  39. 39. 1 1 6 3 2 Type Length SenderTimestamp ReceiverTimesamp SectionType SectionLength Value SectionType SectionLength Value
  40. 40. この構造によるメリット 拡張しやすい 実装が比較的容易 バリデーションが容易
  41. 41. RTT計測 ユーザー サーバー の回線状態を把握していたい 強制切断など 通信時に自分のタイマーと処理時間を加算した相手のタイマーを送る
  42. 42. 固定ヘッダ 1 bit 1 6 3 2 Type (メッセージの種類) Length (全体の長さ) SenderTimestamp (送信者時間) ※後述 ReceiverTimesamp (受信者時間) ※後述 Payload (送信内容)
  43. 43. Client Server Timer Timer 1 1000 Sender Receiver 1 0 ※ ※初回は相手のTimerが わからないので0 送信までに300msかかったので 受け取った1に300を足す Sender Receiver 1300 301 1300 321 この時点で自分のタイマーが 321なのでRTTは20ms 421 送信までに100msかかったので 受け取った1300に100を足す Sender Receiver 421 1400 1420 この時点で自分のタイマーが 1420なのでRTTは20ms521 1520 この時点で自分のタイマーが 1520なのでRTTは20ms Sender Receiver 521 1500 受信から送信までに200msかかったので 受け取った1300に200を足す
  44. 44. なぜTCPか? NAT超え 到達保証 順序保証 輻輳制御 ゲームによってはTCPのみでも十分な場合も多い(ターン制など
  45. 45. UDP拡張の試験中 あくまでTCPのサブとしてのUDP 到達保証なし・順序保証なし・輻輳制御なし 品質の良くない回線などでとにかく早く送りたい場合 重要なやりとりはTCPで行う
  46. 46. サーバー
  47. 47. コンセプト 土管としての役割に徹する ステートフル、データレス 品質重視 安定して繋がり、そこそこ速く、落ちない。
  48. 48. 土管に徹する コネクションを持つ=状態が多くなる ネットワークプログラミングの大半はエラーハンドリング 持つべき状態は極力減らす アップデートの可能性を減らす
  49. 49. ステートフル・データレス 状態(ステート)は持つが、データは持たない。 永続化はしない 必要なデータは外部に問い合わせ or 通知 (ex. 認証 起動したらすぐ使える状態
  50. 50. 認証 App PubSub 1.game start 2.IP:Port, Token, Topic 3.Token 4.Token 5.OK 6.OK
  51. 51. 品質重視 ドキュメント 暗黙のルールを作らない Sphinxを採用(& packetdiag) 負荷試験 性能を保証する 自動テスト デグレさせない End to End テスト タイムアウト 同時処理
  52. 52. なぜ Erlang/OTP なのか
  53. 53. Erlang/OTP とは エリクソン社製の関数型言語 (1986年生まれ) 1998年からオープンソース 動的型付け 優れた耐障害性 並行処理・分散処理に強い
  54. 54. 軽量プロセス 起動速度・使用メモリが超軽量なプロセス OSのプロセス・スレッドとは違う 一瞬で立ち上がり、ごくわずかなメモリしか使用しない インスタンスを作る感覚でプロセスを作る 数万、数十万のプロセス走る プロセス間ではメッセージ通信ができる
  55. 55. Let it crash エラーが起こったプロセスは死ぬ プロセスが死んだ事は監視している別のプロセスに対処させる 再起動や後始末をしたり、連携するほかのプロセスの処置をしたり 監視プロセスは別のマシンで動いていても問題ない 正常系と異常系の処理が分離される
  56. 56. Erlang採用事例紹介 League of Legends https://engineering.riotgames.com/news/chat-service-architecture-servers Call of Duty https://en.wikipedia.org/wiki/Demonware http://www.erlang-factory.com/upload/presentations/395/ErlangandFirst- PersonShooters.pdf WhatsApp http://www.erlang-factory.com/upload/presentations/558/efsf2012-whatsapp-scaling.pdf Game of War https://erlangcentral.org/senior-erlang-engineer-machine-zone/
  57. 57. 社内に導入実績あり 認証・課金・テキスト検証、それぞれのマイクロサービス 数年間の連続稼働実績 全アプリからのリクエストを数台で処理している
  58. 58. プロセスデザイン tcp session session_udp ErlangVM ※ system process link link
  59. 59. tcp session session_udp ※ system process session_sup sessions_sup arkps_sup session_udp_sup ErlangVM udp_sup gen_udp simple_one_for_one one_for_all one_for_one one_for_one one_for_one
  60. 60. 停止フロー
  61. 61. tcp session session_udp ※ system process session_sup sessions_sup arkps_sup session_udp_sup ErlangVM udp_sup gen_udp simple_one_for_one one_for_all one_for_one one_for_one one_for_one session がなんらかの理由で Down
  62. 62. tcp session session_udp ※ system process session_sup sessions_sup arkps_sup session_udp_sup ErlangVM udp_sup gen_udp simple_one_for_one one_for_all one_for_one one_for_one one_for_one 検知した session_sup が session_udp_sup に停止を送り session_udp_sup がそれを受けて session_udpを停止
  63. 63. tcp session session_udp ※ system process session_sup sessions_sup arkps_sup session_udp_sup ErlangVM udp_sup gen_udp simple_one_for_one one_for_all one_for_one one_for_one one_for_one session_udp の停止を確認して session_udp_sup が停止
  64. 64. tcp session session_udp ※ system process session_sup sessions_sup arkps_sup session_udp_sup ErlangVM udp_sup gen_udp simple_one_for_one one_for_all one_for_one one_for_one one_for_one 監視下のすべてのプロセスの終了を確認して session_sup が停止
  65. 65. tcp session session_udp ※ system process session_sup sessions_sup arkps_sup session_udp_sup ErlangVM udp_sup gen_udp simple_one_for_one one_for_all one_for_one one_for_one one_for_one link している tcp も停止
  66. 66. 負荷試験
  67. 67. なぜ負荷試験を行うか 限界性能を知る ボトルネックの発見 スケールすることの確認 必要容量の計算 コスト試算
  68. 68. Locustを使いました Python製分散負荷試験ツール このためにフル機能の Python クライアントを開発 接続側はどんなに頑張っても限界がくるので数で解決 スポットインスタンス安い m4.large のスポットインスタンスが t2.medium オンデマンドより安 い
  69. 69. Locust Slaves PubSub Locust Master m4.2xlargem4.xlarge CPU: 8 RAM: 32GB CPU: 4 RAM: 16GB x8
  70. 70. メッセージ数計測 PubSub x71 msg 合計 8msg
  71. 71. PubSub
  72. 72. PubSub
  73. 73. PubSub
  74. 74. user/room 8 message/user/sec 0.2 waittime[ ms] 5000 rooms 100 1000 2000 3000 3500 3750 (想定) users 800 8000 16000 24000 28000 30000 (想定) message/sec 1280 12800 25600 38400 44800 48000 (実測) message/sec 1270 12783 25560 38328 44787 21054 (Server)CPU [%] 66.5 360.4 404.7 560.9 635.8 444.4 (Server)RAM [%] 0.6 2.4 3.7 6.2 7.2 16.5 RTT Med [ms] 1 2 5 12 19 34 RTT Avg [ms] 14 11 12 14 27 1260 RTT Max [ms] 44 49 75 356 536 62798 End to End Med [ms] 1 3 8 18 39 460 End to End Avg [ms] 2 12 13 21 50 3017 End to End Max [ms] 747 738 754 1003 1315 100979
  75. 75. user/room 8 message/user/sec 1 waittime[ ms] 1000 rooms 100 400 800 900 1000 (想定) users 800 3200 6400 7200 8000 (想定) message/sec 6400 25600 51200 57600 64000 (実測) message/sec 6360 25527 48195 53240 25154 (Server)CPU [%] 275.8 618.3 709.3 774.7 766.7 (Server)RAM [%] 0.5 1.1 2.7 3 11.2 RTT Med [ms] 1 1 5 12 5 RTT Avg [ms] 10 7 24 40 494 RTT Max [ms] 45 48 491 1100 34295 End to End Med [ms] 2 11 36 80 310 End to End Avg [ms] 10 13 54 120 970 End to End Max [ms] 554 550 981 2923 44120
  76. 76. user/room 8 message/user/sec 15 waittime[ ms] 66.66666 6666666 7 rooms 10 50 70 80 90 100 (想定) users 80 400 560 640 720 800 (想定) message/sec 9600 48000 67200 76800 86400 96000 (実測) message/sec 9096 46047 58600 60764 63539 26390 (Server)CPU [%] 229.8 694.7 776.6 775.6 787.9 786.2 (Server)RAM [%] 0.4 0.5 0.6 0.7 0.7 8 RTT Med [ms] 38 2 7 10 15 24 RTT Avg [ms] 30 14 15 17 23 194 RTT Max [ms] 45 67 93 122 522 20686 End to End Med [ms] 19 19 24 33 46 73 End to End Avg [ms] 18 21 27 37 50 293 End to End Max [ms] 618 631 657 718 1231 39470
  77. 77. UDPのスループットがTCPの1/5問題 V「5万/s はいける」 1万/s でない
  78. 78. fprof でプロファイリング sendが遅い port_command で非同期にしたら解決 gen_udp/tcp:send がボトルネックなときにやること http://qiita.com/mururu/items/9b77e49b5b8a2815ceb6 10万/s 出ました
  79. 79. user/room 8 message/user/sec 0.2 waittime[ ms] 5000 rooms 100 2000 3750 6250 7500 8750 (想定) users 800 16000 30000 50000 60000 70000 (想定) message/sec 1280 25600 48000 80000 96000 112000 (実測) message/sec 1281 25639 48124 78742 94555 97731 (Server)CPU [%] 46.9 312.2 426.8 625 723.2 718 (Server)RAM [%] 2 6.8 9.8 14 17.3 18.7
  80. 80. user/room 8 message/user/sec 1 waittime[ ms] 1000 rooms 100 400 800 1000 1200 1400 1600 (想定) users 800 3200 6400 8000 9600 11200 12800 (想定) message/sec 6400 25600 51200 64000 76800 89600 102400 (実測) message/sec 6356 25472 51202 63890 75912 88143 99033 (Server)CPU [%] 139.4 269.1 425 500.3 625.8 699.2 765.3 (Server)RAM [%] 2 3.6 5 5 5.2 5.2 6.6
  81. 81. user/room 8 message/user/sec 15 waittime[ ms] 66.66666 6666666 7 rooms 10 50 70 80 90 100 110 120 130 140 (想定) users 80 400 560 640 720 800 880 960 1040 1120 (想定) message/sec 9600 48000 67200 76800 86400 96000 105600 115200 124800 134400 (実測) message/sec 8912 45967 64648 74035 83211 91581 99596 106775 112889 116739 (Server)CPU [%] 161.5 374.2 489.7 535.8 582.1 632.1 666.4 703.7 726.9 784.7 (Server)RAM [%] 2.1 2.3 2.3 2.3 2.3 2.2 1.8 2.6 3 3.4
  82. 82. 実際のゲームでの使われ方
  83. 83. App PubSub Private Topic Private Topic matching start list matching Private Topic battle starter
  84. 84. HW障害への対応
  85. 85. App PubSub PubSub PubSub 1. battle info 2. 割り振り先をMySQLから取得 3. IP:Port, Token, Topic 4. 接続開始 監視サーバー サーバー一覧
  86. 86. App PubSub PubSub PubSub 1. Down 2. 検知 3. リスト更新 4. 切断されたので問い合わせ 5. Downを確認して割り振り先を決定・保存 6. 新割り振り先を案内 監視サーバー
  87. 87. バージョンアップ 今繋いでいる人 クライアントのバージョンxサーバーのバージョン 新しいサーバーをたてて、Appでの新規接続の案内先を変更 既存の接続がいなくなったら落として終了
  88. 88. Room Worker Room情報をゲームロジックまで含めて面倒をみる 最初に Subscribe する ブローカーからはクライアント扱い
  89. 89. App PubSub Battle Topic 6.battle info 2.battle start room worker 3.room create 4.subscribe 5. ok 7. IP:Port, Token, Topic 8. subscribe
  90. 90. 作ってみて 思ったより速度が出た デグレさせない事の重要さ 運用を最優先の姿勢
  91. 91. ご清聴ありがとうございました
  92. 92. One More Thing
  93. 93. ArkPS Server
  94. 94. OSSとして公開予定
  95. 95. https://github.com/arkps/ (予定地)

×