AWS認定Big Data勉強記 - 7: Amazon DynamoDB

こんにちは、えいりんぐーです。

今回はAmazon DynamoDBについてまとめます。

#### Amazon DynamoDBとは

DynamoDB は、あらゆる規模に適した高速で柔軟な非リレーショナルデータベースサービスです。DynamoDB を使用すると、分散データベースの運用と AWS にスケーリングするための管理負荷を軽減できます。ハードウェアのプロビジョニング、設定と構成、スループット容量のプランニング、レプリケーション、ソフトウェアのパッチ適用、クラスターのスケーリングなどについて心配する必要はありません。


#### 参考資料

基本的に以下の資料を参考にしています。

 - Black Belt資料
    - [Amazon DynamoDB 2017/08/09](https://d1.awsstatic.com/webinars/jp/pdf/services/20170809_AWS-BlackBelt-DynamoDB.pdf)
    - [Amazon DynamoDB Advanced Design Pattern 2018/12/25](https://d1.awsstatic.com/webinars/jp/pdf/services/20181225_AWS-BlackBelt_DynamoDB.pdf)
        - [YouTube 動画](https://www.youtube.com/watch?v=Wd5gbLQ2a1E)
 - 公式ドキュメント
    - [開発者ガイド](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Introduction.html)
        - [DynamoDBのベストプラクティス](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/best-practices.html)
            - 重要
        - [Amazon DynamoDB に対する認証とアクセスコントロール](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/authentication-and-access-control.html)
    - [DynamoDB Accelerator](https://aws.amazon.com/jp/dynamodb/dax/)
    - [DynamoDB Streams](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Streams.html)
    - [よくある質問](https://aws.amazon.com/jp/dynamodb/faqs/)
 - ブログ
    - [Amazon DynamoDB のベストプラクティスに従うという 2019 年の計を立てる](https://aws.amazon.com/jp/blogs/news/resolve-to-follow-amazon-dynamodb-best-practices-in-2019/)
        - 中身は開発者ガイドへのリンク集
    - [AWS データストア内の機密データを保護するためのベストプラクティス](https://aws.amazon.com/jp/blogs/news/best-practices-for-securing-sensitive-data-in-aws-data-stores/)
    - [Amazon DynamoDB ストリームを使用して、順序付けされたデータをアプリケーション間でレプリケーションする方法](https://aws.amazon.com/jp/blogs/news/how-to-perform-ordered-data-replication-between-applications-by-using-amazon-dynamodb-streams/)
 - その他
    - どれも同じ内容
    - [Design Patterns and Best Practices](https://www.slideshare.net/AmazonWebServices/design-patterns-using-amazon-dynamodb)
    - [re:Invent2018](https://www.youtube.com/watch?v=HaEPXoXVf2k)
    - [re:Invent2017](https://www.youtube.com/watch?v=EFDDjzIGxA0)

#### 特徴

 - フルマネージドNoSQLデータベースサービス
 - スケーラブル・低レイテンシー
 - 管理運用なしで高可用性
    - SPOFがない
    - 3カ所のAZに保存
 - プロビジョンドスループット
    - ReadとWriteに必要な分だけのスループットキャパシティを割り当てる
 - 無制限のストレージ
   - 従量課金制のストレージ
 - 整合性モデル
    - Write
        - 少なくとも2つのAZで書き込み完了が確認取れた時点で肯定応答
    - Read
        - デフォルトは結果整合性
        - GetItem, Query, ScanではConsistent Readオプションを使うことで強整合性を指定できる
        - キャパシティユニットを2倍消費する

###### キャパシティユニット

大雑把に処理能力のこと

 - 書き込み
    - 1WCU
        - 最大1KBの書き込みを1秒に1回できる
 - 読み込み
    - 1RCU
        - 最大4KBの書き込みを1秒に1回できる

###### ユースケース

 - KVS
 - 広告やゲームのユーザー行動履歴DB
 - モバイルアプリのバックエンド
 - バッチ処理のロック管理
 - ストレージのインデックス

#### 使い方

 - HTTPベースのAPIでオペレーションをする
    - GetItem, PutItem, Queryなど
    - SDKやCLIもある
 - テーブル設計
    - アトリビュート
        - 各レコードの個々の要素
        - String, Number List, Mapなど
    - パーティションキー
        - キーバリューとしてアクセスする。
        - データ分散にも利用される
        - ハッシュインデックスを構築するためのキー
        - テーブルは性能の確保のためパーティションされる
    - ソートキー
        - オプション
        - 同一パーティションキーで異なるアイテムを取る際にも使う
    - プライマリキー
        - パーティションキーとソートキーの組み合わせで作る
    - セカンダリーインデックス
        - Local Secondary Index
            - ソートキー以外に絞り込み検索を行うキー
            - パーティションキーが同一で、他のアイテムからの検索をする
            - 既存のテーブルに追加・削除できない
            - 結果整合性と強整合性
        - Global Secondary Index
            - パーティションキーをまたいで検索をするためのインデックス
            - 既存のテーブルに追加・削除できる
            - 結果整合性のみ
        - スループットやストレージを追加で必要とするので注意
 - スケーリング
    - テーブルレベルでスループットをプロビジョンする
        - RCUやWCUを指定する
    - テーブルはパーティションに分割される
        - パーティションキーでデータ分散する
        - スループットはパーティションに均等に付与される
            - e.g. RCU=10,000、パーティション10個
                - 各パーティションのRCU=1,000
        - パーティションは最大RCU=3,000、最大WCU=1,000、最大ストレージ=10Gまで
    - キャパシティを減らすと各パーティションのキャパシティが減るので注意
    - バーストキャパシティ
        - 各パーティションで容量を超えなかった分のキャパシティを過去300秒ぶんリザーブ
        - プロビジョン分を超えた際にトラフィック処理に活用
 - 高度なテーブル操作
    - Conditional Write
        - ある値がXX以上/以下だったら、といった条件付き書き込みができる
    - Filter式
        - QueryまたはScanでフィルター式を指定して、返される結果を絞り込みできる
    - UpdateItemによるAttribute操作
        - Put, Add, Deleteという3つの操作ができる
    - Atomic Counter
        - テーブルに操作が行われるとカウンターが増えるといった動作を実現する
 - バックアップ
    - DynamoDB Streamsを使ったクロスリージョンレプリケーション
    - Data Pipelineを使って別のDynamoDBに対してコピー
    - EMRのhiveを使ってS3や別のDynamoDBに対してコピー

#### DynamoDB Accelerator (DAX)

DynamoDB 用完全マネージド型インメモリキャッシュ。リージョン内でマルチAZ構成かつキャッシュ情報のレプリケーション、障害時のフェイルオーバーなどをフルマネージドで実現。キャッシュはライトスルーで保持。最大10ノードまでスケールアウト。

#### DynamoDB Streams

DynamoDBに行われた追加・更新・削除の変更履歴を取り出して保存する。過去24時間以内に行われた変更のストリームにアクセスできる。24時間後にはストリームデータが削除される。操作の順に従ってデータはシリアライズされる。ハッシュキーが同じ場合は正しい順が保証されるが、ハッシュキーが異なる場合は保証されない。
データのストリーム処理とは少し異なる。
SDKやKCLから読み取り可能。書き込みスループットの2倍の速度で更新の読み取りが可能。Lambdaの起動トリガーとすることで、柔軟なイベント実行ができる。Lambdaだけでなく、SNS、Kinesis Data Streamsへもファンアウトできる。
ユースケースとしてはクロスリージョンレプリケーション、非同期集計、通知など。

#### アクセスコントロール

基本的にIAMを用いる。ルートユーザー・IAMユーザー・IAMロールからアクセスできる。IAMロールは次のようなケースで効果的。

 - フェデレーテッドユーザーアクセス
    - サードパーティのIdPと連携したい時
 - AWSサービスアクセス
    - AWSのサービスからDynamoDBにアクセスしたい時
 - EC2上で実行されているアプリケーション
    - EC2にIAMロールを付与してアプリケーションからDynamoDBへのアクセスを許可する

また、条件キーを指定して、条件に応じてDynamoDBへのアクセスを許可するような挙動を実現できる。

#### ベストプラクティス

 -  DynamoDB に合わせた NoSQL 設計
    - DynamoDB の場合は、答えが必要な質問が分かるまで、スキーマの設計を開始しないでください。ビジネス上の問題とアプリケーションのユースケースを理解することが不可欠です。
    - DynamoDB アプリケーションではできるだけ少ないテーブルを維持する必要があります。設計が優れたアプリケーションでは、必要なテーブルは 1 つのみです。
    - DynamoDB アプリケーションを設計する最初のステップは、システムが満たす必要がある特定のクエリパターンを見極めることです。
 - パーティションキーを効率的に設計し、使用するためのベストプラクティス
    - 一般的に言えば、テーブルとそのセカンダリインデックスの論理的なすべてのパーティションキー全体でアクティビティが均一になるようにアプリケーションを設計する必要があります。
 - ソートキーを使用してデータを整理するためのベストプラクティス
    - 関連情報を 1 つの場所にまとめて、効率的にクエリを実行することができます。ソートキーを慎重に設計することで、starts-with、between、>、< などの演算子による範囲のクエリを使用して、一般的に必要な関連項目のグループを検索することができます。
    - 複合ソートキーを作成すれば、データの階層的 (1 対多) な関係を定義して、任意の階層レベルでクエリを実行することができます。
 - DynamoDB でセカンダリインデックスを使用するためのベストプラクティス
    - インデックス数は最小限に抑えます。
    - セカンダリインデックスはストレージとプロビジョニング済みのスループットを消費するため、インデックスのサイズは可能な限り小さくすべきです。
    - 特定のパーティションキー値に対するテーブルおよびインデックス項目の合計が 10 GB を超えると予想される場合は、そのインデックスの作成を回避できないかどうかを検討してください。
    - スパースなインデックスは、テーブルの小さなサブセクションに対して行うクエリに役立ちます。
 - 大きな項目と属性を格納するベストプラクティス
    - 大きな属性値を圧縮すると、DynamoDB の項目制限に収まり、ストレージコストが削減されます。GZIP や LZO などの圧縮アルゴリズムはバイナリ出力を生成し、これを Binary 属性タイプに格納することができます。
    - Amazon S3 のオブジェクトとして保存してから、DynamoDB 項目にオブジェクト識別子を格納することができます。
 - DynamoDB で時系列データを処理するベストプラクティス
    - DynamoDB の一般的な設計原則では、使用するテーブルの数を最小限に抑えることをお勧めします。ほとんどのアプリケーションで、必要なテーブルは 1 つだけです。ただし、時系列データでは、期間あたりアプリケーションごとにテーブルを 1 個使用すると、多くの場合最適に処理できます。
 - DynamoDB でリレーショナルデータをモデル化するためのベストプラクティス
    - DynamoDB では、複合ソートキー、過負荷になっているグローバルセカンダリインデックス、パーティションテーブル/インデックス、その他のデザインパターンを使用することを意味します。これらの要素を使用してデータを構造化することで、アプリケーションは、テーブルまたはインデックスの単一のクエリを使用して、特定のアクセスパターンに必要なものを取得できます。
 - クエリとスキャンデータのベストプラクティス
    - 一般に、Scan オペレーションよりも、DynamoDB の他のオペレーションのほうが効率的です。
    - ページサイズを小さくする
    - スキャンオペレーションを分離する

#### その他

**Time To Live (TTL)**
テーブル項目の有効期限を設定し、データベースから自動的に削除するタイミングを定義できる。スループットを使用しない。追加料金なし。

**AutoScaling**
フルマネージドでWCU、RCU、GSIに対する設定を管理する。上限・加減・目標使用率の設定に合わせて、自動的な容量の拡大・縮小。瞬間的なスパイクに対応するにはDAXの使用を推奨。

**クロスリージョンレプリケーション**
前述のDynamoDB Streamsを利用して、別リージョンにテーブルをコピーする。ユースケースとしては、ディザスタリカバリー、レイテンシーの低いリード、負荷分散のためのリードレプリカ、リージョンマイグレーションなどがある。ライブラリーを用いてCloudFormation化することもできる。

**DynamoDB on-demand**
pay-per-requestモデルでの利用。事前のキャパシティユニットの設計が不要。

**Dynamo DB Transactions**
複数アイテム・複数テーブルに対する書き込み・読み込み操作についてAICDトランザクションが可能。分離レベルはserializableでロックは取らない。トランザクションの進行中にトランザクション外でアイテムが変更された場合、トランザクションをキャンセルしてアイテムの詳細がスローされる。

**インデックスの活用**
アトリビュートを結合してコンポジットキーとしたり、スパースなインデックスを作成したりしてクエリすることで、フィルターと比べてクエリが効率的になる。

**Time-based workflows**
例えば時系列データが必要なアプリケーションで、ホットデータとコールドデータを分ける。DynamoDB StreamsとGSIを活用して、非同期でホットデータをコールドデータへと移動する。

**暗号化**
AWS KMSを使ってデータの暗号化ができる。CMKはAWS所有のものと、AWS管理のものとが利用できる。