ソシャゲ開発経験から学んだゲームに Redis を使う際の Tips


近年の KVS では割と Redis が覇権を取っていることもあり(当社比),
社内の多くのプロジェクトで Redis を使用するようになりました.
ということでノウハウ的なのも溜まってきたのでまとめたいと思います.

(大量のユーザーデータを扱うソシャゲにしか当てはまらない部分もあるかと思います)

単純にパフォーマンスを RDB < Redis と思い込んでとりあえずでキャッシュしない

「Redis は速い」と言われますが, インデックスをちゃんと貼った RDB のクエリも
そこまで遅いわけではありません. 結局通信コストの方が遥かに大きいので内部の
取得時間差はトータルで考えると多くの場合誤差です.
特に RDB の主キーのみで取得できるようなデータを Redis にキャッシュすることに
メリットはありません. キャッシュするコードを書くコストの方が高くつきます.
キャッシュするのは RDB の複数テーブルを参照しなければならないような時間のかかる
かつアクセス頻度が高いクエリに対してしましょう.

基本的に Expire はつける

Redis はデータを永続化できることも特徴ですが, 逆に言えば消えないためディスク容量は
どんどん圧迫していきます. 永続性が必要ないものについては Expire を付けることにより
ディスクが食いつぶされるのを幾分か防ぐことができます. 特にキャッシュの場合は必須.

そもそも容量を圧迫しないように設計する

Expire はあくまで有効期限なので短期間に大量アクセスが来ればデータ設計によっては
やはり容量不足になることもあります. なのでそうそうデータが爆発しないように設計しておきましょう.
ユーザーが何かアクションする度にレコード増えるような設計は NG です.
(ユーザーがクエストに行く度に1レコード増えるとか)

基本的にユーザーと機能に対してデータ量が 1:1 になるようにしておけば, データ量が一気に
増加しにくいしデータ量の把握もしやすいです.
(少し前のゲームによく見られた, 「1日1回フレンドにあいさつする」, という機能で
1あいさつ1レコード作っていたのでKVSの容量がヤバいことになった, という事例があったそうな)

永続データ

Redis と RDB のデータを同時一括更新しないようにする

Redis のデータと RDB のデータの同時更新でエラーが起きた場合, RDB のデータは
トランザクションに守られていますが, Redis のデータは手動ロールバックが必要になります.
実装的にもメンテナンス性にしてもよろしくないので最大限避けるべきです.

そもそもエラー時にロールバックしなければならないようなデータを Redis に入れるのを
避けるべきかもしれません. エラーが出たらそのデータは一旦削除, くらいの気軽さがあった方がいろいろ楽.

Redis にユーザーの永続データを入れるのを避ける

前項目に若干関係しますが, ユーザーの永続データは入れない方がいいです. ユーザー数は
広告効果等である日大量に増加したりするので思わぬところで負債が産まれたりします.

(RDB の負荷分散はバッチリだったけど Redis の負荷分散は考えてなかった! とか.
負荷分散するにはデータを一旦消さなきゃ!でもユーザーデータだから消せないorz!とか)

そもそも RDB があるのにわざわざ Redis を永続データの保存先に使う必要は基本的にないはずです.
(でもちょっとしたパラメータが気づいたらなぜか Redis のみに保存されるようになってたりする. git blame しなきゃ)

ユーザーデータでない永続データは設定系ですかね...(例が出ない)
ユーザーデータ以外なら開発側である程度データ量の制御ができるので便利に使えるなら使ってもよいかと.

ゲームにおける Redis の使い所

キャッシュ

KVS なのでキャッシュが一番に思いつきますが, 前述の通りキャッシュ対象は吟味しましょう.
もちろん Expire 必須!
あと負荷が高い時はスケールアウトできるようにしておくといいです. Redis はスケールアップより
スケールアウトの方が効果が高い気がします.
(シングルスレッドだからかコア数とか増やしてもそこまでパフォーマンス上がらなかった経験)
各言語の Redis ライブラリも割とシャーディング対応してます. 大体がキーのハッシュ値から
各シャードに振り分ける実装になっているためキャッシュサーバーの増減もしやすいです.

ランキング

ソート済みセットを使ったランキング実装は Redis の有効な使い方です.
各ユーザーのポイントは DB に保存してあるはずなので何かあったら
ランキングは集計し直せばいいだけという点も good !
同点問題?管轄外です

レイド(みんなでボスを殴るやつ)

複数ユーザーで一体のボスを倒すようなのはボスの体力減少のレースコンディションがやっかいですが,
Redis の incrby, decrby はアトミックなためみんなで一斉に殴っても大丈夫. やったぜ.

最後に

以上になります. Redis は便利ですがデータの保存先としては RDB に寄せた方が運用しやすいです.
Redis の中身は吹っ飛んでも最悪作り直せば OK という設計にしておくと精神的に楽です.
(別にRedis のデータが吹っ飛びやすいとか言ってるのではなく, 死守しなきゃならないものが多いと大変ということです)