SlideShare a Scribd company logo
1 of 69
DynamoDBによる
    ソーシャルゲーム実装 How
                      To

   2013-03-16 JAWS DAYS 2013 [DEV-02]
   株式会社マイネット
   伊藤 祐策
概要

 『DynamoDB×ソシャゲ』
     をテーマに
 設計と実装のHow To を
惜しむことなく伝授します!
本資料について
以下のURLからいつでもダウンロード可能です


  http://iy-h.com/01/
  読み上げ原稿も置いてあるので
 聞き逃したところがあっても安心!
DynamoDBの紹介
DynamoDBとは?

 Key Value Store型データベース
 NoSQL
     REST   APIでアクセス
   性能課金
     読込性能、書込性能の予約量に応じて時間課
     金
DynamoDBのここがスゴイ

ウルトラスケーラビリ


ティ
 KVS型データベースの最大の強み
 課金すればするほど強くなる!


   超絶耐障害性
 書込み完了と同時に70km以上離れた3箇
    所のデータセンターに分散保存される!
予習
基本的な使い方
   キーを指定してデータへアクセス
     CRUD操作は一通り揃っている
     操作は全てアトミックに処理される

   キーと更新条件を指定してデータを更新する
     データの内容が更新条件に適合しなければ失敗する
     楽観的ロックの実装に必要
他のKVS型DBとの大きな違い
   「レンジキー」というものがある。
   テーブルのキーは以下の2通りから選択できる
     ハッシュキーのみ

     ハッシュキー+レンジキーの組み合わせ
ハッシュキーとは?
   データへアクセスするためのプライマリキー
   ハッシュキーを上手に分散させることができれ
    ば
    概ね課金額通りの性能が得られる。
   逆を言えば、1つのハッシュキーにアクセスが
    集中する設計にしてしまうと、パフォーマンス
    が
    低下してしまう。【重要】
レンジキーとは?
   ハッシュキー+レンジキーでプライマリキーに
    なる
   Queryメソッドで範囲検索が可能になる
       「ハッシュキー」と「レンジキーの範囲」を指定し
        て
        複数レコードをまとめて取得することができる
   レンジキーに対するアクセスを分散しても
    負荷が分散されないことに注意
       ハッシュキーでしっかり分散される設計にしよう
基本的なレコード操作
   CRUD
     PutItem ... 作成/置換
     UpdateItem ... 全部更新/部分更新

     DeleteItem ... 削除

     GetItem ... 取得

   複数レコードの取得
     Query ... 1つのハッシュキーに対する範囲検索
     Scan ... テーブル内の全レコード取得
格納できる値

   値の型は3種類から選べる
     String型
      UTF-8文字列

     Number型
      整数または小数

     Binary型
      用途としては、暗号化されたデータ等
格納できない値

   NULL値
     代わりに属性ごと削除する

   長さ0の文字列
     NULLと同様、属性ごと削除する

   真偽値
     Number型の1と0で代用する
条件付きアップデート
   更新系のメソッドで利用できる
   条件に適合しなければ操作は失敗する
   以下のような条件が指定可能
     「もしレコードが存在しなければ」
     「もしレコードが存在したならば」

     「もしこの属性の値がこの内容と同一であれば」

     「もしこの属性が存在しなければ」
DynamoDBの使いどころ
MySQLの代替手段となり得るか?

   完全には無理。
   以前DynamoDBだけでソーシャルゲーム作って
    みましたが、結論としては色々と無理がある
    のでMySQL等とのハイブリット型にするのが良
    いです。
DynamoDBが苦手なこと
   縦横無尽な検索
     プライマリキー以外のインデックスを張れない
     せいぜいレンジキーで範囲検索ができるくらい

   小規模な集計処理
     集計機能がそもそもないので自前で実装する必要があ
      る
     大規模データならEMR連携という手段が用意されてい
      る
   大きなデータの保存
     1レコードあたり64kBというデータ長制限がある
     素直にS3使いましょう
MySQLとの比較

        DynamoDB   MySQL

データ保全     ◎         ○
検索        ×         ◎
負荷分散      ◎         △
どう使うべきか?
   アプリケーションに要求される機能のうち、
    DynamoDBが苦手なものは他の手段に任せる
     検索はMySQLやCloudSearchへ
     集計はMySQLへ

     大きなデータの保存はS3へ

   残ったものは全てDynamoDBで実装する
