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

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

Serverless Virtual #5 の登壇資料です。

62340514ee3033d54d79c9e7a3db68d5?s=128

Kazutomo Niwa

August 26, 2020
Tweet

Transcript

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

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

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

    Partners ワンダープラネット
  4. このセッション is 何

  5. DynamoDB の知見を共有 DynamoDB の知見としてテーブル構成の Best Practice を共有 するのが目的。 みんなが DynamoDB

    を使いこなせるようになるといいな!
  6. アジェンダ 1. 動機および事例に関する個別事情 2. 新テーブルを準備 3. 新テーブルに同期 4. 新テーブルに切り替え 5.

    インデックス問題を回避するために
  7. 動機および事例に関する個別事情

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

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

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

    用テーブル マイクロサービスB + テナントB 用テーブル マイクロサービスA マイクロサービスB テナント×(利用されている)マイクロサービス のテーブルが存在 合計 2,000 テーブル以上
  11. 新テーブルを準備

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

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

    + テナントB 用テーブル マイクロサービスA + テナントA 用テーブル’ マイクロサービスB + テナントA 用テーブル’ マイクロサービスB + テナントB 用テーブル’
  14. 新テーブルに同期

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

  16. DynamoDB Stream マイクロサービスA + テナントA 用テーブル マイクロサービスB + テナントA 用テーブル

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

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

    今回はトランザクションを採用
  19. Why 2,000テーブルもあるから (DynamoDB の制限にはストリームの数の明記はないけど、 何かあるかもしれない)

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

  21. DynamoDB Stream マイクロサービスA + テナントA 用テーブル マイクロサービスB + テナントA 用テーブル

    マイクロサービスB + テナントB 用テーブル マイクロサービスA + テナントA 用テーブル’ マイクロサービスB + テナントA 用テーブル’ マイクロサービスB + テナントB 用テーブル’ どうでもいい更新 作成
  22. プログラム マイクロサービスA + テナントA 用テーブル マイクロサービスA + テナントA 用テーブル’ 読み取り

    プログラム 作成
  23. 新テーブルに切替

  24. プログラム マイクロサービスA + テナントA 用テーブル マイクロサービスA + テナントA 用テーブル’ マイクロサービスA

    作成・更新・削除
  25. インデックス問題を回避するために

  26. 毎回こんなことやってられない 新しいテーブル設計では先にインデックスを作るように 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
  27. 毎回こんなことやってられない 新しいテーブル設計では先にインデックスを作るように 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 先にインデックス用の列を定義しておく 使いたくなったら、値を入れ始めればいい
  28. 毎回こんなことやってられない 新しいテーブル設計では先にインデックスを作るように 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個作ってしまっている
  29. Next Action インデックスを見直したことで 全ての1テーブルに色々なエンティティを入れやすくなった

  30. インデックス設計 GS2 では ARN を模した GRN というIDを採用 grn:gs2:ap-northeast-1:0uUD6p9U-project-0001:account:namespace-0001:account:47076847-e98e-4f01-84c2-5165e81fba56 リージョン アカウントID

    マイクロサービスの種類/ネームスペース エンティティの種類/ゲームプレイヤーの識別子 ゲームプレイヤーのGRN
  31. インデックス設計 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:niwa_kazutomo@gs2.io __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:niwa_kazutomo@gs2.io 引継ぎ情報 account:namespace-0002:account 047027b2-3cd9-4561-a993- dbd0b243b90f ゲームプレイヤーのアカウント
  32. インデックス設計 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:niwa_kazutomo@gs2.io 引継ぎ情報 account:namespace-0002:account 047027b2-3cd9-4561-a993- dbd0b243b90f ゲームプレイヤーのアカウント __parent_key__ == ‘account’
  33. インデックス設計 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:niwa_kazutomo@gs2.io 引継ぎ情報 account:namespace-0002:account 047027b2-3cd9-4561-a993- dbd0b243b90f ゲームプレイヤーのアカウント __parent_key__ == ‘account:namespace-0001:account’
  34. インデックス設計 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:niwa_kazutomo@gs2.io 引継ぎ情報 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:’)
  35. テナントごとに1テーブルに テナントA テナントB テナントA 用テーブル テナントB 用テーブル マイクロサービスA マイクロサービスB

  36. テナントごとに1テーブルに テナントA テナントB テナントA 用テーブル テナントB 用テーブル マイクロサービスA マイクロサービスB 本当は全てのテナントを1テーブルにしたかった

    そうすると、キャパシティ管理が容易になる
  37. バックアップはテーブル単位 GS2 では テーブルのバックアップを ポイントインタイムリカバ リ でバックアップ。

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

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

  40. 宣伝: GS2 で Serverless に出来ること例 • 匿名アカウント サービスを最初に提供し、メールアドレスやパスワードの登録を後回しに • 所持品管理

    クーポン所持数とか。有効期限付きも可能 • 経験値・レベル フォーラムの書き込み回数で称号が付く。とか • チャット WebSocketを使ったリアルタイムテキストチャット • 装備 お気に入りの動画をマイリストに登録する。とか • スタミナ 8時間に1回無料で漫画が読める。とか https://gs2.io
  41. Thanks