Slide 1

Slide 1 text

DynamoDB のインデックス再編事例

Slide 2

Slide 2 text

自己紹介 丹羽 一智 携帯電話向けのゲームおよびサーバ開発業務 ニンテンドー3DSのOS開発 ゲームサーバの開発・運用 Nintendo Switchのサーバシステム設計 設立 代表取締役 に就任 2006 2009 2016

Slide 3

Slide 3 text

会社概要 事業内容 ゲームをメインターゲットとした BaaS を提供。 (ゲーム以外も応用できるので、他業種でも是非触ってみてください) 代表的なゲーム関連企業の株主 DeNA KLab Venture Partners ワンダープラネット

Slide 4

Slide 4 text

このセッション is 何

Slide 5

Slide 5 text

DynamoDB の知見を共有 DynamoDB の知見としてテーブル構成の Best Practice を共有 するのが目的。 みんなが DynamoDB を使いこなせるようになるといいな!

Slide 6

Slide 6 text

アジェンダ 1. 動機および事例に関する個別事情 2. 新テーブルを準備 3. 新テーブルに同期 4. 新テーブルに切り替え 5. インデックス問題を回避するために

Slide 7

Slide 7 text

動機および事例に関する個別事情

Slide 8

Slide 8 text

インデックス設計に失敗 DynamoDB の Local Secondary Index はテーブルの作成時にし か作れない。 しかし、後になって追加したくなるものです

Slide 9

Slide 9 text

元々のテーブル構成 テナントA テナントB マイクロサービスA + テナントA 用テーブル マイクロサービスB + テナントA 用テーブル マイクロサービスB + テナントB 用テーブル マイクロサービスA マイクロサービスB

Slide 10

Slide 10 text

元々のテーブル構成 テナントA テナントB マイクロサービスA + テナントA 用テーブル マイクロサービスB + テナントA 用テーブル マイクロサービスB + テナントB 用テーブル マイクロサービスA マイクロサービスB テナント×(利用されている)マイクロサービス のテーブルが存在 合計 2,000 テーブル以上

Slide 11

Slide 11 text

新テーブルを準備

Slide 12

Slide 12 text

流れはRDBMSのシャーディングと同じ DynamoDB のテーブル移行は基本的には RDBMS のシャーディ ングと同じです。

Slide 13

Slide 13 text

インデックスを変更したテーブルを用意 マイクロサービスA + テナントA 用テーブル マイクロサービスB + テナントA 用テーブル マイクロサービスB + テナントB 用テーブル マイクロサービスA + テナントA 用テーブル’ マイクロサービスB + テナントA 用テーブル’ マイクロサービスB + テナントB 用テーブル’

Slide 14

Slide 14 text

新テーブルに同期

Slide 15

Slide 15 text

新しいデータの同期の方法は2種類ある 1. DynamoDB Stream を使用した同期 2. トランザクションを使用した同期

Slide 16

Slide 16 text

DynamoDB Stream マイクロサービスA + テナントA 用テーブル マイクロサービスB + テナントA 用テーブル マイクロサービスB + テナントB 用テーブル マイクロサービスA + テナントA 用テーブル’ マイクロサービスB + テナントA 用テーブル’ マイクロサービスB + テナントB 用テーブル’ 作成・更新・削除 作成・更新・削除

Slide 17

Slide 17 text

トランザクション マイクロサービスA + テナントA 用テーブル マイクロサービスA + テナントA 用テーブル’ 作成・更新・削除

Slide 18

Slide 18 text

トランザクション マイクロサービスA + テナントA 用テーブル マイクロサービスA + テナントA 用テーブル’ 作成・更新・削除 今回はトランザクションを採用

Slide 19

Slide 19 text

Why 2,000テーブルもあるから (DynamoDB の制限にはストリームの数の明記はないけど、 何かあるかもしれない)

Slide 20

Slide 20 text

古いデータの同期の方法も2種類ある 1. DynamoDB Stream を使用した同期 2. プログラムを使用した同期

Slide 21

Slide 21 text

DynamoDB Stream マイクロサービスA + テナントA 用テーブル マイクロサービスB + テナントA 用テーブル マイクロサービスB + テナントB 用テーブル マイクロサービスA + テナントA 用テーブル’ マイクロサービスB + テナントA 用テーブル’ マイクロサービスB + テナントB 用テーブル’ どうでもいい更新 作成