MySQLハイブリッド型にする場合

   MySQLのシステムがある日突然消失しても、
    すぐにサービスが再開できるような設計にして
    おく
     MySQL内のデータは全てDynamoDBのデータを本体とし
      たコピーにする。
     データが全て消失しても、MySQLインスタンスを作り
      なおして全データを再投入すれば完全復旧できるよう
      にする。
     「多尐ロストしても構わないデータ」の分別をしっか
      りつけておく
弊社事例
大激闘!キズナバトル
   Androidアプリ
   2012年12月26日リリース
   GvGカードバトル型ゲーム
   最大20人のチームを組んで、
    1日3回開催されるバトルを
    勝ち抜き、最強チームを目指す。
大激闘!キズナバトル
   使用DynamoDBテーブル数は47。
   MySQLとのハイブリット型構成。
   バトル開催時間になるとアクセス量は一気に15倍になる。
                             22時
    1日のアクセス数グラ         19時
    フ
                 12時
DynamoDBの使われ方
   原則全てのデータはDynamoDBで管理
       ユーザー情報
       ユーザーの所有物(カード、アイテム、etc)
       チーム情報
       バトル結果
   MySQLで行なっている処理
       対戦相手のマッチング
       ランキング集計
       チーム検索
       入団希望者検索
実装の基本方針(1)
   ユーザーが1回行動するたびに1レコード作る
       アイテムを使った、カードバトルで対戦した、etc
       ユーザーの行動が全て「証拠」として残されている。
       お問い合わせからクレームが来た時に、何が起こったのかが
        明確に分かるので調査が容易になる。
   レコードは消さない
       保存費用よりWrite性能費用のほうが高い。
         【速報】3月1日にデータ保存料金が75%も値下げされまし
          た!!
       リリース時から全ての歴史が保存されている。
       KVSなのでデータ量がいくら増えてもパフォーマンスに影響
        がない。
実装の基本方針(2)
   ほぼ全ての処理をキューで非同期に実行
       処理が終わるまでのタイムラグは画面エフェクトを表示して待
        たせる
       いかに「ごまかす」かが腕の見せ所
   キャッシュはTAT改善のために使う
       さすがにMemcachedのほうが応答が速い。
       Read性能はかなり安いので節約する意味があまりない。
       m1.smallインスタンス1台の費用でRead性能を366も買えてしま
        う。
テーブル設計
テーブル設計
   スキーマレスだけどスキーマは定義する
   まずはゲームオブジェクトをクラスとして定義
       ユーザー、所有カード、所有アイテム、etc
   1クラス=1スキーマ=1テーブル
       class App_Record_Card extends DynamoDBRecord
   ハッシュキーはユーザーIDで
   レンジキーはオブジェクトインスタンスIDで
       インスタンスIDは日付+時刻+乱数で生成
テーブル定義の例
ユーザー                カード
ユーザーID        100   ユーザーID    100
名前       †ラインハル     インスタンス   1001
             ト†     ID
レベル            15   レベル        10
所有アイテム
ユーザーID        100
所持金         1500G
薬草           32個
実践
残念なお知らせ
   全てのレコード操作メソッドは失敗する可能性がある。
       TCP/IP ネットワークエラーが発生した場合 (結構頻繁)
       Endpoint側に障害が発生した場合 (数回実績あり)
       課金額以上の負荷を与えた場合 (何度もやらかした)
   RDBMSにおける「トランザクション」は提供されていな
    い
       複数レコードを一貫性を保ったまま同時に更新することがで
        きない。
       アプリケーションレイヤで一貫性を保証する実装をしなけれ
        ばならない。
更新対象が1レコードの場合

所有アイテム
ユーザー      100
ID               Case 1:
所持金      1500G
                 薬草を1個購入する
薬草       10個
更新対象が1レコードの場合

所有アイテム                        クエリ内容
ユーザー      100    UpdateItem   ユーザーID     100
ID
                              所持金      -100G
所持金      1500G
                              薬草        +1個
薬草       10個
             【更新条件】
             所持金が1500Gだった
             ら
更新対象が1レコードの場合

所有アイテム
ユーザー       100
ID               更新完了!
所持金      1400G
薬草        11個
更新対象が2レコード以上の場合

所有アイテム           強化対象カード
ユーザー       100   ユーザーID     100
ID
                 インスタンス    1001
所持金      1500G   ID
                 レベル         10
                 素材カード
