[レポート] Amazon DynamoDB Deep Dive: より進んだDynamoDBのデザインパターン #reinvent

本ブログエントリはre:Invent 2018のセッション「Amazon DynamoDB Deep Dive: Advanced Design Patterns for DynamoDB」の参加レポートです。
2018.11.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

福岡のyoshihitohです。re:Invent 2018のセッション「Amazon DynamoDB Deep Dive: Advanced Design Patterns for DynamoDB」についてレポートします。

セッション情報

セッション名

Amazon DynamoDB Deep Dive: Advanced Design Patterns for DynamoDB

スピーカー

  • Rick Houlihan - Principal Technologist, NoSQL

概要

原文の引用です。

This session is for those who already have some familiarity with DynamoDB. The patterns and data models discussed in this session summarize a collection of implementations and best practices leveraged by Amazon.com to deliver highly scalable solutions for a wide variety of business problems. The session also covers strategies for global secondary index sharding and index overloading, scalable graph processing with materialized queries, relational modeling with composite keys, and executing transactional workflows on DynamoDB.

以降がセッション内容です。

DynamoDB Deep Dive: より進んだDynamoDBのデザインパターン

アジェンダ

  • データ処理の簡単な歴史 (なんでNoSQL?)
  • DynamoDBの概要
  • NoSQLのデータモデリング
    • 正規化 vs 非正規化
  • NoSQL共通のデザインパターン
    • 複合キー
    • 階層データ
    • リレーショナルデータ
  • 実際のアプリケーションのモデリング

データ処理の歴史

データベース技術のタイムライン

技術の適用と誇張の曲線

なんでNoSQL?

SQL NoSQL
保存に特化 計算に特化
アドホックなクエリ インスタンス化したビュー
垂直スケーリング 水平スケーリング
OLAP向き スケールするOLTP向き

Amazon DynamoDB

特徴

  • フルマネージドなNoSQL
  • ドキュメント型・もしくはキー・バリュー型
  • どんなワークロードでもスケールする
  • 高速かつ一貫性がある
  • アクセス制御できる
  • イベント駆動のプログラミング

テーブルの構造

パーティションキー

  • アイテムを一意に識別する
  • 順序のないハッシュのインデクスとして使われる
  • テーブルをパーティション化してスケールできるようにする

パーティション: ソートキー

  • 2つの属性を組み合わせてアイテムを一意に識別する
  • 順序のないハッシュインデクスキーが同一のアイテムについて、ソートキー順にデータを並べる
  • パティションキー1個につき何個でもソートキーを持てる
    • ただしセカンダリインデクスがある場合は除く

パーティションはそれぞれ3つずつレプリケートされる

ローカルセカンダリインデクス(LSI)

  • ソートキーに代替の属性を使う
  • インデクスは1つのパーティションキーに対してローカル
  • LSIを使う場合、パーティションキー1つのつき10BMまで

グローバルセカンダリインデクス(GSI)

  • 代替のハッシュキーを使う
  • ソートキーを使う場合は同一もしくは代替の属性を使う
  • インデクスは全てのパーティションキーにまたがる
  • 複合インデクスを使う場合は複合キーを用意する

  • LSIを使う場合、パーティションキー1つのつき10BMまで

グローバルセカンダリインデクスの更新はどうやって動いてる?

  1. クライアント → テーブル: 更新リクエストを投げる
  2. クライアント ← テーブル: 更新レスポンスを返す
  3. テーブル → GSI: 非同期更新を開始する

GSIのWCUが不足している場合、テーブルへの書き込みがスロットルされる

NoSQLのスケーリング

NoSQLをうまく使っていない場合

ホットパーティションにアクセスが集中している

うまく使ってる場合

アクセスを均等に分散させている

自動スケール

実際のトラフィックに応じてスループットを自動調整する

NoSQLのデータモデリング

リレーショナルなデータの例

SQL vs NoSQLのデザインパターン

  • NoSQLでは正規化しない

Amazon DynamoDBの主要なコンセプト

  • パーティションキー
    • パーティションキーを選択する
      • 重複なしの値を大量に
      • アイテムは均一にリクエストされ、ランダムに分散する
      • 悪い値: ステータス、性別
      • 良い値: カスタマーID、デバイスID
  • ソートキー
    • ソートキーを選択する
      • モデルは1:NとN:Nの関連にする
      • Efficient/selectiveパターン
        • 複数のエンティティをクエリする
      • Orders
      • OrderItems

