More Related Content Similar to ゲームエンジニアのためのデータベース設計
Similar to ゲームエンジニアのためのデータベース設計 (20) More from sairoutine (11) ゲームエンジニアのためのデータベース設計1. Copyright © DeNA Co.,Ltd. All Rights Reserved.
ゲームエンジニアのための
データベース設計
株式会社 DeNA Games Osaka
技術編成部
人西 聖樹 masaki.hitonishi@dena.com
2. Copyright © DeNA Co.,Ltd. All Rights Reserved.
自己紹介
人西聖樹 (ひとにし まさき)
株式会社 DeNA Games Osaka 2014年 入社
Webアプリケーションエンジニア
シューティングゲーム好き。東方Project 大好き
某400万人ユーザー超えモバイルゲームの
開発やってます
5. Copyright © DeNA Co.,Ltd. All Rights Reserved.
多様な選択肢
RDBMS
MySQL
Oracle
PostgreSQL
KVS
Redis
Riak
カラム指向型
Apache Cassandra
Hbase
ドキュメント指向
MongoDB
Apache CouchDB
etc…
10. Copyright © DeNA Co.,Ltd. All Rights Reserved.
InnoDB における
ギャップロック と
ネクストキーロック
について説明できる人!
11. Copyright © DeNA Co.,Ltd. All Rights Reserved.
本日のテーマ
RDBMS (リレーショナルデータベース) とは
データベース観点でのゲームのデータの特徴
データベース構築時に気をつけること
アプリケーション開発時に気をつけること
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. Copyright © DeNA Co.,Ltd. All Rights Reserved.
ACID特性
Atomicity 原子性
トランザクションの操作は全て実行されるか
まったく実行されないかのどちらか
Consistency 一貫性
トランザクション開始時と終了時にデータの
整合性が保たれる
Isolation 独立性
他のトランザクションによる操作の影響を受けない
Durability 永続性
コミットしたトランザクションのデータは保存される
14. Copyright © DeNA Co.,Ltd. All Rights Reserved.
ゲームデータの特徴
ユーザーを primary key としたレコードが多い
永続データと期間限定データ(イベントのデータ等)がある
マスタデータ(read only)が多い
アイテムマスタ、ボスマスタ、ボス出現マスタ etc…
レコードの状態更新が多い
ボスのHP減少、HP回復、マップ移動 etc…
可用性・整合性は大切
ゲームがプレイできない、アイテムを使用したのに
回復していない等の不具合・障害に対して、
課金しているユーザーの温度感は非常に高い
15. Copyright © DeNA Co.,Ltd. All Rights Reserved.
データベース構築時に考えること
Master/Slave 構成
垂直分割
水平分割
垂直/水平分割はアプリケーション側で対応しないといけない
(MySQL 側に仕組みがない)が後から追加するのは
大変なので最初から考慮して開発する
16. Copyright © DeNA Co.,Ltd. All Rights Reserved.
Master / Slave 構成
Master
Slave Slave Slave
レプリケーション
17. Copyright © DeNA Co.,Ltd. All Rights Reserved.
ゲームは更新系クエリがめちゃ多い
ボタンを押すだけでステータス更新
体力増減とか
ボスへダメージとか
アイテム獲得とか
18. Copyright © DeNA Co.,Ltd. All Rights Reserved.
参照系クエリは Slave に逃せる。
Slave のスケールアウトは容易
更新系クエリは必ず Master にI/O負荷がか
かる → Master はボトルネックになりがち
19. Copyright © DeNA Co.,Ltd. All Rights Reserved.
垂直分割
Aテーブル
Bテーブル
Cテーブル
Dテーブル
Eテーブル
Fテーブル
Gテーブル
Hテーブル
Iテーブル
テーブルの種類によって DB を分割。
Join 句が使えなくなる。
テーブルへのアクセス数が均等になるように分割しないと負荷が偏る
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. Copyright © DeNA Co.,Ltd. All Rights Reserved.
複数のトランザクションを扱う
複数DB へのトランザクションをどう扱うか?
InnoDB の REPEATABLE READ は最初のクエリ発行時に取得できるレ
コードの値が決定するので、各DBに対して最初のクエリをいつ投げる
か意識する必要がある。
コミットタイミングは全て同一で行うのが楽
コミットタイミングが別々だとデータ不整合が起こりやすくなる(片方
はコミット済みなのにもう片方はロールバックとか…
22. Copyright © DeNA Co.,Ltd. All Rights Reserved.
アプリケーション開発時に気をつけること
適切なindexとindexを使える適切なクエリ
クエリ発行量を減らす
行ロック
レプリ遅延対策
Repeatable read の特性
23. Copyright © DeNA Co.,Ltd. All Rights Reserved.
インデックス
InnoDB のインデックスは B+ Tree
常に一定の深度になるようにバランス化された木構造
1レコードの取得に対して O(log N) で探索することができる
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. Copyright © DeNA Co.,Ltd. All Rights Reserved.
オプティマイザ
MySQLはコストベース・オプティマイザ
コストベースのオプティマイザでは、統計情報だけなく
CPUクロック
メモリ容量
DISK I/O速度
DBMSでのパラメータ
で実行計画が決定される
開発環境と同じ実行計画になるとは限らない
データ件数が違う
データの種類が違う
CPUクロックが違う
メモリ容量が違う
など
MySQL のオプティマイザは実行計画を結構見誤る
不安ならばFORCE INDEX で使用するインデックスを指定する
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. 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. Copyright © DeNA Co.,Ltd. All Rights Reserved.
行ロック
同時操作を常に意識する
AさんとBさんが同時にボスを攻撃したら両方ともボスを撃破した扱い
になったり…
Aさんが2端末使って、同時にアイテムを受け取りを押すことでアイテ
ム増殖できたり…
前者は攻撃時にまずボスレコードをロックして、AさんとBさんの処理
を直列させることで防げる
後者はアイテム受け取り時にAさんのレコードをロックして処理を直列
させることで防げる
ロックの順番を統一しないと、デッドロックが発生する。
必ず存在するレコードに対してロックを取る
存在しないレコードをロックすると、InnoDBの Repeatable Read で
は gap lock が発生し、広範囲にロックを獲得する。
→ lock wait timeout
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. Copyright © DeNA Co.,Ltd. All Rights Reserved.
KVSとの併用について
ゲームデータのキャッシュは難しい
更新を頻繁に行うのでキャッシュクリア処理が面倒
忘れると気づきづらい障害に
トランザクションとの整合性
Read Only のデータ(マスタ等)をキャッシュするのが一番楽
31. Copyright © DeNA Co.,Ltd. All Rights Reserved.
ゲームサーバーのデータベースは整合性/負荷と
の戦い
ノウハウを知って急激なアクセス増加にも耐えら
れる構築/開発をしよう
Editor's Notes インデックス効かない場合の解決策
見出しは文字をでっかく