Case 2:          ユーザーID     100
カードを強化す          インスタンス    1002
る                ID
                 レベル          1
更新対象が2レコード以上の場合

所有アイテム              強化対象カード
ユーザー          100   ユーザーID     100
ID
                    インスタンス    1001
所持金         1500G   ID
                    レベル         10
       更新           素材カード

         削除         ユーザーID     100
素材カードを消費して強化対 インスタンス          1002
象カードのレベルを1上げる。 ID
費用として500G徴収する。 レベル               1
更新対象が2レコード以上の場合

所有アイテム           強化対象カード
ユーザー       100   ユーザーID     100
ID
                 インスタンス    1001
所持金      1000G   ID
                 レベル         10
Step1:           素材カード
所持金 -500G        ユーザーID     100
                 インスタンス    1002
                 ID
                 レベル          1
更新対象が2レコード以上の場合

所有アイテム           強化対象カード
ユーザー       100   ユーザーID     100
ID
                 インスタンス    1001
所持金      1000G   ID
                 レベル         10
Step2:           素材カード
素材カードを削          ユーザーID     100
除                    削除
                 インスタンス    1002
                 ID
                 レベル          1
更新対象が2レコード以上の場合

所有アイテム           強化対象カード
ユーザー       100   ユーザーID     100
ID
                 インスタンス    1001
所持金      1000G   ID
                 レベル         10
Step3:           素材カード
レベル              ユーザーID     100
アッ・・・                削除済
                 インスタンス    1002
                 ID
                 レベル          1
突然の死
更新対象が2レコード以上の場合

所有アイテム           強化対象カード
ユーザー       100   ユーザーID     100
ID
                 インスタンス    1001
所持金      1000G   ID
                 レベル         10
残念!!             素材カード
カードの強化処理         ユーザーID     100
は                    削除済
                 インスタンス    1002
これで終わって          ID
                 レベル          1
しまった!
お問い合わせ内容

【ユーザーID】 100
【ユーザー名】 †ラインハルト†
【日時】2013年3月16日 16:25:58
【お問い合わせ内容】
お金とカードだけ取られた!!!
ふざけんな補償しろ!!!
正しい実装パターン
用意するもの

 Webサーバー
 Batchサーバー

 DynamoDB

   Amazon SQS
システム構成

                     3.Enqueue              4.Dequeue



                                   SQS



1.HTTP Request

                 Web Servers                     Batch Servers



                   2.Put Record             5.Update Records

                                  DynamoD
                                     B
2種類のプロセス
   Webリクエスト処理
     HTTPリクエストをトリガーとして実行される処理
     プロセスはApacheによって実行・管理される

     途中でエラーが発生したら503エラーを返して中断さ
      れる
   キュー処理
     SQSへメッセージを送り、メッセージの取り出しを
      トリガーとして実行される処理。
     プロセスはアプリケーション用のユーザーで実行され
      る
     正常終了するまで何度も繰り返し実行される
Amazon SQSを使う
   SQSは、処理の「完遂保証」のために使う
   失敗した時は何度でも再実行されることを保証さ
    せる
   キュー処理は最終的に正常終了に収束するよう
    実装する
       状態遷移図を書いてしっかり机上デバッグ
           但し書いたら負けかなと思ってる
           図が要らないほどシンプルな実装にしよう
キュー処理実装の鉄則

   再実行耐性を持たせる
     同じ処理が2回実行されても
    結果に影響がでないようにする。
   並列実行耐性を持たせる
     同じ処理が2つ以上のプロセスで並行して
    実行されても結果に影響がでないようにする。
再実行耐性の実装方法
   入力内容から処理内容が全て決定されるようにする。
   レコードの更新をする際に、確かに更新されたことが判
    別できるよう「証拠」を残すようにする。
     更新日時を書き込む、ステータス値を変更する、etc。

     レコード内容をみればどこまで処理が終わったかが
      分かるようにする。
   処理済みであればスキップして次の処理へ進むようにす
    る。
   複雑な分岐をさせず、上から流れ落ちるような処理にす
    る。
並列行耐性の実装方法
   条件付きアップデート機能を用いて楽観的ロックを実装
    する。
   更新する前にレコードを「一貫性あり」で読み込む。
   レコードを更新するときは、「読み込んだ時点から他の
    誰にも更新されていなければ」という条件をつける。
       「条件付きアップデート」を使う
       必要であればレコードにバージョン番号を導入する
   更新に失敗した場合は処理を最初からやりなおす。
     → 再実行耐性が実現されていれば問題ないはず!
