Amazon DynamoDB テーブル 設 計 と 実 践 Tips アマゾンデータサービスジャパン 株 式 会 社 シニアソリューションアーキテクト 安 川 健 太 Session #TA-10 2014 Amazon.com, Inc. and its affiliates. All rights reserved. May not be copied, modified, or distributed in whole or in part without the express consent of Amazon.com, Inc.
自 己 紹 介 安 川 健 太 (@thenkentiest) AWSソリューションアーキテクト 担 当 するお 客 様 の 範 囲 スタートアップ ゲーム ソーシャルサービス 時 々エンタープライズ 好 きなAWSサービス Amazon DynamoDB, Amazon Cognito
Amazon DynamoDBとは NoSQL as a Service 超高速 予測可能な一貫したパフォーマンス シームレスなスケーラビリティと低コスト 運用管理必要なし 低レイテンシ SSD プロビジョンスループット 無限に使えるストレージ ADMIN
Amazon DynamoDBの 特 徴 管 理 不 要 かつ 高 い 可 用 性 と 堅 牢 性 プロビジョンドスループット 容 量 制 限 のないストレージキャパシティ クライアント
ご 利 用 のお 客 様 の 一 部
短期間でのDAUの急上昇もわずかなスケール パラメータの調整で対応 AWSの利用: 人気のドット絵ファンタジー 騎士とドラゴン のインフラ をAWSで運用 ビジネス効果: 少数精鋭で開発を行う中で 運用 面の負担を最小化 ゲームの開発 リソースを最大化
DAUが5,000から30,000に6 日 間 で 跳 ね 上 がった 時 の 作 業 AWS Elastic Beanstalkのインスタンス 数 Amazon DynamoDBのスループット
Amazon DynamoDBに 増 え 続 けるチャットデータを 確 実 に 保 存 しつつ サービスの 成 長 に 備 える AWSの 利 用 : 2012 年 のサービスの 開 始 時 からEC2 上 にシステムを 構 築 課 題 : MySQLとRedisでは 増 え 続 ける 思 い 出 のデータを 保 持 しながらのサービス 成 長 が 難 しい ビジネス 効 果 : Amazon DynamoDBの 導 入 で 増 え 続 け るデータの 心 配 や バックアップやメン テナンスを 考 慮 する 必 要 がなくなった
RedisからAmazon DynamoDBへ Redisは 高 機 能 だがデータ 保 存 容 量 の 単 価 は 高 い タイムスタンプでの 検 索 が 主 用 途 だったので Rangeキーを 用 いた 検 索 で 置 き 換 え EC2 Redis http://timers-tech.hatenablog.com/entry/2013/10/31/232027
Amazon DynamoDBの 基 礎 知 識
TableのKey, Indexとクエリ 操 作 Hash Key Scan + + Global Secondary Index Hash Key + Range Key + Hash Keyを 超 えたQuery Scan Query Local Secondary Index Range Key 以 外 でのQuery
Table 操 作 についての 基 礎 知 識 1 アイテムの 更 新 はアトミックに 可 読 み 込 みの 一 貫 性 は2 種 類 Strongly Consistent Eventually Consistent Filterを 設 定 したScanやQuery
並 列 アクセスの 制 御 Conditional Update Attribute Xの 値 が に 等 しい/ 以 上 / 以 下 だったら などの 条 件 を 付 けた 更 新 Set 型 を 使 う 際 には 値 がSetに 含 まれるかどうかも 条 件 に 設 定 可 Atomic Counter 値 の 加 算 減 算 などの 操 作 を 競 合 なく 実 行 UpdateItemのADDを 利 用
テーブル 設 計 &クエリ 例
ユースケースごとのテーブル 設 計 及 びクエリの 例 1. アプリのイベント 履 歴 管 理 Hash + Range keyの 利 用 例 2. ソーシャル 画 像 共 有 アプリ 複 数 テーブルによるデータモデル LSI GSIの 利 用 例 3. マルチプレーヤゲーム Conditional UpdateとAtomic Counter 4. 投 票 システム Write Sharding
アプリのイベント 履 歴 管 理 ユーザIDをHash Key + Time StampをRange Keyに ユーザごとにTimestampで 範 囲 指 定 してクエリ 可 Your Battle History Charlie 02-25 16:21 Won! Dan 02-24 09:48 Won! Alice 02-21 12:42 Won! Battle History User (Hash) Timestamp (Range) Opponent Alice 2014-07-11 12:21:20 Bob Lost Alice 2014-07-11 12:42:01 Bob Won Alice 2014-07-14 09:48:00 Dan Won Alice 2014-07-15 16:21:11 Charlie Won Result
Amazon DynamoDBのデータも 解 析 に 利 用 Amazon Elastic MapReduce (EMR) で 読 み 出 し Amazon Redshiftで 直 接 読 み 込 み EMRでFilterした 後 Redshiftに 読 み 込 み etc EC2
Time Based Partition Tables Log-2014-July Log-2014-June Log-2013-June COPY Simple Query Delete Table
ソーシャル 画 像 共 有 アプリ Bob Steak! 10:18 Alice Beer! 10:21 Name: Alice Carol BBQ! w/alice 10:12 Dan Riajuee 10:11 Alice BBQ! w/carol 10:12 Alice Starting BBQ! 10:09 Mail: foo Profile: some texts Home My Posts My Profile
テーブル 設 計 2つのテーブルを 定 義 ユーザ 情 報 テーブル 友 達 リストテーブル Friends Table Users Table
友 達 一 覧 を 取 得 Attribute (string, number, binary, set) Users Table Item Primary Key (Hash) User (Hash) Nicknames Bob [ Rob, Bobby ] Alice [ Allie ] Carol [ Caroline ] Dan [ Daniel, Danny ]
友 達 一 覧 を 取 得 Friends Table Users Table User (Hash) Friend (Range) Hash + Range Primary Key User (Hash) Nicknames Bob Alice Bob [ Rob, Bobby ] Alice Bob Alice [ Allie ] Alice Carol Carol [ Caroline ] Alice Dan Dan [ Daniel, Danny ]
友 達 一 覧 を 取 得 Friends Table Users Table User (Hash) Bob Friend (Range) Alice Aliceの 友 達 一 覧 を 取 得 1. Query (Table = Friends, Hash = Alice, Range = *) User (Hash) Nicknames Bob [ Rob, Bobby ] Alice Alice Bob Carol 2. BatchGetItem(Bob, Carol, Dan) Alice [ Allie ] Carol [ Caroline ] Alice Dan Dan [ Daniel, Danny ]
投稿画像の保存と検索 Images Table Bob User Hash) Image Range) Date Link Bob aed4c 2013-10-01 s3:// Bob cf2e2 2013-09-05 s3:// Bob f93bae 2013-10-08 s3:// Alice ca61a 2013-09-12 s3:// Bobの投稿画像一覧を取得 Query (Table=Images, Hash= Bob, Range=*) でもある時刻以降の画像を取得し たかったら?
ある 日 時 の 画 像 取 得 Images Table Local Secondary Index をDateに 張 る User Image Date Link Bob aed4c 2013-10-01 s3:// Bob cf2e2 2013-09-05 s3:// Bob f93bae 2013-10-08 s3:// Alice ca61a 2013-09-12 s3:// Table User Date Image Bob 2013-09-05 cf2e2 Bob 2013-10-01 aed4c Bob 2013-10-08 f93bae Alice 2013-09-12 ca61a ByDate Local Secondary Index
画 像 にユーザのタグ 付 け ImageTags Table Image f93baeにaliceをタグ 付 け PutItem(Table = ImageTags, Hash = f93bae, Range = Alice) Bob Image aed4c aed4c f93bae f93bae User Alice Bob Alice Bob Image f93baeにタグ 付 けされたユーザ 一 覧 Query(Table = ImageTags, Hash = f93bae, Range = *) でもあるユーザがタグ 付 けされて る 画 像 の 一 覧 を 取 得 したかったら?
ユーザのタグ 付 き 画 像 一 覧 ImageTags Table UserにImageをRangeキーとした Global Secondary Indexを 張 る Image (Hash) User (Range) User (Hash) Image (Range) aed4c Alice Bob aed4c aed4c Bob Bob f93bae Bob f93bae f93bae Alice Bob Alice Alice aed4c f93bae Aliceがタグ 付 けされた 画 像 一 覧 Table ByUser Global Secondary Index
マルチプレーヤーバトル Characters designed by Bleed, AnthonyMyers and surt at http://opengameart.org and provided under CC license
RDBでやろうとすると ボスのレコードをロック HPからダメージ 分 を 引 く ボスのレコードを 更 新 ボスのレコードのロックを 解 除 低 遅 延 での 実 行 は 難 しい 上 DBにも 大 きな 負 荷 が
DynamoDBの 場 合 HP > 0を 条 件 にしたConditional Write 成 功 したらダメージ 反 映 完 了 条 件 にあわずに 失 敗 したら 既 に 誰 かが 倒 したってことで 処 理 通 常 の1アイテム 更 新 と 同 じコスト&パフォーマンス!
戦 士 の 攻 撃 Character Status { } Id : fighter123, HP : 250, MP : 100, Attack : 100, Defence : 50, LastHitBy: null { } Id : fighter123, HP : 4890, MP : 800, Attack : 250, Defence : 150, LastHitBy : null
ドラゴンに80のダメージを 与 えた Character Status { } Id : fighter123, HP : 250, MP : 100, Attack : 100, Defence : 50, LastHitBy: Update: HP : -80, LastHitBy: figher123 Expect: HP > 0 { } Id : dragon234, HP : 4810, MP : 800, Attack : 250, Defence : 150, LastHitBy : figher123
魔 法 使 いはいかづちの 杖 を 振 りかざした Character Status { } Id : wizard456, HP : 980, MP : 400, Attack : 20, Defence : 40, LastHitBy: null { } Id : dragon234, HP : 4810, MP : 800, Attack : 250, Defence : 150, LastHitBy : figher123
杖 からいかづちがほとばしる Character Status { } Id : wizard456, HP : 980, MP : 400, Attack : 20, Defence : 40, LastHitBy: null Update: HP : -9999, LastHitBy: wizard456 Expect: HP > 0 { } Id : dragon234, HP : -5189, MP : 800, Attack : 250, Defence : 150, LastHitBy : wizard456
再 び 戦 士 の 攻 撃 Character Status { } Id : fighter123, HP : 250, MP : 100, Attack : 100, Defence : 50, LastHitBy: Update: HP : -78, LastHitBy: figher123 Expect: HP > 0 { } Id : dragon234, HP : -5189, MP : 800, Attack : 250, Defence : 150, LastHitBy : wizard456 ConditionalCheckFailedException
投 票 システム 投 票 者 候 補 者 A 得 票 数 : 20 Votes Table 候 補 者 B 得 票 数 : 30
投 票 システム 投 票 者 UpdateItem ADD 1 to 候 補 者 A 候 補 者 A 得 票 数 : 21 Votes Table 候 補 者 B 得 票 数 : 30
投 票 に 備 えてDynamoDBをスケール 投 票 者 200,000 Write Capacity Unitsをプロビジョニング Partition 1 600 writes/s Partition L 600 writes/s Partition M 600 writes/s Partition N 600 writes/s Votes Table
パーティションへのアクセスに 偏 り 投 票 者 Partition 1 600 writes/s Partition L 600 writes/s Partition M 600 writes/s Partition N 600 writes/s 候 補 者 A Votes Table 候 補 者 B
Write ShardingでPartition 負 荷 を 分 散 候 補 者 IDにランダムなSuffixをつけて 書 き 込 み 候 補 者 ID 得 票 数 投 票 者 候 補 者 Aに 投 票 +1 候 補 者 A_ + rand(0, 10) +1 候 補 者 A_0 1,848 候 補 者 A_1 2,183 候 補 者 B_0 4,084 集 計 時 は 全 Suffixにクエリ 候 補 者 B_1 3,984
Write Shardingした 上 での 投 票 投 票 者 UpdateItem: 候 補 者 A_ + rand(0, 10) ADD 1 to 得 票 数 候 補 者 A_1 候 補 者 A_4 候 補 者 A_7 候 補 者 B_1 候 補 者 B_4 候 補 者 B_5 候 補 者 B_8 候 補 者 A_2 候 補 者 A_3 候 補 者 A_5 候 補 者 B_3 候 補 者 B_7 候 補 者 A_6 候 補 者 A_8 Votes Table 候 補 者 B_2 候 補 者 B_6
Write Shardingした 場 合 の 集 計 バッチ プロセス 1. 合 算 2. 保 存 投 票 者 候 補 者 A_1 候 補 者 A_4 候 補 者 A_7 候 補 者 A Total: 2.5M 候 補 者 B_1 候 補 者 B_4 候 補 者 B_5 候 補 者 B_8 候 補 者 A_2 候 補 者 A_3 候 補 者 A_5 候 補 者 B_3 候 補 者 B_7 候 補 者 A_6 候 補 者 A_8 Votes Table 候 補 者 B_2 候 補 者 B_6
まとめ ユーザの 行 動 履 歴 Hash+Range Key Time Based Partition Table ソーシャル 画 像 共 有 アプリ Index Table LSI / GSI マルチプレーヤーバトル Conditional Update + Atomic Counter 投 票 システム Write Sharding
2014.09.09 SAVE THE DATE http://csd.awseventsjapan.com/ Cloud Storage & DB Day 検 索