true/falseのような値など、カーディナリティが低い(取りうる値域が狭い)ものは適さない

NoSQLデータモデリングの教義

  • ユースケースを学ぶ
    • アプリケーションの性質
      • OLTP
      • OLAP
      • DSS
  • アクセスパターンを明確にする
    • データソースを明確にする
    • クエリ集約を定義する
    • すべてのワークフローをドキュメント化する
  • データモデリング
    • リレーショナルモデルを避ける (1つのテーブルを使う)
    • アプリケーションサービス1つにつき、テーブル1個
      • テーブル間でいったりきたりするのを避ける
      • アクセスパスを単純化する
    • 主キーを明確にする
      • アイテムがどれくらい追加・参照されそうか
      • パーティションで負荷を散らす
    • 主要でないアクセスパターンにインデクスを定義する
  • レビューして上記プロセスを繰り返す

複合キー

アプローチ1: クエリフィルターを使う

アプローチ2: 複合キーを使う

StatusDate を組み合わせる

より進んだデータモデリング

OLTPアプリケーションでどのようにデータを使うか

  • ほとんど階層構造
  • エンティティ駆動のワークフロー
  • データが複数のテーブルに分散する
  • 複雑なクエリが必要になる
  • ACIDがメイン

バージョン履歴を管理する場合の例

リレーショナルなトランザクションをマッピングする

  • 設定管理サービス
    • ResolerGroup
    • Contacts
    • Configuration Items
  • トランザクションなワークフロー
    • Config ItemsResolver Group に追加する
    • Config Itemstatus を更新する
    • ContactsResolver Group に追加する

DynamoDB Transactions API

  • TransactWriteItems
    • 同期更新 (update/put/delete)
      • アトミック
      • 自動ロールバック
    • 1トランザクションで10アイテムまで
    • 複数テーブルをサポート
    • 複雑な条件チェック
  • 良いユースケース
    • 複数のアイテムをまたいで更新する場合
    • 条件付きのバッチ更新
  • 悪いユースケース
    • 正規化データをメンテナンスするため

DynamoDBのテーブルスキーマ

変更前

変更後、正規化をやめる

階層型データ構造にする

  • 複合ソートキーを使って階層を決める
  • ソート条件によって決定的なクエリを実行できる
  • クエリの複雑さを減らす

リレーショナルなデータをモデリングする

配信サービス GetMeThat! をモデリングする

  • ビジネスモデル
    • 顧客は物を欲しがる
    • 我々は顧客のために物を入手する
  • どういう仕組みか
    • 人々は忙しいが、物が必要
    • GetMeThat!でユーザに必要な物のリストを作ってもらう
    • いつ・どこで必要かも書いてもらう
  • 使い方
    • GetMeThat! をダウンロードする
    • 物を閲覧する
    • 物を入手する
    • どこに配置すればいいか教えてもらう

エンティティモデル

アクセスパターン

  • 注文および注文一覧を取得する
    • 日付の範囲で
      • 顧客ごと
      • ベンダーごと
  • 注文の詳細を取得する
    • ステータス
    • アイテム
  • 配送一覧を取得する
    • 日付の範囲で
      • ドライバーごと
  • 配送可能なドライバー一覧を取得する
    • 地理データと時間ごと
  • 顧客データを取得する
  • ベンダーのデータを取得する

リレーショナルなアプローチ

NoSQLなアプローチ

現実的な例

Audible eBook Sync Service

  • Audible eBooks のセッション情報を保存できるようにする
  • ユーザごとの eBookとオーディオのマッピングを管理する
  • 突発的な負荷集中に対応する場合過剰なプロビジョニングが必要になる
  • 大量のアクセスパターン

サーバーレスパラダイム

Elastic Serverless Applications

  • NoSQLはリレーショナルじゃない、という訳じゃない
  • ER図はまだ重要
  • NoSQLが使われるようになってもRDBMSは非推奨にはならない
  • OLTP・DSSでスケールが必要な場合はNoSQLを使う
  • OLAP、もしくはスケールが重要でないOLTPの場合はRDBMSを使う

おわりに

今回のre:Inventで多くのアップデートが入ったDynamoDBについて色々な話を聞けてとても勉強になりました。NoSQLとRDBMSの違いを理解して上手に使っていきたいですね!