処理単位のフローチャート

 GetItem()

             NO        UpdateItem()
  処理済み?
                      with Condition
     YES
             YES
                        更新成功?

                              NO
次の処理へ              throw RetryException
キュー処理全体の流れ

  開始

 処理単位1


 処理単位2   流れ落ちるよう
 処理単位3
         に

  終了
実践・改
カードの強化
所有アイテム           強化対象カード
ユーザー       100   ユーザーID     100
ID
                 インスタンス    1001
所持金      1500G   ID
                 レベル         10
                 素材カード
Case 2':         ユーザーID     100
今度こそ             インスタンス    1002
カードを強化す          ID
る                レベル          1
カードの強化
所有アイテム           カード強化依頼
ユーザー       100   ユーザーID     100
ID
                 依頼ID      5001
所持金      1500G
                 強化対象カード   1001
                 素材対象カード   1002
Step1:           強化費用      500G
依頼レコードを          開始済         NO
作成する
カードの強化
所有アイテム              カード強化依頼
ユーザー          100   ユーザーID     100
ID
                    依頼ID      5001
所持金         1500G
                    強化対象カード   1001
未決済      [ 5001 ]
                    素材対象カード   1002
Step2:
            強化費用              500G
依頼IDを所有アイテム
レコードに登録する   開始済                 NO
※STRING_SET型を使う
カードの強化
強化対象カード              カード強化依頼
ユーザーID         100   ユーザーID     100
インスタンス        1001   依頼ID      5001
ID
                     強化対象カード   1001
レベル             10
                     素材対象カード   1002
未処理       [ 5001 ]
Step3:      強化費用               500G
依頼IDを強化対象カー 開始済                  NO
ド
レコードにも登録する
※STRING_SET型を使う
カードの強化
キューメッセージ           カード強化依頼
処理種別     カード強      ユーザーID     100
             化
                   依頼ID      5001
ユーザー        100
ID                 強化対象カード   1001
依頼ID        5001   素材対象カード   1002
Step4:             強化費用      500G
キューメッセージ           開始済         NO
を発行する
カードの強化(キュー処理)
所有アイテム              カード強化依頼
ユーザー          100   ユーザーID     100
ID
                    依頼ID      5001
所持金         1500G
                    強化対象カード   1001
未決済      [ 5001 ]
                    素材対象カード   1002
Step5:              強化費用      500G
レコードを読み込
                    開始済         NO
む
カードの強化(キュー処理)
所有アイテム               カード強化依頼
ユーザー           100   ユーザーID     100
ID
                     依頼ID      5001
所持金          1500G
                     強化対象カード   1001
未決済      [ 5001 ]
                     素材対象カード   1002
Step6:               強化費用      500G
開始済みにする
※無条件UPDATE           開始済        YES
カードの強化(キュー処理)
所有アイテム             カード強化依頼
ユーザー         100   ユーザーID     100
ID
                   依頼ID      5001
所持金        1000G
                   強化対象カード   1001
未決済       (NULL)
                   素材対象カード   1002
Step7:             強化費用      500G
決済する               開始済        YES
※条件付きUPDATEを使う
カードの強化(キュー処理)
素材カード           カード強化依頼
ユーザーID    100   ユーザーID     100
インスタンス   1002   依頼ID      5001
ID
                強化対象カード   1001
レベル         1
                素材対象カード   1002
Step8:          強化費用      500G
素材カードを削除        開始済        YES
カードの強化(キュー処理)
素材カード           カード強化依頼
ユーザーID    100   ユーザーID     100
    削除
インスタンス   1002   依頼ID      5001
ID
                強化対象カード   1001
レベル         1
                素材対象カード   1002
Step8:          強化費用      500G
素材カードを削除        開始済        YES
カードの強化(キュー処理)
強化対象カード              カード強化依頼
ユーザーID         100   ユーザーID     100
インスタンス        1001   依頼ID      5001
ID
                     強化対象カード   1001
レベル             10
                     素材対象カード   1002
未処理       [ 5001 ]
                     強化費用      500G
Step9:
強化対象カードのパラメー 開始済                YES
タを加算する
※条件付きUPDATEを使う
カードの強化(キュー処理)
強化対象カード              カード強化依頼
ユーザーID         100   ユーザーID     100
インスタンス        1001   依頼ID      5001
ID
                     強化対象カード   1001