Slide 22

Slide 22 text

プログラム マイクロサービスA + テナントA 用テーブル マイクロサービスA + テナントA 用テーブル’ 読み取り プログラム 作成

Slide 23

Slide 23 text

新テーブルに切替

Slide 24

Slide 24 text

プログラム マイクロサービスA + テナントA 用テーブル マイクロサービスA + テナントA 用テーブル’ マイクロサービスA 作成・更新・削除

Slide 25

Slide 25 text

インデックス問題を回避するために

Slide 26

Slide 26 text

毎回こんなことやってられない 新しいテーブル設計では先にインデックスを作るように accountId S HASH_KEY uniqueName S RANGE_KEY status S LSI1 createdAt N LSI2 __parent_key__ S HASH_KEY __key__ S RANGE_KEY __lsi_range_key1__ S LSI1(status のコピー) __lsi_range_key2__ S LSI2(createdAt のコピー) __lsi_range_key3__ S LSI3(値なし) __lsi_range_key4__ S LSI4(値なし) __lsi_range_key5__ S LSI5(値なし) accountId S uniqueName S status S createdAt N

Slide 27

Slide 27 text

毎回こんなことやってられない 新しいテーブル設計では先にインデックスを作るように accountId S HASH_KEY uniqueName S RANGE_KEY status S LSI1 createdAt N LSI2 __parent_key__ S HASH_KEY __key__ S RANGE_KEY __lsi_range_key1__ S LSI1(status のコピー) __lsi_range_key2__ S LSI2(createdAt のコピー) __lsi_range_key3__ S LSI3(値なし) __lsi_range_key4__ S LSI4(値なし) __lsi_range_key5__ S LSI5(値なし) accountId S uniqueName S status S createdAt N 先にインデックス用の列を定義しておく 使いたくなったら、値を入れ始めればいい

Slide 28

Slide 28 text

毎回こんなことやってられない 新しいテーブル設計では先にインデックスを作るように accountId S HASH_KEY uniqueName S RANGE_KEY status S LSI1 createdAt N LSI2 __parent_key__ S HASH_KEY __key__ S RANGE_KEY __lsi_range_key1__ S LSI1(status のコピー) __lsi_range_key2__ S LSI2(createdAt のコピー) __lsi_range_key3__ S LSI3(値なし) __lsi_range_key4__ S LSI4(値なし) __lsi_range_key5__ S LSI5(値なし) accountId S uniqueName S status S createdAt N 実際はGSIも5個作ってしまっている

Slide 29

Slide 29 text

Next Action インデックスを見直したことで 全ての1テーブルに色々なエンティティを入れやすくなった

Slide 30

Slide 30 text

インデックス設計 GS2 では ARN を模した GRN というIDを採用 grn:gs2:ap-northeast-1:0uUD6p9U-project-0001:account:namespace-0001:account:47076847-e98e-4f01-84c2-5165e81fba56 リージョン アカウントID マイクロサービスの種類/ネームスペース エンティティの種類/ゲームプレイヤーの識別子 ゲームプレイヤーのGRN

Slide 31

Slide 31 text

インデックス設計 GRNのツリーと同じ構造でテーブルにデータを格納する account:namespace-0001:account:47076847-e98e-4f01-84c2-5165e81fba56 account:546c375f-d6e1-4b1b-9da7-1ca08c97ab0f account:namespace-0002:account:047027b2-3cd9-4561-a993-dbd0b243b90f takeover:type:0:identifier:[email protected] __parent_key__ __key__ account namespace-0001 GS2-Accountのネームスペース account namespace-0002 GS2-Accountのネームスペース account:namespace-0001:account 47076847-e98e-4f01-84c2-5165e81fba56 ゲームプレイヤーのアカウント account:namespace-0001:account 546c375f-d6e1-4b1b-9da7-1ca08c97ab0f ゲームプレイヤーのアカウント account:namespace-0001:account:546c375f- d6e1-4b1b-9da7-1ca08c97ab0f:takeover type:0:identifier:[email protected] 引継ぎ情報 account:namespace-0002:account 047027b2-3cd9-4561-a993- dbd0b243b90f ゲームプレイヤーのアカウント

Slide 32

Slide 32 text

