Your SlideShare is downloading. ×
DynamoDBによるソーシャルゲーム実装 How To
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

DynamoDBによるソーシャルゲーム実装 How To

13,563
views

Published on

JAWS DAYS 2013 [DEV-02] …

JAWS DAYS 2013 [DEV-02]
http://jaws-ug.jp/jawsdays2013/


0 Comments
72 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
13,563
On Slideshare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
Downloads
79
Comments
0
Likes
72
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. DynamoDBによる ソーシャルゲーム実装 How To 2013-03-16 JAWS DAYS 2013 [DEV-02] 株式会社マイネット 伊藤 祐策
  • 2. 概要 『DynamoDB×ソシャゲ』 をテーマに 設計と実装のHow To を惜しむことなく伝授します!
  • 3. 本資料について以下のURLからいつでもダウンロード可能です http://iy-h.com/01/ 読み上げ原稿も置いてあるので 聞き逃したところがあっても安心!
  • 4. DynamoDBの紹介
  • 5. DynamoDBとは? Key Value Store型データベース NoSQL  REST APIでアクセス 性能課金  読込性能、書込性能の予約量に応じて時間課 金
  • 6. DynamoDBのここがスゴイウルトラスケーラビリティ KVS型データベースの最大の強み 課金すればするほど強くなる! 超絶耐障害性 書込み完了と同時に70km以上離れた3箇 所のデータセンターに分散保存される!
  • 7. 予習
  • 8. 基本的な使い方 キーを指定してデータへアクセス  CRUD操作は一通り揃っている  操作は全てアトミックに処理される キーと更新条件を指定してデータを更新する  データの内容が更新条件に適合しなければ失敗する  楽観的ロックの実装に必要
  • 9. 他のKVS型DBとの大きな違い 「レンジキー」というものがある。 テーブルのキーは以下の2通りから選択できる  ハッシュキーのみ  ハッシュキー+レンジキーの組み合わせ
  • 10. ハッシュキーとは? データへアクセスするためのプライマリキー ハッシュキーを上手に分散させることができれ ば 概ね課金額通りの性能が得られる。 逆を言えば、1つのハッシュキーにアクセスが 集中する設計にしてしまうと、パフォーマンス が 低下してしまう。【重要】
  • 11. レンジキーとは? ハッシュキー+レンジキーでプライマリキーに なる Queryメソッドで範囲検索が可能になる  「ハッシュキー」と「レンジキーの範囲」を指定し て 複数レコードをまとめて取得することができる レンジキーに対するアクセスを分散しても 負荷が分散されないことに注意  ハッシュキーでしっかり分散される設計にしよう
  • 12. 基本的なレコード操作 CRUD  PutItem ... 作成/置換  UpdateItem ... 全部更新/部分更新  DeleteItem ... 削除  GetItem ... 取得 複数レコードの取得  Query ... 1つのハッシュキーに対する範囲検索  Scan ... テーブル内の全レコード取得
  • 13. 格納できる値 値の型は3種類から選べる  String型  UTF-8文字列  Number型  整数または小数  Binary型  用途としては、暗号化されたデータ等
  • 14. 格納できない値 NULL値  代わりに属性ごと削除する 長さ0の文字列  NULLと同様、属性ごと削除する 真偽値  Number型の1と0で代用する
  • 15. 条件付きアップデート 更新系のメソッドで利用できる 条件に適合しなければ操作は失敗する 以下のような条件が指定可能  「もしレコードが存在しなければ」  「もしレコードが存在したならば」  「もしこの属性の値がこの内容と同一であれば」  「もしこの属性が存在しなければ」
  • 16. DynamoDBの使いどころ
  • 17. MySQLの代替手段となり得るか? 完全には無理。 以前DynamoDBだけでソーシャルゲーム作って みましたが、結論としては色々と無理がある のでMySQL等とのハイブリット型にするのが良 いです。
  • 18. DynamoDBが苦手なこと 縦横無尽な検索  プライマリキー以外のインデックスを張れない  せいぜいレンジキーで範囲検索ができるくらい 小規模な集計処理  集計機能がそもそもないので自前で実装する必要があ る  大規模データならEMR連携という手段が用意されてい る 大きなデータの保存  1レコードあたり64kBというデータ長制限がある  素直にS3使いましょう
  • 19. MySQLとの比較 DynamoDB MySQLデータ保全 ◎ ○検索 × ◎負荷分散 ◎ △
  • 20. どう使うべきか? アプリケーションに要求される機能のうち、 DynamoDBが苦手なものは他の手段に任せる  検索はMySQLやCloudSearchへ  集計はMySQLへ  大きなデータの保存はS3へ 残ったものは全てDynamoDBで実装する
  • 21. MySQLハイブリッド型にする場合 MySQLのシステムがある日突然消失しても、 すぐにサービスが再開できるような設計にして おく  MySQL内のデータは全てDynamoDBのデータを本体とし たコピーにする。  データが全て消失しても、MySQLインスタンスを作り なおして全データを再投入すれば完全復旧できるよう にする。  「多尐ロストしても構わないデータ」の分別をしっか りつけておく
  • 22. 弊社事例
  • 23. 大激闘!キズナバトル Androidアプリ 2012年12月26日リリース GvGカードバトル型ゲーム 最大20人のチームを組んで、 1日3回開催されるバトルを 勝ち抜き、最強チームを目指す。
  • 24. 大激闘!キズナバトル 使用DynamoDBテーブル数は47。 MySQLとのハイブリット型構成。 バトル開催時間になるとアクセス量は一気に15倍になる。 22時 1日のアクセス数グラ 19時 フ 12時
  • 25. DynamoDBの使われ方 原則全てのデータはDynamoDBで管理  ユーザー情報  ユーザーの所有物(カード、アイテム、etc)  チーム情報  バトル結果 MySQLで行なっている処理  対戦相手のマッチング  ランキング集計  チーム検索  入団希望者検索
  • 26. 実装の基本方針(1) ユーザーが1回行動するたびに1レコード作る  アイテムを使った、カードバトルで対戦した、etc  ユーザーの行動が全て「証拠」として残されている。  お問い合わせからクレームが来た時に、何が起こったのかが 明確に分かるので調査が容易になる。 レコードは消さない  保存費用よりWrite性能費用のほうが高い。  【速報】3月1日にデータ保存料金が75%も値下げされまし た!!  リリース時から全ての歴史が保存されている。  KVSなのでデータ量がいくら増えてもパフォーマンスに影響 がない。
  • 27. 実装の基本方針(2) ほぼ全ての処理をキューで非同期に実行  処理が終わるまでのタイムラグは画面エフェクトを表示して待 たせる  いかに「ごまかす」かが腕の見せ所 キャッシュはTAT改善のために使う  さすがにMemcachedのほうが応答が速い。  Read性能はかなり安いので節約する意味があまりない。  m1.smallインスタンス1台の費用でRead性能を366も買えてしま う。
  • 28. テーブル設計
  • 29. テーブル設計 スキーマレスだけどスキーマは定義する まずはゲームオブジェクトをクラスとして定義  ユーザー、所有カード、所有アイテム、etc 1クラス=1スキーマ=1テーブル  class App_Record_Card extends DynamoDBRecord ハッシュキーはユーザーIDで レンジキーはオブジェクトインスタンスIDで  インスタンスIDは日付+時刻+乱数で生成
  • 30. テーブル定義の例ユーザー カードユーザーID 100 ユーザーID 100名前 †ラインハル インスタンス 1001 ト† IDレベル 15 レベル 10所有アイテムユーザーID 100所持金 1500G薬草 32個
  • 31. 実践
  • 32. 残念なお知らせ 全てのレコード操作メソッドは失敗する可能性がある。  TCP/IP ネットワークエラーが発生した場合 (結構頻繁)  Endpoint側に障害が発生した場合 (数回実績あり)  課金額以上の負荷を与えた場合 (何度もやらかした) RDBMSにおける「トランザクション」は提供されていな い  複数レコードを一貫性を保ったまま同時に更新することがで きない。  アプリケーションレイヤで一貫性を保証する実装をしなけれ ばならない。
  • 33. 更新対象が1レコードの場合所有アイテムユーザー 100ID Case 1:所持金 1500G 薬草を1個購入する薬草 10個
  • 34. 更新対象が1レコードの場合所有アイテム クエリ内容ユーザー 100 UpdateItem ユーザーID 100ID 所持金 -100G所持金 1500G 薬草 +1個薬草 10個 【更新条件】 所持金が1500Gだった ら
  • 35. 更新対象が1レコードの場合所有アイテムユーザー 100ID 更新完了!所持金 1400G薬草 11個
  • 36. 更新対象が2レコード以上の場合所有アイテム 強化対象カードユーザー 100 ユーザーID 100ID インスタンス 1001所持金 1500G ID レベル 10 素材カードCase 2: ユーザーID 100カードを強化す インスタンス 1002る ID レベル 1
  • 37. 更新対象が2レコード以上の場合所有アイテム 強化対象カードユーザー 100 ユーザーID 100ID インスタンス 1001所持金 1500G ID レベル 10 更新 素材カード 削除 ユーザーID 100素材カードを消費して強化対 インスタンス 1002象カードのレベルを1上げる。 ID費用として500G徴収する。 レベル 1
  • 38. 更新対象が2レコード以上の場合所有アイテム 強化対象カードユーザー 100 ユーザーID 100ID インスタンス 1001所持金 1000G ID レベル 10Step1: 素材カード所持金 -500G ユーザーID 100 インスタンス 1002 ID レベル 1
  • 39. 更新対象が2レコード以上の場合所有アイテム 強化対象カードユーザー 100 ユーザーID 100ID インスタンス 1001所持金 1000G ID レベル 10Step2: 素材カード素材カードを削 ユーザーID 100除 削除 インスタンス 1002 ID レベル 1
  • 40. 更新対象が2レコード以上の場合所有アイテム 強化対象カードユーザー 100 ユーザーID 100ID インスタンス 1001所持金 1000G ID レベル 10Step3: 素材カードレベル ユーザーID 100アッ・・・ 削除済 インスタンス 1002 ID レベル 1
  • 41. 突然の死
  • 42. 更新対象が2レコード以上の場合所有アイテム 強化対象カードユーザー 100 ユーザーID 100ID インスタンス 1001所持金 1000G ID レベル 10残念!! 素材カードカードの強化処理 ユーザーID 100は 削除済 インスタンス 1002これで終わって ID レベル 1しまった!
  • 43. お問い合わせ内容【ユーザーID】 100【ユーザー名】 †ラインハルト†【日時】2013年3月16日 16:25:58【お問い合わせ内容】お金とカードだけ取られた!!!ふざけんな補償しろ!!!
  • 44. 正しい実装パターン
  • 45. 用意するもの Webサーバー Batchサーバー DynamoDB Amazon SQS
  • 46. システム構成 3.Enqueue 4.Dequeue SQS1.HTTP Request Web Servers Batch Servers 2.Put Record 5.Update Records DynamoD B
  • 47. 2種類のプロセス Webリクエスト処理  HTTPリクエストをトリガーとして実行される処理  プロセスはApacheによって実行・管理される  途中でエラーが発生したら503エラーを返して中断さ れる キュー処理  SQSへメッセージを送り、メッセージの取り出しを トリガーとして実行される処理。  プロセスはアプリケーション用のユーザーで実行され る  正常終了するまで何度も繰り返し実行される
  • 48. Amazon SQSを使う SQSは、処理の「完遂保証」のために使う 失敗した時は何度でも再実行されることを保証さ せる キュー処理は最終的に正常終了に収束するよう 実装する  状態遷移図を書いてしっかり机上デバッグ  但し書いたら負けかなと思ってる  図が要らないほどシンプルな実装にしよう
  • 49. キュー処理実装の鉄則 再実行耐性を持たせる  同じ処理が2回実行されても 結果に影響がでないようにする。 並列実行耐性を持たせる  同じ処理が2つ以上のプロセスで並行して 実行されても結果に影響がでないようにする。
  • 50. 再実行耐性の実装方法 入力内容から処理内容が全て決定されるようにする。 レコードの更新をする際に、確かに更新されたことが判 別できるよう「証拠」を残すようにする。  更新日時を書き込む、ステータス値を変更する、etc。  レコード内容をみればどこまで処理が終わったかが 分かるようにする。 処理済みであればスキップして次の処理へ進むようにす る。 複雑な分岐をさせず、上から流れ落ちるような処理にす る。
  • 51. 並列行耐性の実装方法 条件付きアップデート機能を用いて楽観的ロックを実装 する。 更新する前にレコードを「一貫性あり」で読み込む。 レコードを更新するときは、「読み込んだ時点から他の 誰にも更新されていなければ」という条件をつける。  「条件付きアップデート」を使う  必要であればレコードにバージョン番号を導入する 更新に失敗した場合は処理を最初からやりなおす。 → 再実行耐性が実現されていれば問題ないはず!
  • 52. 処理単位のフローチャート GetItem() NO UpdateItem() 処理済み? with Condition YES YES 更新成功? NO次の処理へ throw RetryException
  • 53. キュー処理全体の流れ 開始 処理単位1 処理単位2 流れ落ちるよう 処理単位3 に 終了
  • 54. 実践・改
  • 55. カードの強化所有アイテム 強化対象カードユーザー 100 ユーザーID 100ID インスタンス 1001所持金 1500G ID レベル 10 素材カードCase 2: ユーザーID 100今度こそ インスタンス 1002カードを強化す IDる レベル 1
  • 56. カードの強化所有アイテム カード強化依頼ユーザー 100 ユーザーID 100ID 依頼ID 5001所持金 1500G 強化対象カード 1001 素材対象カード 1002Step1: 強化費用 500G依頼レコードを 開始済 NO作成する
  • 57. カードの強化所有アイテム カード強化依頼ユーザー 100 ユーザーID 100ID 依頼ID 5001所持金 1500G 強化対象カード 1001未決済 [ 5001 ] 素材対象カード 1002Step2: 強化費用 500G依頼IDを所有アイテムレコードに登録する 開始済 NO※STRING_SET型を使う
  • 58. カードの強化強化対象カード カード強化依頼ユーザーID 100 ユーザーID 100インスタンス 1001 依頼ID 5001ID 強化対象カード 1001レベル 10 素材対象カード 1002未処理 [ 5001 ]Step3: 強化費用 500G依頼IDを強化対象カー 開始済 NOドレコードにも登録する※STRING_SET型を使う
  • 59. カードの強化キューメッセージ カード強化依頼処理種別 カード強 ユーザーID 100 化 依頼ID 5001ユーザー 100ID 強化対象カード 1001依頼ID 5001 素材対象カード 1002Step4: 強化費用 500Gキューメッセージ 開始済 NOを発行する
  • 60. カードの強化(キュー処理)所有アイテム カード強化依頼ユーザー 100 ユーザーID 100ID 依頼ID 5001所持金 1500G 強化対象カード 1001未決済 [ 5001 ] 素材対象カード 1002Step5: 強化費用 500Gレコードを読み込 開始済 NOむ
  • 61. カードの強化(キュー処理)所有アイテム カード強化依頼ユーザー 100 ユーザーID 100ID 依頼ID 5001所持金 1500G 強化対象カード 1001未決済 [ 5001 ] 素材対象カード 1002Step6: 強化費用 500G開始済みにする※無条件UPDATE 開始済 YES
  • 62. カードの強化(キュー処理)所有アイテム カード強化依頼ユーザー 100 ユーザーID 100ID 依頼ID 5001所持金 1000G 強化対象カード 1001未決済 (NULL) 素材対象カード 1002Step7: 強化費用 500G決済する 開始済 YES※条件付きUPDATEを使う
  • 63. カードの強化(キュー処理)素材カード カード強化依頼ユーザーID 100 ユーザーID 100インスタンス 1002 依頼ID 5001ID 強化対象カード 1001レベル 1 素材対象カード 1002Step8: 強化費用 500G素材カードを削除 開始済 YES
  • 64. カードの強化(キュー処理)素材カード カード強化依頼ユーザーID 100 ユーザーID 100 削除インスタンス 1002 依頼ID 5001ID 強化対象カード 1001レベル 1 素材対象カード 1002Step8: 強化費用 500G素材カードを削除 開始済 YES
  • 65. カードの強化(キュー処理)強化対象カード カード強化依頼ユーザーID 100 ユーザーID 100インスタンス 1001 依頼ID 5001ID 強化対象カード 1001レベル 10 素材対象カード 1002未処理 [ 5001 ] 強化費用 500GStep9:強化対象カードのパラメー 開始済 YESタを加算する※条件付きUPDATEを使う
  • 66. カードの強化(キュー処理)強化対象カード カード強化依頼ユーザーID 100 ユーザーID 100インスタンス 1001 依頼ID 5001ID 強化対象カード 1001レベル 11 素材対象カード 1002未処理 ( NULL ) 強化費用 500GStep9:強化対象カードのパラメー 開始済 YESタを加算する※条件付きUPDATEを使う
  • 67. 実装の要点 完遂保証のない処理(Webリクエスト処理) と、 完遂保証のある処理(キュー処理)で、 実行すべき処理を上手に振り分ける。 Webリクエスト処理の途中でエラーが発生 しても、キュー処理の実行が開始されな い限り「何も起こらなかった」ことにな る。  その時は仕方なく503エラーを返す  各レコードにトランザクションIDが残る可能性につい
  • 68.
  • 69. 本資料について(再掲)以下のURLからいつでもダウンロード可能です http://iy-h.com/01/