レベル             11
                     素材対象カード   1002
未処理       ( NULL )
                     強化費用      500G
Step9:
強化対象カードのパラメー 開始済                YES
タを加算する
※条件付きUPDATEを使う
実装の要点
 完遂保証のない処理(Webリクエスト処理)
  と、
  完遂保証のある処理(キュー処理)で、
  実行すべき処理を上手に振り分ける。
 Webリクエスト処理の途中でエラーが発生
  しても、キュー処理の実行が開始されな
  い限り「何も起こらなかった」ことにな
  る。
     その時は仕方なく503エラーを返す
       各レコードにトランザクションIDが残る可能性につい
終
本資料について(再掲)
以下のURLからいつでもダウンロード可能です


  http://iy-h.com/01/

More Related Content

What's hot

AWSのログ管理ベストプラクティス
AWSのログ管理ベストプラクティスAWSのログ管理ベストプラクティス
AWSのログ管理ベストプラクティスAkihiro Kuwano
 
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]DeNA
 
マルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのことマルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのことAmazon Web Services Japan
 
elixirを使ったゲームサーバ
elixirを使ったゲームサーバelixirを使ったゲームサーバ
elixirを使ったゲームサーバHidetaka Kojo
 
Kongの概要と導入事例
Kongの概要と導入事例Kongの概要と導入事例
Kongの概要と導入事例briscola-tokyo
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」Takuto Wada
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!mosa siru
 
Azure AD とアプリケーションを SAML 連携する際に陥る事例と対処方法について
Azure AD とアプリケーションを SAML 連携する際に陥る事例と対処方法についてAzure AD とアプリケーションを SAML 連携する際に陥る事例と対処方法について
Azure AD とアプリケーションを SAML 連携する際に陥る事例と対処方法についてShinya Yamaguchi
 
ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)
ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)
ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)Amazon Web Services Japan
 
Azure ADと外部アプリのID連携/SSO - Deep Dive
Azure ADと外部アプリのID連携/SSO - Deep DiveAzure ADと外部アプリのID連携/SSO - Deep Dive
Azure ADと外部アプリのID連携/SSO - Deep DiveNaohiro Fujie
 
Amazon DynamoDB(初心者向け 超速マスター編)JAWSUG大阪
Amazon DynamoDB(初心者向け 超速マスター編)JAWSUG大阪Amazon DynamoDB(初心者向け 超速マスター編)JAWSUG大阪
Amazon DynamoDB(初心者向け 超速マスター編)JAWSUG大阪崇之 清水
 
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design PatternAWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design PatternAmazon Web Services Japan
 
サポート エンジニアが Azure Networking をじっくりたっぷり語りつくす会
サポート エンジニアが Azure Networking をじっくりたっぷり語りつくす会サポート エンジニアが Azure Networking をじっくりたっぷり語りつくす会
サポート エンジニアが Azure Networking をじっくりたっぷり語りつくす会ShuheiUda
 
新入社員のための大規模ゲーム開発入門 サーバサイド編
新入社員のための大規模ゲーム開発入門 サーバサイド編新入社員のための大規模ゲーム開発入門 サーバサイド編
新入社員のための大規模ゲーム開発入門 サーバサイド編infinite_loop
 
ソーシャルゲームの為のデータベース設計
ソーシャルゲームの為のデータベース設計ソーシャルゲームの為のデータベース設計
ソーシャルゲームの為のデータベース設計kaminashi
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021Hiroshi Tokumaru
 
Keycloakの実際・翻訳プロジェクト紹介
Keycloakの実際・翻訳プロジェクト紹介Keycloakの実際・翻訳プロジェクト紹介
Keycloakの実際・翻訳プロジェクト紹介Hiroyuki Wada
 
MongoDB〜その性質と利用場面〜
MongoDB〜その性質と利用場面〜MongoDB〜その性質と利用場面〜
MongoDB〜その性質と利用場面〜Naruhiko Ogasawara
 
