ゲームエンジニアのためのデータベース設計

701 views
758 views

Published on

GameServerDevelopers Vol.1
https://gsdevelopers.doorkeeper.jp/events/42497

Published in: Engineering
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
701
On SlideShare
0
From Embeds
0
Number of Embeds
200
Actions
Shares
0
Downloads
1
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide
  • インデックス効かない場合の解決策

    見出しは文字をでっかく

  • ゲームエンジニアのためのデータベース設計

    1. 1. Copyright © DeNA Co.,Ltd. All Rights Reserved. ゲームエンジニアのための データベース設計 株式会社 DeNA Games Osaka 技術編成部 人西 聖樹 masaki.hitonishi@dena.com
    2. 2. Copyright © DeNA Co.,Ltd. All Rights Reserved. 自己紹介  人西聖樹 (ひとにし まさき)  株式会社 DeNA Games Osaka 2014年 入社  Webアプリケーションエンジニア  シューティングゲーム好き。東方Project 大好き  某400万人ユーザー超えモバイルゲームの 開発やってます
    3. 3. Copyright © DeNA Co.,Ltd. All Rights Reserved. ゲームの サーバーサイド
    4. 4. Copyright © DeNA Co.,Ltd. All Rights Reserved. データを どうやって 保存しようか?
    5. 5. Copyright © DeNA Co.,Ltd. All Rights Reserved. 多様な選択肢  RDBMS MySQL Oracle PostgreSQL  KVS Redis Riak  カラム指向型 Apache Cassandra Hbase  ドキュメント指向 MongoDB Apache CouchDB etc…
    6. 6. Copyright © DeNA Co.,Ltd. All Rights Reserved. 今日は MySQL の 話をします!
    7. 7. Copyright © DeNA Co.,Ltd. All Rights Reserved. 突然ですがアンケー ト
    8. 8. Copyright © DeNA Co.,Ltd. All Rights Reserved. MySQL使った事ある人!
    9. 9. Copyright © DeNA Co.,Ltd. All Rights Reserved. explain コマンド 使ったことある人!
    10. 10. Copyright © DeNA Co.,Ltd. All Rights Reserved. InnoDB における ギャップロック と ネクストキーロック について説明できる人!
    11. 11. Copyright © DeNA Co.,Ltd. All Rights Reserved. 本日のテーマ  RDBMS (リレーショナルデータベース) とは  データベース観点でのゲームのデータの特徴  データベース構築時に気をつけること  アプリケーション開発時に気をつけること
    12. 12. Copyright © DeNA Co.,Ltd. All Rights Reserved. リレーショナルデータベースとは  データを行と列の組み合わせによる表で表す  複数の表と表を関係(リレーション)によって組み合わせられる ID 名前 攻撃力 防御力 1 Aさん 100 100 2 Bさん 200 150 ユーザーID アイテムID 所持数 1 1 1 1 2 3 1 3 5 ユーザーテーブル アイテム所持テーブル ユーザーテーブルの情報から Aさんがどのアイテムを何個所持している か取得することができる。
    13. 13. Copyright © DeNA Co.,Ltd. All Rights Reserved. ACID特性  Atomicity 原子性 トランザクションの操作は全て実行されるか まったく実行されないかのどちらか  Consistency 一貫性 トランザクション開始時と終了時にデータの 整合性が保たれる  Isolation 独立性 他のトランザクションによる操作の影響を受けない  Durability 永続性 コミットしたトランザクションのデータは保存される
    14. 14. Copyright © DeNA Co.,Ltd. All Rights Reserved. ゲームデータの特徴  ユーザーを primary key としたレコードが多い  永続データと期間限定データ(イベントのデータ等)がある  マスタデータ(read only)が多い アイテムマスタ、ボスマスタ、ボス出現マスタ etc…  レコードの状態更新が多い ボスのHP減少、HP回復、マップ移動 etc…  可用性・整合性は大切 ゲームがプレイできない、アイテムを使用したのに 回復していない等の不具合・障害に対して、 課金しているユーザーの温度感は非常に高い
    15. 15. Copyright © DeNA Co.,Ltd. All Rights Reserved. データベース構築時に考えること  Master/Slave 構成  垂直分割  水平分割 垂直/水平分割はアプリケーション側で対応しないといけない (MySQL 側に仕組みがない)が後から追加するのは 大変なので最初から考慮して開発する
    16. 16. Copyright © DeNA Co.,Ltd. All Rights Reserved. Master / Slave 構成 Master Slave Slave Slave レプリケーション
    17. 17. Copyright © DeNA Co.,Ltd. All Rights Reserved. ゲームは更新系クエリがめちゃ多い  ボタンを押すだけでステータス更新  体力増減とか  ボスへダメージとか  アイテム獲得とか
    18. 18. Copyright © DeNA Co.,Ltd. All Rights Reserved.  参照系クエリは Slave に逃せる。  Slave のスケールアウトは容易  更新系クエリは必ず Master にI/O負荷がか かる → Master はボトルネックになりがち
    19. 19. Copyright © DeNA Co.,Ltd. All Rights Reserved. 垂直分割 Aテーブル Bテーブル Cテーブル Dテーブル Eテーブル Fテーブル Gテーブル Hテーブル Iテーブル  テーブルの種類によって DB を分割。  Join 句が使えなくなる。  テーブルへのアクセス数が均等になるように分割しないと負荷が偏る
    20. 20. Copyright © DeNA Co.,Ltd. All Rights Reserved. 水平分割  レコードのカラムの値でDBを分割  範囲取得や count, sum が面倒に  auto_increment が使えなくなる→採番テーブルを別途用意する Aテーブル Bテーブル Cテーブル Aテーブル Bテーブル Cテーブル Aテーブル Bテーブル Cテーブル ↑ID: 1 のレコードはこっち ↑ID: 2 のレコードはこっち ↑ID: 3 のレコードはこっち
    21. 21. Copyright © DeNA Co.,Ltd. All Rights Reserved. 複数のトランザクションを扱う  複数DB へのトランザクションをどう扱うか?  InnoDB の REPEATABLE READ は最初のクエリ発行時に取得できるレ コードの値が決定するので、各DBに対して最初のクエリをいつ投げる か意識する必要がある。  コミットタイミングは全て同一で行うのが楽  コミットタイミングが別々だとデータ不整合が起こりやすくなる(片方 はコミット済みなのにもう片方はロールバックとか…
    22. 22. Copyright © DeNA Co.,Ltd. All Rights Reserved. アプリケーション開発時に気をつけること  適切なindexとindexを使える適切なクエリ  クエリ発行量を減らす  行ロック  レプリ遅延対策  Repeatable read の特性
    23. 23. Copyright © DeNA Co.,Ltd. All Rights Reserved. インデックス InnoDB のインデックスは B+ Tree 常に一定の深度になるようにバランス化された木構造 1レコードの取得に対して O(log N) で探索することができる
    24. 24. Copyright © DeNA Co.,Ltd. All Rights Reserved. オプティマイザ オプティマイザとは・・・ SQLがどのインデックスを使用し、どの順序でアクセスするかという 実行計画(EXPLAIN)を決定する EXPLAIN構文・・・ 「EXPLAIN SELECT~」とすることで、オプティマイザが 選択した実行計画を表示できる UPDATEやDELETEの場合、SELECTに書き換える必要がある mysql> explain select * from test where id = 1; +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+ | 1 | SIMPLE | test | const | PRIMARY | PRIMARY | 4 | const | 1 | Using index | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
    25. 25. Copyright © DeNA Co.,Ltd. All Rights Reserved. オプティマイザ MySQLはコストベース・オプティマイザ コストベースのオプティマイザでは、統計情報だけなく CPUクロック メモリ容量 DISK I/O速度 DBMSでのパラメータ で実行計画が決定される 開発環境と同じ実行計画になるとは限らない データ件数が違う データの種類が違う CPUクロックが違う メモリ容量が違う など MySQL のオプティマイザは実行計画を結構見誤る 不安ならばFORCE INDEX で使用するインデックスを指定する
    26. 26. Copyright © DeNA Co.,Ltd. All Rights Reserved. インデックスを使えないケース例 ALTER TABLE テーブル名 ADD KEY (col1, col2, col3); ・否定 WHERE col1 <> 1 ・2つ目のキーから指定 WHERE col2 = 1 AND col3 = 1 ・カラム側に計算式を使用 WHERE col1 * 100 = 100 ・範囲指定 WHERE col1 > 1 AND col2 = 2 (col2はインデックスを使えない) ・昇順と降順の混在 ORDER BY col1 ASC, col2 DESC(col2はインデックスを使えない)
    27. 27. Copyright © DeNA Co.,Ltd. All Rights Reserved. クエリ発行量を減らす  綺麗に正規化しない(あえて冗長にデータを持つことで 1 query で必要 なデータを取得する)  あえてカラムを分割する 更新が低いが参照の多いテーブルはmemcached にキャッシュする 更新が多いテーブルはなるべくカラムを絞って InnoDB の buffer pool に乗るようにする  時限付きデータ(イベントデータ等)は別テーブルにすることでイベント 終了後に drop table できるようにする  IN句でSELECT SELECT * FROM user WHERE id IN(1, 2, 3, ...);  Bulk insert INSERT INTO user values (1,'tanaka'),(2,'yamada'),(3,'hansen');  INSERT INTO … ON DUPLICATE KEY UPDATE … レコードが存在しなければ INSERT 、存在すれば UPDATE を 1 query で実行できる。
    28. 28. Copyright © DeNA Co.,Ltd. All Rights Reserved. 行ロック  同時操作を常に意識する AさんとBさんが同時にボスを攻撃したら両方ともボスを撃破した扱い になったり… Aさんが2端末使って、同時にアイテムを受け取りを押すことでアイテ ム増殖できたり…  前者は攻撃時にまずボスレコードをロックして、AさんとBさんの処理 を直列させることで防げる  後者はアイテム受け取り時にAさんのレコードをロックして処理を直列 させることで防げる  ロックの順番を統一しないと、デッドロックが発生する。  必ず存在するレコードに対してロックを取る  存在しないレコードをロックすると、InnoDBの Repeatable Read で は gap lock が発生し、広範囲にロックを獲得する。 → lock wait timeout
    29. 29. Copyright © DeNA Co.,Ltd. All Rights Reserved. レプリケーション遅延対策  大量クエリのコミット等でレプリ遅延(master DBへの変更が slave DBへ反映が遅れること)が発生する  回復アイテムの使用(Masterを更新)→次ページで使用結果を見ると回復 していない(Slave にまだ回復の反映が遅れてる) →更新処理後、更新したデータをcacheに詰めて、遷移先で使用する →更新処理後、更新処理から遷移されてきたかどうかを見て、master or slave のどちらを参照するか決める  1リクエスト内で Slave のデータを元に Master を更新すると、レプリ 遅延で古い Slave のデータを参照していてデータの不整合が起こる →更新系のリクエスト内で参照するDB は Master で統一する
    30. 30. Copyright © DeNA Co.,Ltd. All Rights Reserved. KVSとの併用について  ゲームデータのキャッシュは難しい  更新を頻繁に行うのでキャッシュクリア処理が面倒  忘れると気づきづらい障害に  トランザクションとの整合性  Read Only のデータ(マスタ等)をキャッシュするのが一番楽
    31. 31. Copyright © DeNA Co.,Ltd. All Rights Reserved.  ゲームサーバーのデータベースは整合性/負荷と の戦い  ノウハウを知って急激なアクセス増加にも耐えら れる構築/開発をしよう
    32. 32. Copyright © DeNA Co.,Ltd. All Rights Reserved. おわり

    ×