【AWS公式ドキュメントを噛み砕く】DynamoDB Stream

# はじめに
[【AWS公式ドキュメントを噛み砕く】DynamoDBとは？（概要編）](https://qiita.com/nh321/items/7f43a87a0ec36b266222)で、概要レベルの話を抑えた。
ベストプラクティスは[こっち](https://qiita.com/nh321/items/3264a25b8c8fb482a61e)でおさえた。
今回はDynamoDB Streamsの話。

結構抜粋してます。
そして、学習がてらのアウトプットなので、正しい情報はAWSの公式ドキュメント見てくださいね。
（そして誤りあれば指摘してもらえると嬉しいです）

# 公式ガイド：Streamsの使用
「[ここ](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Streams.html)」の話

**DynamoDB ストリーム を使用したテーブルアクティビティのキャプチャ**
まとめるとこんな感じ

- ストリームレコードの性質
    - 時系列順
        - （ストリームレコード自体は時系列順だけど、時系列順に厳密に処理を実現するのは難しい。）
        - （シャードという単位に分割され、その中では時系列を維持されるけど、シャード間の時系列は維持されないっぽいため。）（ドキュメントからそう読み取った）
    - キャプチャした情報（ストリームレコード）は「24時間」保存する。
        - （リトライ含め24時間以内に処理を終わらせないと、ストリームレコードは消失する。当然だが、実データは消えない。）
    - ストリームレコードは「変更前後の内容」を「ほぼリアルタイム」で参照できる。
    - 暗号化して保存される。
    - 各ストリームレコードは、ストリームに 1 回だけ出現します。
        - （ただし、失敗時にリトライされるため、重複を想定しておいた方が良い）

- ストリームレコードが持っている情報
    - 変更された項目のプライマリキー属性
    - テーブル内の単一の項目に加えられたデータ変更についての情報
    - 追加情報（変更された項目の前後のイメージ）を保持するように設定も可能


**DynamoDB ストリーム におけるエンドポイント**

- 「DynamoDB」 と 「DynamoDB ストリーム」 はそれぞれ異なるエンドポイントである。

**ストリームの有効化**

- ストリームは任意のタイミングで、有効化/無効化が可能。
- DynamoDB ストリーム は非同期的に動作する。
- 非同期なので、ストリームを有効にしても本体テーブルのパフォーマンスに影響は無い。

**ストリームの読み込みと処理**

◆シャードについて
ストリームレコードをまとめた「シャード」という存在について

- シャード＞ストリームレコード　という構造になっている。（ストリームレコードは、シャードという単位でグルーピングされる。）
- 各シャードには、これらのレコードへのアクセスと反復処理に必要な情報が含まれています。
- シャードの作成/分割/統合は、自動的に行われる。
- シャードには系列 (親と子) があるため、アプリケーションは子シャードを処理する前に、必ず親シャードを処理する必要があります。
    - これにより、ストリームレコードも正しい順序で処理されるようになります。

◆ストリームレコードの処理について
ストリームレコードを処理するには、以下が必要。

- アクセスするストリームの一意の Amazon リソースネーム（ARN）を調べます。
- 目的のストリームレコードがストリーム内のどのシャードに含まれているかを調べます。
- シャードにアクセスし、目的のストリームレコードを取得します。

◆DynamoDBストリームAPIについて
以下4APIが存在する。

- ListStreams — 現在のアカウントおよびエンドポイントのストリーム記述子のリストを返します。必要に応じて、特定のテーブル名のストリーム記述子だけをリクエストできます。
- DescribeStream — 特定のストリームに関する詳細情報を返します。出力には、ストリームに関連付けられたシャードのリストが含まれています（シャード ID を含む）。
- GetShardIterator — シャード内の場所を表すシャードイテレーターを返します。イテレータがストリーム内の最も古いポイント、最も新しいポイント、特定のポイントへのアクセスを提供することをリクエストできます。
- GetRecords — 特定のシャード内からストリームレコードを返します。GetShardIterator リクエストから返されたシャードイテレーターを指定する必要があります。

## DynamoDB ストリーム および Time To Live

TTLによって削除される項目も、DynamoDBストリームで処理することが可能。

# 公式ブログ：DynamoDBストリームによるレプリケーション
「[Amazon DynamoDB ストリームを使用して、順序付けされたデータをアプリケーション間でレプリケーションする方法](https://aws.amazon.com/jp/blogs/news/how-to-perform-ordered-data-replication-between-applications-by-using-amazon-dynamodb-streams/)」の話
※ガイドに重複する内容は割愛

## AWS Lambda を使用した DynamoDB ストリームの処理

- ストリームにおける、「シャード **内** の順序性」は **保証される**。
- ストリームにおける、「シャード **間** の順序性」は **保証されない**。
    - 3シャードあれば、3Lambdaが同時に実行される。

並列化しないのであれば、これで十分。

## DynamoDB ストリームへの複数の Lambda 関数の設定

- ストリーム毎に1～2のLambda関数の指定が望ましい。
    - DynamoDB では 1 つのストリームに複数の Lambda 関数を設定が可能。
    - ストリームごとに 3 つ以上の Lambda 関数を設定するとリクエストが失敗する可能性が高くなります。
    - DynamoDB ストリームから読み込める Lambda 関数またはプロセスの数は、今後増える可能性があります。

結局、これは望ましくないパターンなので、並列処理化したい場合は、ファンアウトパターンを使う。

## ファンアウトパターンを使用した DynamoDB ストリームの処理
ファンアウトパターンには3種類ある。

### Lambda ファンアウトパターン

Lambdaファンアウトパターンがすべての基礎。残りの2つもこれがベースになっているので、同じメリデメが発生する。
ダウンストリームへの書き込み失敗などの挙動については触れられていないので、必ず成功することが保証されている場合以外は避けたほうが良いかも？

**メリット**

- Lambda 関数の処理が失敗した場合、Lambda は成功するまで、またはストリームからのデータの有効期限が切れるまでレコードのバッチ全体を再試行します。
    - この再試行のメカニズムは、すべてのイベントが正しい順序で処理されるために役立ちます。

**デメリット**

- Lambda は部分的な失敗への処理として再試行を実施しますが、システムは完全なリアルタイムではなくなります。
- ダウンストリームサービスへの書き込み時に部分的な失敗を処理する際、メッセージの書き込み順序を保証することは難しくなります。
- 新しいダウンストリームサービスにデータを送信するためには、Lambda 関数を再度デプロイする必要があります。
- Lambda の処理が失敗すると、レコードのバッチ全体が再処理されるため、Kinesis Data Streams または DynamoDB 内のレコード重複につながることがあります。
- Lambda 関数のスループットは、ダウンストリームデータの保存時またはアプリケーションの導入時に低下します。

### Amazon SQS への Amazon SNS ファンアウトパターン

SQSも重複が発生する仕組みなので、重複対処が考えられているなら、ありかなー。SQSのデッドレターキューなども使えば、ダウンストリームへの書き込み失敗などもカバーできるので、割と良い気配がする。
一方で、RDBMSなどのコネクション周りに限界がある場合は、SQSとつなぐのはアンチパターンなので、これは避けたほうが良さそう。
※Lambdaファンアウトパターンにも記載されているメリデメは割愛してます。

**メリット**

- 1 つの SNS トピックに多くの AWS のサービスをサブスクライブできるため、拡張可能なサブスクリプションメカニズムを提供します。

**デメリット**

- Amazon SNS にはメッセージサイズが 256 KB までという制限があるため、DynamoDB の項目のサイズもこの制限内となります。
- SNS が SQS キューへ書き込む際に部分的に失敗している間、メッセージの書き込みは順序付けられません。
- Amazon SQS 内のメッセージは、CloudWatch Events でスケジュールされた Lambda 関数によって処理されますが、システムは完全なリアルタイムではなくなります。

### Kinesis Data Streams ファンアウトパターン

kinesis側である程度のまとまりに固めて処理が可能となるため、RDBMSなどコネクション周りに限界がある場合はこちらのほうが良い気がする。
※Lambdaファンアウトパターンにも記載されているメリデメは割愛してます。

**メリット**

- Kinesis Data Streams は、 DynamoDB によって生成される書き込み順イベントへの手段を提供します。
- 複数のデータストリームを一緒にチェーンすることで、Kinesis Data Streams のさらなるファンアウトが可能です。
- Kinesis Data Firehose を使用して Amazon S3、Amazon Redshift、Amazon Elasticsearch Service へデータのアーカイブができます。
- DynamoDB テーブル内で定義されたパーティションキー以外のパーティションキーを使用したデータ集約が可能です。

**デメリット**

- このパターンは、書き込み順を確実にするため PutRecord API のシリアル呼び出しパターンを奨励するため、スループットが制限されます。

# さいごに

ブログあわせて3～4時間くらい。