【AWS公式ドキュメントを噛み砕く】DynamoDBとは？（概要編）

# はじめに
案件でdynamoDBを触れるから、学習がてらアウトプットしてみるよ。（本は無いし、AWSの公式ドキュメントは読みにくいし・・・）
個人の理解メモなので、正しい情報はAWSの公式ドキュメント見てくださいね。
（そして誤りあれば指摘してもらえると嬉しいです）

# 「概要」を読み解く
「[概要](https://aws.amazon.com/jp/dynamodb/)」で謳われている文句が良く分からんので、読み解く。

## レベル1
「早い！便利！安全！」

|レベル1|説明|
|---|---|
|大規模なパフォーマンス|どんな規模のシステムでも一貫して早いスピードを出せるよ！なんならマイクロ秒レベルにまで対応できるよ！|
|完全マネージド型（フルマネージド）|サービス提供型なので、自分であれこれ考えなくていいよ！具体的には自動的にスケールするよ！|
|大企業で使用可能|とってもセキュアに利用できるよ！|


## レベル2
デフォルトで全てが有効というワケではないけど、いろんなコトができるよ。
なんだか粒度がバラバラな気がするけど、それぞれ6つのメリットをあげたかったんだろうな。

**大規模なパフォーマンス**
ストリーム・トリガーあたりは、AWSサービスの組み合わせとしてのメリット感を強く出している感じはある。

|レベル2|説明|
|---|---|
|Amazon DynamoDB Accelerator|性能を格段に上げるインメモリキャッシュを具備しているよ！|
|キーと値およびドキュメントデータモデルのサポート|KVSでも、ドキュメント指向でもどっちでもOK！（日本語訳が分かり辛い・・・）[^1]|
|デスクトップでローカルに開発|DynamoDBをjarとしてローカルにダウンロードしてローカルに閉じて開発できるよ！[^2]|
|セカンダリインデックス|KVS型だと、keyでしか基本的には検索できない？けど、dynamoDBならvalueも合わせて検索できるよ！[^3]|
|ストリーム|変更発生時にキャプチャできるので、通知やいろんな連携が捗る！|
|トリガー|Lambdaのトリガー機能と、上記のストリームを組み合わせるのが便利だよ！[^4]|

**完全マネージド型（フルマネージド）**
Cassandraよりも、「使いやすさ」を意識している感がある。

|レベル2|説明|
|---|---|
|グローバルテーブル|リージョンをまたぐレプリケーションができるよ！|
|ポイントインタイムリカバリ|過去 35 日間の任意の時点にテーブルを復元することができるよ！|
|オンデマンドバックアップおよび復元|これで長期間の保存とアーカイブとかの要件にも対応できるよ！|
|アダプティブキャパシティー|dynamoDBはトランザクション量を事前に宣言しておく必要があるのだけど、超過を想定してある程度柔軟に対応できるような設定をしておくことが可能だよという話|
|Auto Scaling|オートスケールできるよ。|
|有効期限|有効期限設定（TTL）を利用することで、データを安全かつ効率的に削除できるよ！|

「アダプティブキャパシティー」と「Auto Scaling」の違いがいまいち分かってない。
→アダプティブキャパシティーは、データ構造上の話で、「特定の領域にアクセスが偏ると性能が普通は出ない」んだけど、そこをいい感じにしてくれる話。（あくまでも一時的回避策的にちょっとだけ性能あげるだけなので、恒常的にアダプティブキャパシティーが発生しているのは、設計がイケテナイってことになる。）
→オートスケールは、一般的なオートスケールに同じ。DynamoDB自体が分散サーバーなので、トランザクション量に応じて、いい感じにスケールしてくれるという話。

**大企業で使用可能**
セキュリティ部分ってあんまり意識してなかったけど、かなり良さそう。
なによりもPCIDSS準拠は嬉しい。

|レベル2|説明|
|---|---|
|保管時の暗号化|PCIDSS準拠のAWS Key Management Serviceに暗号化キーを保存できるよ。|
|DynamoDB サービスレベルアグリーメント (SLA)|可用性めっちゃ保証するよ。（99.99%。頑張れば99.999%。）（なお、年間じゃなくて、月間で保証。）|
|モニタリング機能を統合|マネジメントコンソールでもCloudWatchからでも運用メトリクスをモニタできるよ！|
|きめ細かなアクセス制御|IAMを使うことでかなり細やかにアクセス制御できるよ！|
|VPC エンドポイント|Amazon ネットワークを離れずにdynamoDBとやりとりできるよ！|
|DynamoDB コンソールと API|コンソールだけじゃなくて、APIでもdynamoDBを操作できるよ！|

[^1]: KVSとかドキュメント指向ってのは、noSQL型DBのパターンの一種。そもそもnoSQL型DBは、RDBMS以外を指す用語なので、とても広い。
[^2]: 当然だけど、データはローカルに限られるし、AWSのアカウントとかも必要。開発中のトランザクションにまで、お金を払わなくていい！
[^3]: テーブルを「プライマリ」として扱うから、この子は「セカンダリ」と呼ばれる？
[^4]: もはやdynamoDBの機能じゃないじゃん！って思った。（サービスとしてのメリットなので、ここに挙げられている事自体に違和感は無いけど）


# 「料金」を読み解く
「[料金](https://aws.amazon.com/jp/dynamodb/pricing/)」の考え方が良く分からん。

## 概要
データ量と、書込/読込トランザクションの量で決まるっぽい。
あとはオプションをどれだけ使うかかな。

|項目|説明|
|---|---|
|データストレージ|単純に保存されているデータ量での課金。25GBまで無料。|
|書き込みキャパシティーユニット|1wcu＝1秒あたり最大1回の書き込み。2wcu＝1秒あたり最大2回の書き込み。25wcuまで無料。|
|読み込みキャパシティーユニット|1rcu＝1秒あたり最大2回の読み込み。2rcu＝1秒あたり最大4回の書き込み。25rcuまで無料。|

※wcuとかrcuとかは単位っぽく見せるために書いただけ。

## 料金詳細

なにやら事前に宣言するらしい。

|項目|説明|
|---|---|
|DynamoDB Auto Scaling|処理用が読めない時や、時間によって処理量が異なる場合に使う。目標使用率、最小/最大容量制限を指定する。要は「だいたいこんなもんやろ」って定義したら良しなにしてくれる。|
|手動プロビジョニング|処理量が時間に変わらず一定の場合に用いる。（たぶんあんま使われないのでは？）|

以下にも注意しましょう。

> 大きい項目のあるテーブルの場合は、同じリクエスト回数を処理するためにより多くのユニットが必要になる場合があります。

事前宣言ってあるけど、超過したらどうすんだ？って思ったら、以下に書込や読込等の「リクエストが失敗」すると書いてあった。
[DynamoDBにおけるスループット超過対策 〜 Fallback-Queueingパターン](https://dev.classmethod.jp/cloud/aws/fallback-queueing-pattern-on-dynamodb/)
※公式情報ではないけど、よくお世話になっているサイト

# 「開発者ガイド」を読み解く
「[開発者ガイド](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Introduction.html)」が長いので読む気が失せるので、なるべくポイント絞って書きたい。
（取り上げてないページたくさんあります）

## 仕組み
### コアコンポーネント

**基本用語**

|dynamoDB用語|RDBMSだと|
|---|---|
|テーブル(Tables)|テーブル|
|項目(Items)|レコード|
|属性(Attributes)|カラム|

気になったポイント

* プライマリキー以外、People テーブルはスキーマレスです。つまり、属性またはデータ型を事前に定義する必要はありません。（公式文書そのまま）
    * RDBMSみたいに事前に決めた型しか入らないってことは無いよってことか。ってことは、レコード毎にカラム定義するってことかな？（解釈）
* 項目の一部には、入れ子の属性 (Address) があります。DynamoDB は深さが最大 32 レベルの入れ子の属性をサポートします。（公式文書そのまま）

**プライマリキー**
「項目（RDBMSで言うところのレコード）を一意に特定する」という役割はRDBMSと同じ。
どうやら2種類あるらしい。

|dynamoDB用語|RDBMSだと|
|---|---|
|パーティションキー|1属性だけで一意に特定する時を指すっぽい|
|パーティションとソートキー|2属性で一意に特定する時を指すっぽい。パーティションキーで、だいたい絞れること。そのうえで、ソートキーを使えば一意に特定できること。|

それ以外の記載は無いので、3属性以上で一意に特定するとかはサポートしていないっぽい。

気になったポイント

* プライマリキー属性に許可される唯一のデータ型は、文字列、数値、またはバイナリです。他のキー以外の属性では、このような制限はありません。（公式文書そのまま）
* 物理的な領域としてのデータの距離を近くするために、パーティションという考え方があるらしい。性能改善目的？（解釈）
    * パーティションキーの値に基づいてパーティション間でデータ項目を均等に分散する。（抜粋）
    * ソートキー値で並べ替えられた順に、同じパーティションキーを持つ項目どうしを物理的に近くに保存する。（抜粋）

**セカンダリインデックス**
そもそもなぜセカンダリ？プライマリはどこいった？
　→　テーブルをプライマリだとして、サブ的な位置づけってニュアンスだと受け取った。
そもそもインデックスそのもが理解できてなかたのだけど、実データとは別に「検索用のデータ」をインデックスと呼ぶのね。

|dynamoDB用語|RDBMSだと|
|---|---|
|**グローバル**セカンダリインデックス（GSI）|パーティションキーとソートキーを持つインデックス。テーブル内の項目とは異なる場合があります。|
|**ローカル**セカンダリインデックス|テーブルと同じパーティションキーと、異なるソートキーを持つインデックス。|

気になったポイント

* テーブルあたり最大 5 個のグローバルセカンダリインデックスと 5 個のローカルセカンダリインデックスまで定義できます。

**DynamoDB ストリーム**
テーブルのデータ変更イベントをキャプチャするオプションの機能

* insert: 登録される属性「全て」をキャプチャする。（1レコードまるっと）
* update: 「変更対象の属性に限り」、変更前後の属性を取得する。（変更したカラムだけ）
* delete: 削除された属性「全て」をキャプチャする。（1レコードまるっと）

気になったポイント

* 各ストリームレコードには、テーブルの名前、イベントのタイムスタンプ、およびその他のメタデータも含まれます。ストリームレコードには 24 時間の有効期間があり、その後はストリームから自動的に削除されます。（公式文書そのまま）
* DynamoDB ストリーム は AWS Lambda と共に使用してトリガーを作成できます。これは、ストリームで関心のあるイベントが発生するたびに自動的に実行されるコードです。（公式文書そのまま）

### データ型
「セット」が「リスト」の下位互換にしか見えないけど、どういう時に使うのだろうか？

|型分類|型名|説明|
|---|---|---|
|スカラー型|文字列|UTF-8。0以上の文字列長。最大400KB。|
||数値|最大38桁。これを超えると例外が発生する。|
||バイナリ|0以上の長さ。最大400KB。|
||Boolean|true or false|
||Null|不明または未定義|
|ドキュメント型|リスト|順序付きの値のコレクション。角括弧で囲まれます: [ ... ]。|
||マップ|要は、JSONのこと。|
|セット型|文字セット|「順序保証なし」かつ「文字列に限る」という制約を持ったリスト。|
||数値セット|「順序保証なし」かつ「数値に限る」という制約を持ったリスト。|
||バイナリセット|「順序保証なし」かつ「バイナリに限る」という制約を持ったリスト。|

気になったポイント

* 全般的に
    * プライマリキー属性として利用する際には、最大1024ないしは2048byteという制約が追加される。（解釈）
    * DynamoDB では、要素が深い入れ子になっていても、リスト内の個々の要素を操作できます。（公式文書そのまま）
* 数値
    * 「数値の精度が重要な場合は、数値型から変換する文字列を使用して、DynamoDB に数値を渡します。」ってあるけど、どういうことだ？
* バイナリ
    * DynamoDB に送信する前に、base64 エンコード形式のバイナリ値をエンコードする必要があります。（公式文書そのまま）
* リスト・マップ
    * リスト・マップ要素に保存できるデータ型に制限はなく、リスト・マップ要素の要素が同じ型である必要はありません。（公式文書**ほぼ**そのまま）
* セット
    * 値を含む項目が DynamoDB のサイズ制限 (400 KB) 内である限り、セットの値の最大数の制限はありません。（公式文書そのまま）

### 読み込み整合性
要は、デフォルト設定なら更新後1秒程度経過しないと、最新データは取得できないよということか。
そもそも、dynamoDB使う時点で、基本的には結果整合性を前提にしておいた方がいいんだろうな。
あと、「強力な整合性のある読込」の方が、キャパシティーユニットを消費するので、割高になる。（実質2倍）

|用語|説明|
|---|---|
|結果整合性のある読み込み|応答には古いデータが含まれる場合があります。（通常は1秒以内）|
|**強力な**整合性のある読み込み|最新を返すよ！ただ、ネットワークの遅延または停止があった場合には使えない場合もある。|

気になったポイント

* アプリケーションが DynamoDB テーブルにデータを書き込み、HTTP 200 応答 (OK) を受け取ると、書き込みが開始され、継続します。（公式文書そのまま）
* データは、すべてのストレージの場所で結果的に整合性が保たれます (通常は 1 秒以内)。（公式文書そのまま）
* 1 つの読み込みキャパシティーユニットは、最大サイズ 4 KB の項目について、1 秒あたり 1 回の強力な整合性のある読み込み、あるいは 1 秒あたり 2 回の結果的に整合性のある読み込みを表します。（公式文書そのまま）

## SQLとnoSQL
一般的なRDBMSとdynamoDBとの比較表が以下にあるので、一度見てみるといいかも。
＞[AWS ドキュメント » Amazon DynamoDB » 開発者ガイド » Amazon DynamoDB とは » SQL から NoSQL へ](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/SQLtoNoSQL.html#SQLtoNoSQL.WhyDynamoDB)

気になったポイント

* DynamoDB は、非リレーショナル NoSQL データベースのため、テーブルの結合はサポートされません。 その代わり、アプリケーションは一度に 1 つのテーブルからデータを読み込みます。


## 制限
以下にまとまっている。
[AWS ドキュメント » Amazon DynamoDB » 開発者ガイド » DynamoDB での制限](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Limits.html)

# さいごに
自分の言葉に置き換え直すコトで結構理解は深まった感ある。（ので、みんなもアウトプットしよう）
（ベスト・プラクティスのドキュメントも解釈してアウトプットしたいところ。）

そしてちゃんと読んで見ると、結構わかりやすい。公式ドキュメントもっと読まねば。
（日本語訳が分かりづらいところはあるけど、逆に言えばそれくらい。）

以上

# 2018-08-21追記
書きました
[【AWS公式ドキュメントを噛み砕く】DynamoDBベストプラクティス](https://qiita.com/nh321/items/3264a25b8c8fb482a61e)