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