Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ステートフルで大規模アクセスのあるsoft-realtimeなゲームサーバーをeasyにつくる

 ステートフルで大規模アクセスのあるsoft-realtimeなゲームサーバーをeasyにつくる

#elixirfest #elixirfestjp

さっちゃん

June 16, 2018
Tweet

More Decks by さっちゃん

Other Decks in Programming

Transcript

  1. 開発teamを立ち上げる 前提 : 資産が無い。 • 新規開発である。 • Real time対戦serverの知見があまり無い。 •

    HTML5 game applicationのserver側の知見が無い。 Elixirの運用経験が在る。(Elixirを使ってSidekiqを操作する https://qiita.com/ohr486/items9/db88866786ee8bb89d9) Prototype開発期間であり、失敗したら作り直せる。
  2. どのやうに開発を始めたか アプリを作る前にrailを敷く心。 • Credo • Dialyzer • mix test •

    eye_drops • docker-compose.yml • PULL_REQUEST_TAMPLATE.md • CODE_OF_CONDUCT.md
  3. どのやうに開発を始めたか アプリを作る前にrailを敷く心。 • Credo • Dialyzer • mix test •

    eye_drops • docker-compose.yml • PULL_REQUEST_TAMPLATE.md • PULL_REQUEST_TAMPLATE.md • CODE_OF_CONDUCT.md https://hex.pm/packages/inner_cotton
  4. Master dataの管理 https://hex.pm/packages/mnemonics • 読み取り専用。 • on-memoryで高速。 • 再起動せずに新しいver.のdataへ入れ 替へられる。

    • 古いver.で処理してゐた計算はそのまま 古いver.を読み出し続けられる。 • Heap領域にcacheできる。読み出した dataをsnapshotとしてsystem外に持 ち運べる。 • Parallel。
  5. Build for release Distilleryでmix releaseする。 Docker multi stage buildでimageを軽くする。 Umbrellaでmicro

    serviceを開発し、Distilleryで別々にbuildしてゐる。 Stagingと本番で全く同じimageを使ふ (可搬性) 為に、config.exsではなく環境変数 で設定する。(https://hexdocs.pm/distillery/runtime-configuration.html) 環境変数はK8sのConfigMapから設定する。
  6. Kubernetes on AWS K8sを選んだのは : • Game logicが大量に載ってゐる & PvPなので、hot

    deployは考へたくなかっ た。 • Elixirの標準のdeploy & scale方法が無かったので、containerに入れて何も 考へたくなかった。 • Dockerに含まれる等、de facto standardである。 • GCPでもAzureでも使へる。(当時はAWSでのみ使へなかった。) • 将来の為の知見としても有用。
  7. 監視 監視は社内標準のZabbix。 Node (インスタンス) のmetricsは社内標準のmackerel。 APMはAppSignal + ReconEx。error通知はSentryで行ふのでerror_loggerは 外す。 error通知は社内標準のSentry。logger_sentryを使ってゐたが追加情報を送れな

    いのでやめた。Sentry付属のerror_logger + 自作のErrorLogger macroを丁寧 に埋め込んである。 Logは、DaemonSetでfluentdを立て、CloudWatch + S3に送る標準的なやり方 をしてゐる。
  8. 負荷試験 問題 : Logger。 Stagingでdebug logを見たい & stagingと本番で同じDocker imageを使ひたい →

    Loggerのlevelだけ設定し、compile_time_purge_levelを設定してゐなかっ た。 Loggerに大量のmessageが詰まり、常にsync_thresholdを超える。全ての処理が IO待ちになる。 Stagingでのdebug logを諦め、compile_time_purge_levelを設定した。 Loggerの各種thresholdを1桁くらい上げた。
  9. 負荷試験 問題 : 対戦dataがmemoryを使ひ切る。 対戦dataをRedisに一時保存してあり、計算時に取り出す。取り出したところで memory不足でprocessがcrash (process毎にmemory制限をかけてある)。 Erlangの一部の外部表現は大きくなる。特にNEW_FUN_EXTとか (External Term

    Format http://erlang.org/doc/apps/erts/erl_ext_dist.html)。 Master dataと共通するdata (Mnemonics.Snap) を保存前に削除し、master dataから毎回取り直す。 `:erlang.term_to_binary(&1,[:compressed])`で圧縮する。
  10. 負荷試験 問題 : Redis (PubSub) へのnetworkを使ひ切る。 そもそもpublishを減らす。Publish先を抽象化するstructを作り、Channel topic ではなくstructに向けてpublishする。Publishが不要だと判定したら、send/2で済ま す。

    `:erlang.term_to_binary(&1,[:compressed])`で圧縮する。但しmapしかpublish できないのでvalueだけ圧縮する等dirty hack。 Dataを直接にpublishせずKVSに置き、keyだけをpublishする。 Redisをshardingする (後述)。
  11. Redis (KVS)をscaleさせる https://hex.pm/packages/redis_z • No downgrade from Redix: pipeline concurrency

    & auto reconnection. (https://hexdocs.pm/redix/real-world-usage.html) • Parallel connection pooling. • Sharding support. • Auto reconnect at Amazon ElastiCache Multi-AZ failover. (https://rubygems.org/gems/redis-elasticache)