インデックス設計 GS2-Accountのネームスペースの一覧をとりたい __parent_key__ __key__ account namespace-0001 GS2-Accountのネームスペース account namespace-0002 GS2-Accountのネームスペース account:namespace-0001:account 47076847-e98e-4f01-84c2-5165e81fba56 ゲームプレイヤーのアカウント account:namespace-0001:account 546c375f-d6e1-4b1b-9da7-1ca08c97ab0f ゲームプレイヤーのアカウント account:namespace-0001:account:546c375f- d6e1-4b1b-9da7-1ca08c97ab0f:takeover type:0:identifier:[email protected] 引継ぎ情報 account:namespace-0002:account 047027b2-3cd9-4561-a993- dbd0b243b90f ゲームプレイヤーのアカウント __parent_key__ == ‘account’

Slide 33

Slide 33 text

インデックス設計 GS2-Accountのネームスペース名’namespace-0001’のアカウン ト一覧をとりたい __parent_key__ __key__ account namespace-0001 GS2-Accountのネームスペース account namespace-0002 GS2-Accountのネームスペース account:namespace-0001:account 47076847-e98e-4f01-84c2-5165e81fba56 ゲームプレイヤーのアカウント account:namespace-0001:account 546c375f-d6e1-4b1b-9da7-1ca08c97ab0f ゲームプレイヤーのアカウント account:namespace-0001:account:546c375f- d6e1-4b1b-9da7-1ca08c97ab0f:takeover type:0:identifier:[email protected] 引継ぎ情報 account:namespace-0002:account 047027b2-3cd9-4561-a993- dbd0b243b90f ゲームプレイヤーのアカウント __parent_key__ == ‘account:namespace-0001:account’

Slide 34

Slide 34 text

インデックス設計 GS2-Accountのネームスペース名’namespace-0001’のアカウント ‘546c375f-d6e1-4b1b-9da7-1ca08c97ab0f’ のtype0の引継ぎ情報一覧をとりたい __parent_key__ __key__ account namespace-0001 GS2-Accountのネームスペース account namespace-0002 GS2-Accountのネームスペース account:namespace-0001:account 47076847-e98e-4f01-84c2-5165e81fba56 ゲームプレイヤーのアカウント account:namespace-0001:account 546c375f-d6e1-4b1b-9da7-1ca08c97ab0f ゲームプレイヤーのアカウント account:namespace-0001:account:546c375f- d6e1-4b1b-9da7-1ca08c97ab0f:takeover type:0:identifier:[email protected] 引継ぎ情報 account:namespace-0002:account 047027b2-3cd9-4561-a993- dbd0b243b90f ゲームプレイヤーのアカウント __parent_key__ == ‘account:namespace-0001:account:546c375f-d6e1-4b1b-9da7-1ca08c97ab0f:takeover’ and begins_with(__key__, ‘type:0:’)

Slide 35

Slide 35 text

テナントごとに1テーブルに テナントA テナントB テナントA 用テーブル テナントB 用テーブル マイクロサービスA マイクロサービスB

Slide 36

Slide 36 text

テナントごとに1テーブルに テナントA テナントB テナントA 用テーブル テナントB 用テーブル マイクロサービスA マイクロサービスB 本当は全てのテナントを1テーブルにしたかった そうすると、キャパシティ管理が容易になる

Slide 37

Slide 37 text

バックアップはテーブル単位 GS2 では テーブルのバックアップを ポイントインタイムリカバ リ でバックアップ。

Slide 38

Slide 38 text

バックアップはテーブル単位 GS2 では テーブルのバックアップを ポイントインタイムリカバ リ でバックアップ。 テナントごとにロールバック出来るようにするには テナントごとにテーブルを分けておく必要がある マルチテナントアプリケーションでなければ1テーブルに出来たはず

Slide 39

Slide 39 text

おっ。これなんか見たことあるぞ 結論:NoSQL データ構造の行きつく先は同じなのかもしれない

Slide 40

Slide 40 text

宣伝: GS2 で Serverless に出来ること例 • 匿名アカウント サービスを最初に提供し、メールアドレスやパスワードの登録を後回しに • 所持品管理 クーポン所持数とか。有効期限付きも可能 • 経験値・レベル フォーラムの書き込み回数で称号が付く。とか • チャット WebSocketを使ったリアルタイムテキストチャット • 装備 お気に入りの動画をマイリストに登録する。とか • スタミナ 8時間に1回無料で漫画が読める。とか https://gs2.io

Slide 41

Slide 41 text

Thanks