S13_レガシー ID 管理者でも分かる Verifiable Credentials のセッション [Microsoft Japan Digital D...
S13_レガシー ID 管理者でも分かる Verifiable Credentials のセッション [Microsoft Japan Digital D...S13_レガシー ID 管理者でも分かる Verifiable Credentials のセッション [Microsoft Japan Digital D...
S13_レガシー ID 管理者でも分かる Verifiable Credentials のセッション [Microsoft Japan Digital D...日本マイクロソフト株式会社
 

What's hot (20)

AWSのログ管理ベストプラクティス
AWSのログ管理ベストプラクティスAWSのログ管理ベストプラクティス
AWSのログ管理ベストプラクティス
 
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
 
マルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのことマルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのこと
 
elixirを使ったゲームサーバ
elixirを使ったゲームサーバelixirを使ったゲームサーバ
elixirを使ったゲームサーバ
 
Kongの概要と導入事例
Kongの概要と導入事例Kongの概要と導入事例
Kongの概要と導入事例
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
分散トレーシング技術について(Open tracingやjaeger)
分散トレーシング技術について(Open tracingやjaeger)分散トレーシング技術について(Open tracingやjaeger)
分散トレーシング技術について(Open tracingやjaeger)
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
 
Azure AD とアプリケーションを SAML 連携する際に陥る事例と対処方法について
Azure AD とアプリケーションを SAML 連携する際に陥る事例と対処方法についてAzure AD とアプリケーションを SAML 連携する際に陥る事例と対処方法について
Azure AD とアプリケーションを SAML 連携する際に陥る事例と対処方法について
 
ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)
ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)
ゲームアーキテクチャパターン (Aurora Serverless / DynamoDB)
 
Azure ADと外部アプリのID連携/SSO - Deep Dive
Azure ADと外部アプリのID連携/SSO - Deep DiveAzure ADと外部アプリのID連携/SSO - Deep Dive
Azure ADと外部アプリのID連携/SSO - Deep Dive
 
Amazon DynamoDB(初心者向け 超速マスター編)JAWSUG大阪
Amazon DynamoDB(初心者向け 超速マスター編)JAWSUG大阪Amazon DynamoDB(初心者向け 超速マスター編)JAWSUG大阪
Amazon DynamoDB(初心者向け 超速マスター編)JAWSUG大阪
 
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design PatternAWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
 
サポート エンジニアが Azure Networking をじっくりたっぷり語りつくす会
サポート エンジニアが Azure Networking をじっくりたっぷり語りつくす会サポート エンジニアが Azure Networking をじっくりたっぷり語りつくす会
サポート エンジニアが Azure Networking をじっくりたっぷり語りつくす会
 
新入社員のための大規模ゲーム開発入門 サーバサイド編
新入社員のための大規模ゲーム開発入門 サーバサイド編新入社員のための大規模ゲーム開発入門 サーバサイド編
新入社員のための大規模ゲーム開発入門 サーバサイド編
 
ソーシャルゲームの為のデータベース設計
ソーシャルゲームの為のデータベース設計ソーシャルゲームの為のデータベース設計
ソーシャルゲームの為のデータベース設計
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021
 
Keycloakの実際・翻訳プロジェクト紹介
Keycloakの実際・翻訳プロジェクト紹介Keycloakの実際・翻訳プロジェクト紹介
Keycloakの実際・翻訳プロジェクト紹介
 
MongoDB〜その性質と利用場面〜
MongoDB〜その性質と利用場面〜MongoDB〜その性質と利用場面〜
MongoDB〜その性質と利用場面〜
 
S13_レガシー ID 管理者でも分かる Verifiable Credentials のセッション [Microsoft Japan Digital D...
S13_レガシー ID 管理者でも分かる Verifiable Credentials のセッション [Microsoft Japan Digital D...S13_レガシー ID 管理者でも分かる Verifiable Credentials のセッション [Microsoft Japan Digital D...
S13_レガシー ID 管理者でも分かる Verifiable Credentials のセッション [Microsoft Japan Digital D...
 

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

  • 1. DynamoDBによる ソーシャルゲーム実装 How To  2013-03-16 JAWS DAYS 2013 [DEV-02]  株式会社マイネット  伊藤 祐策
  • 2. 概要 『DynamoDB×ソシャゲ』 をテーマに 設計と実装のHow To を 惜しむことなく伝授します!
  • 3. 本資料について 以下のURLからいつでもダウンロード可能です http://iy-h.com/01/ 読み上げ原稿も置いてあるので 聞き逃したところがあっても安心!
  • 5. DynamoDBとは?  Key Value Store型データベース  NoSQL  REST APIでアクセス  性能課金  読込性能、書込性能の予約量に応じて時間課 金
  • 6. DynamoDBのここがスゴイ ウルトラスケーラビリ  ティ  KVS型データベースの最大の強み  課金すればするほど強くなる!  超絶耐障害性  書込み完了と同時に70km以上離れた3箇 所のデータセンターに分散保存される!
  • 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. 条件付きアップデート  更新系のメソッドで利用できる  条件に適合しなければ操作は失敗する  以下のような条件が指定可能  「もしレコードが存在しなければ」  「もしレコードが存在したならば」  「もしこの属性の値がこの内容と同一であれば」  「もしこの属性が存在しなければ」
  • 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インスタンスを作り なおして全データを再投入すれば完全復旧できるよう にする。  「多尐ロストしても構わないデータ」の分別をしっか りつけておく
  • 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も買えてしま う。
  • 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個
  • 32. 残念なお知らせ  全てのレコード操作メソッドは失敗する可能性がある。  TCP/IP ネットワークエラーが発生した場合 (結構頻繁)  Endpoint側に障害が発生した場合 (数回実績あり)  課金額以上の負荷を与えた場合 (何度もやらかした)  RDBMSにおける「トランザクション」は提供されていな い  複数レコードを一貫性を保ったまま同時に更新することがで きない。  アプリケーションレイヤで一貫性を保証する実装をしなけれ ばならない。
  • 33. 更新対象が1レコードの場合 所有アイテム ユーザー 100 ID Case 1: 所持金 1500G 薬草を1個購入する 薬草 10個
  • 34. 更新対象が1レコードの場合 所有アイテム クエリ内容 ユーザー 100 UpdateItem ユーザーID 100 ID 所持金 -100G 所持金 1500G 薬草 +1個 薬草 10個 【更新条件】 所持金が1500Gだった ら
  • 35. 更新対象が1レコードの場合 所有アイテム ユーザー 100 ID 更新完了! 所持金 1400G 薬草 11個
  • 36. 更新対象が2レコード以上の場合 所有アイテム 強化対象カード ユーザー 100 ユーザーID 100 ID インスタンス 1001 所持金 1500G ID レベル 10 素材カード Case 2: ユーザーID 100 カードを強化す インスタンス 1002 る ID レベル 1
  • 37. 更新対象が2レコード以上の場合 所有アイテム 強化対象カード ユーザー 100 ユーザーID 100 ID インスタンス 1001 所持金 1500G ID レベル 10 更新 素材カード 削除 ユーザーID 100 素材カードを消費して強化対 インスタンス 1002 象カードのレベルを1上げる。 ID 費用として500G徴収する。 レベル 1
  • 38. 更新対象が2レコード以上の場合 所有アイテム 強化対象カード ユーザー 100 ユーザーID 100 ID インスタンス 1001 所持金 1000G ID レベル 10 Step1: 素材カード 所持金 -500G ユーザーID 100 インスタンス 1002 ID レベル 1
  • 39. 更新対象が2レコード以上の場合 所有アイテム 強化対象カード ユーザー 100 ユーザーID 100 ID インスタンス 1001 所持金 1000G ID レベル 10 Step2: 素材カード 素材カードを削 ユーザーID 100 除 削除 インスタンス 1002 ID レベル 1
  • 40. 更新対象が2レコード以上の場合 所有アイテム 強化対象カード ユーザー 100 ユーザーID 100 ID インスタンス 1001 所持金 1000G ID レベル 10 Step3: 素材カード レベル ユーザーID 100 アッ・・・ 削除済 インスタンス 1002 ID レベル 1
  • 42. 更新対象が2レコード以上の場合 所有アイテム 強化対象カード ユーザー 100 ユーザーID 100 ID インスタンス 1001 所持金 1000G ID レベル 10 残念!! 素材カード カードの強化処理 ユーザーID 100 は 削除済 インスタンス 1002 これで終わって ID レベル 1 しまった!
  • 43. お問い合わせ内容 【ユーザーID】 100 【ユーザー名】 †ラインハルト† 【日時】2013年3月16日 16:25:58 【お問い合わせ内容】 お金とカードだけ取られた!!! ふざけんな補償しろ!!!
  • 46. システム構成 3.Enqueue 4.Dequeue SQS 1.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 に 終了
  • 55. カードの強化 所有アイテム 強化対象カード ユーザー 100 ユーザーID 100 ID インスタンス 1001 所持金 1500G ID レベル 10 素材カード Case 2': ユーザーID 100 今度こそ インスタンス 1002 カードを強化す ID る レベル 1
  • 56. カードの強化 所有アイテム カード強化依頼 ユーザー 100 ユーザーID 100 ID 依頼ID 5001 所持金 1500G 強化対象カード 1001 素材対象カード 1002 Step1: 強化費用 500G 依頼レコードを 開始済 NO 作成する
  • 57. カードの強化 所有アイテム カード強化依頼 ユーザー 100 ユーザーID 100 ID 依頼ID 5001 所持金 1500G 強化対象カード 1001 未決済 [ 5001 ] 素材対象カード 1002 Step2: 強化費用 500G 依頼IDを所有アイテム レコードに登録する 開始済 NO ※STRING_SET型を使う
  • 58. カードの強化 強化対象カード カード強化依頼 ユーザーID 100 ユーザーID 100 インスタンス 1001 依頼ID 5001 ID 強化対象カード 1001 レベル 10 素材対象カード 1002 未処理 [ 5001 ] Step3: 強化費用 500G 依頼IDを強化対象カー 開始済 NO ド レコードにも登録する ※STRING_SET型を使う
  • 59. カードの強化 キューメッセージ カード強化依頼 処理種別 カード強 ユーザーID 100 化 依頼ID 5001 ユーザー 100 ID 強化対象カード 1001 依頼ID 5001 素材対象カード 1002 Step4: 強化費用 500G キューメッセージ 開始済 NO を発行する
  • 60. カードの強化(キュー処理) 所有アイテム カード強化依頼 ユーザー 100 ユーザーID 100 ID 依頼ID 5001 所持金 1500G 強化対象カード 1001 未決済 [ 5001 ] 素材対象カード 1002 Step5: 強化費用 500G レコードを読み込 開始済 NO む
  • 61. カードの強化(キュー処理) 所有アイテム カード強化依頼 ユーザー 100 ユーザーID 100 ID 依頼ID 5001 所持金 1500G 強化対象カード 1001 未決済 [ 5001 ] 素材対象カード 1002 Step6: 強化費用 500G 開始済みにする ※無条件UPDATE 開始済 YES
  • 62. カードの強化(キュー処理) 所有アイテム カード強化依頼 ユーザー 100 ユーザーID 100 ID 依頼ID 5001 所持金 1000G 強化対象カード 1001 未決済 (NULL) 素材対象カード 1002 Step7: 強化費用 500G 決済する 開始済 YES ※条件付きUPDATEを使う
  • 63. カードの強化(キュー処理) 素材カード カード強化依頼 ユーザーID 100 ユーザーID 100 インスタンス 1002 依頼ID 5001 ID 強化対象カード 1001 レベル 1 素材対象カード 1002 Step8: 強化費用 500G 素材カードを削除 開始済 YES
  • 64. カードの強化(キュー処理) 素材カード カード強化依頼 ユーザーID 100 ユーザーID 100 削除 インスタンス 1002 依頼ID 5001 ID 強化対象カード 1001 レベル 1 素材対象カード 1002 Step8: 強化費用 500G 素材カードを削除 開始済 YES
  • 65. カードの強化(キュー処理) 強化対象カード カード強化依頼 ユーザーID 100 ユーザーID 100 インスタンス 1001 依頼ID 5001 ID 強化対象カード 1001 レベル 10 素材対象カード 1002 未処理 [ 5001 ] 強化費用 500G Step9: 強化対象カードのパラメー 開始済 YES タを加算する ※条件付きUPDATEを使う
  • 66. カードの強化(キュー処理) 強化対象カード カード強化依頼 ユーザーID 100 ユーザーID 100 インスタンス 1001 依頼ID 5001 ID 強化対象カード 1001 レベル 11 素材対象カード 1002 未処理 ( NULL ) 強化費用 500G Step9: 強化対象カードのパラメー 開始済 YES タを加算する ※条件付きUPDATEを使う
  • 67. 実装の要点  完遂保証のない処理(Webリクエスト処理) と、 完遂保証のある処理(キュー処理)で、 実行すべき処理を上手に振り分ける。  Webリクエスト処理の途中でエラーが発生 しても、キュー処理の実行が開始されな い限り「何も起こらなかった」ことにな る。  その時は仕方なく503エラーを返す  各レコードにトランザクションIDが残る可能性につい
  • 68.