【AWS】Amazon DynamoDB

Amazon DynamoDBについて勉強したのをまとめてみます。


# 特徴
- 管理不要で信頼性が高い
    - SPOFの存在しない構成
    - データは３箇所のAZに保存されるので信頼性が高い
    - ストレージは自動的にパーティショニング・スケール
- プロビジョンスループット
    - ReadとWrite、それぞれに対して必要な分だけのスループットキャパソティをプロビジョンすることができる
        - 一般的なReadヘビーなDBなら、 Read:1,000 Write:100
        - ライトヘビーなDBなら、Read:500 Write:500
    - 運用中に値は変更可能
- ストレージの容量制限がない
    - 使った分だけの従量課金制のストレージ
    - データ容量が増えててきたので、ディスクを足したり、ノードを足したりという作業が不要

# コンポーネント

# テーブル設計
- Table
    - プライマリキーの持ち方は２つ
        - Hash keyをプライマリキー
        - Hash KeyとRange Keyの複合キーをプライマリキー

- Hash key
    - 順序を指定しないハッシュインデックスを構築するためのキー
    - 単体でプライマリキーとして利用されることがある
    
-　Range key
    -　Hash keyに該当する複数のデータの順序を保証するためのキー
    -　Hash + Rangeでプライマリキーとして利用されることがある 

- Item
    - RDBでいう所謂レコード
    - 1つ以上のAttributeを持つ
    
- Attriutes
    - データの中身。RDBでいうカラム
    - Hash key, Range keyに該当するAttributes以外は事前定義不要
    - レコード間でAttributesが不揃いであっても問題ない 

# 料金体系
* キャパシティユニットの利用時間料金
    * できるだけ利用料はすくなく、定量がみえるならRI、見えないならオンデマンド、使わないDBは消す。1キャパシティーユニットは1秒間に決められた回数の読み込み/書き込み容量を提供。1WCUは1秒間に1回の書き込み、1RCUは1秒に2回の読み込み。1時間ごとに課金される。 
* ストレージ利用料：大きいデータはS3に、保存先のメタデータをDynamoDBに
* データ転送量

# 設計
## DynamoDBのNoSQL設計のプラクティス
DynamoDB アプリケーションを設計する最初のステップは、システムが満たす必要がある特定のクエリパターンを見極める
ビジネス上の問題とアプリケーションのユースケースの理解
DynamoDBはできるだけ少ないテーブルで管理する
例外として、大容量の時系列データが必要な場合や、データセットのアクセスパターンが非常に異なる場合がある

他方、RDBMSはアクセスパターンを考慮せず正規化されたデータモデルを作る。

アクセスパターン(3つ)

```
データサイズ: 一度に格納され、リクエストされるデータの量を把握することは、データを分割する最も効果的な方法を決定するのに役立つ
データシェイプ: クエリが処理される際NoSQL データベースでデータを整理することで、データベース内の形状がクエリされるものと一致する
これは、スピードとスケーラビリティを向上させる
データ速度: DynamoDB では、クエリを処理するために使用可能な物理パーティションの数を増やし、それらのパーティション間で効率的にデータを分散させることでスケーリングします。
```

## 設計の一般アプローチ
* 関連するデートをできるだけ1つのテーブルにまとめる
* ソートを利用する：キーは関連項目をグループ化して、ソートする
* クエリを分散する：クエリはパーティションに分散させる
* GSIを使う：GSIを使うことでメインテーブルでサポートできるクエリとは異なるクエリを有効にすることができ、高速かつ比較的安価になる

### パーティションキーの設計
### パーティションキーを効率的に設計し、使用するためのベストプラクティス
* バーストキャパシティーを使う：未使用の読み込みおよび書き込みキャパシティーは最大 5 分 (300 秒) 保持される
* アダプティブキャパシティーを使う；アダプティブキャパシティーが使用されることで、偏ったデータアクセスにも対応できるようになっていますが、未然にスロットリングを防ぐことはできません
* パーティションキーのワークロードを均等に分散する："ホット" パーティションキー値 (何度もリクエストされるパーティションキー値) を回避するように、プライマリキー要素を構築してください。このようなパーティションキー値が原因で、全体のパフォーマンス速度が低下する場合があります
* 書き込みシャーディングで均等に分散させる: パーティションキーの値にランダムなサフィックスをつける、パーティションキーに日付データをつけるなどする
* データアップロード時に書き込みを効率的に分散する：ソートキーを使用して各パーティションキー値から 1 つの項目をロードし、次に各パーティションキー値から別の項目をロードするなどして、アップロード作業を分散させることができる

### セカンダリインデックスの一般的なガイドライン
* GSI : パーティションキーおよびソートキーを持つインデックス。ベーステーブルのものとは異なる場合があります。グローバルセカンダリインデックスは、このインデックスに関するクエリが、すべてのパーティションにまたがり、ベーステーブル内のすべてのデータを対象とする可能性があるため、「グローバル」と見なされます。グローバルセカンダリインデックスにはサイズの制限はなく、読み込みアクティビティと書き込みアクティビティ用にプロビジョニングされた独自のスループット設定が、テーブルのものとは異なります。
* LSI : パーティションキーはベーステーブルと同じですが、ソートキーが異なるインデックスです。ローカルセカンダリインデックスは、ローカルセカンダリインデックスのすべてのパーティションの範囲が、同じパーティションキー値を持つベーステーブルのパーティションに限定されるという意味で「ローカル」です。その結果、任意の 1 つのパーティションキー値に対してインデックスが作成された項目の合計サイズが、10 GB を超えることはできません。また、ローカルセカンダリインデックスでは、読み込みアクティビティおよび書き込みアクティビティのプロビジョニングされたスループット設定が、インデックス作成中のテーブルと共有されます
テーブルごとに、最大5つまで。

#### 使い分け
一般的に、ローカルセカンダリインデックスではなく、グローバルセカンダリインデックスを使用する必要があります。
例外として、クエリ結果に強力な整合性が必要な場合があります。これは、ローカルセカンダリインデックスでは可能だが、グローバルセカンダリインデックスでは提供できません (グローバルセカンダリインデックスのクエリは結果整合性のみサポート)。
LSIは復号キーテーブルにしか定義できない。

* インデックスを効率的に使う
* 射影を慎重に選択する：インデックスのサイズは小さくする。
* フェッチの回避
* LSI作成時に項目コレクションのサイズ制限を確認する