DynamoDB Streams
DynamoDB Streamsは変更データキャプチャのログです。テーブルへのすべての挿入、更新、削除が順序どおりにキャプチャされ、反応できるレコードのストリームになります。これがポーリングなしでテーブルをイベントソースに変える方法です。
監査ログのシナリオでは、機密性の高いイベントが届いた瞬間に反応したくなります — 誰かが請求書をエクスポートしたり管理者ロールを付与したりしたときにアラートを発火させる — タイマーでテーブルをスキャンすることなく、です。Streamsはそのプッシュ側です。
DynamoDB Streamsはどのように機能しますか?
DynamoDB Streamsは、テーブルへのすべての挿入、更新、削除を時刻順で重複排除されたレコードのログとしてキャプチャし、最大24時間保持します。StreamViewTypeで各レコードが運ぶ内容(キーのみ、新しいイメージ、古いイメージ、または両方)を選択し、Lambdaトリガーでストリームを消費することで、ポーリングなしにアイテムの変更に反応できます。
- Streamsはアイテムレベルの変更をキャプチャします。時刻順で重複排除されたログとして、最大24時間保持されます。
- 各レコードが何を運ぶかを選べます。
StreamViewTypeにより、キーのみ、新しいイメージ、古いイメージ、または古い・新しいの両方を選択します。 - レコードはパーティションキー内で順序付けされ、ストリームはテーブルと同じ方法でシャーディングされます。
- ネイティブのコンシューマーはLambdaです — 新しいレコードのバッチごとに実行されるトリガーで、よりリッチなファンアウト向けの代替としてKinesis Data Streamsがあります。
問題:ポーリングなしで反応する
「role.grantedイベントが書き込まれたら通知して」が必要です。素朴なアプローチは、毎分新しいイベントをスキャンするスケジュールジョブですが — これは毎回直近のパーティション全体を読み取り、キャパシティを消費し、常に少なくとも1分遅れます。
実際に欲しいのはプッシュです。アイテムが変更された瞬間にDynamoDBが教えてくれる。それこそまさにStreamsが提供するもので、変更レコードはあなたが探しに行くのではなくコードへ届けられます。
Streamsの仕組み
AWSドキュメントによれば、DynamoDB StreamsはネイティブなLambda連携とともに「最大24時間の、重複排除され時刻順に並んだ変更ログ」を保存します(DynamoDBの変更データキャプチャ)。各レコードは1つのアイテムレベルの変更を記述します。
ストリームを有効にするときに**StreamViewType**を選びます。これは各レコードが変更されたアイテムをどれだけ運ぶかを制御します:
| StreamViewType | each record contains |
|---|---|
| KEYS_ONLY | only the key attributes of the changed item |
| NEW_IMAGE | the entire item as it looks after the change |
| OLD_IMAGE | the entire item as it looked before the change |
| NEW_AND_OLD_IMAGES | both the before and after images |
レコードは各パーティションキー内で順序付けされ、ストリームはテーブルと同じパーティション構造に沿ってシャーディングされます。保持期間は24時間です — Streamsは反応のためのバッファであり、恒久的な履歴ではありません。永続的な履歴には、イベントそのものを保存します(まさにこの監査ログテーブルがすでにそうしているものです)。
ネイティブのコンシューマーはLambdaトリガーです。DynamoDBは新しいストリームレコードのバッチが届くたびに、それを引数として関数を呼び出します。
実例:機密性の高い監査イベントでアラート
監査ログテーブルにはNEW_IMAGEのストリームが設定されており、各レコードは完全な新しいイベントを運びます。Lambdaがバッチを消費し、重要なレコードだけを転送します:
| stream record (NEW_IMAGE) | consumer action | ||
|---|---|---|---|
| TENANT#acme | EVENT#…#a2 | action=invoice.export | send to SIEM |
| TENANT#globex EVENT#…#b9 action=role.granted | page on-call | ||
| TENANT#acme | EVENT#…#a1 | action=login.success | ignore |
この関数はテーブルに一切触れません — ストリームが渡すものだけに純粋に反応します。ポーリングもスキャンもなく、書き込みから数秒以内にアラートが発火します。レコードはパーティションキーごとに順序付けされているため、あるテナントのすべてのイベントは書き込まれた順序で届きます。
これは下流のコピーを維持する標準的な方法でもあります。ストリームコンシューマーは各イベントを全文監査検索のためにOpenSearchへ投影したり、件数を集計したりできます — すべて同じ変更ログから派生します。
DynoTableでの実践
ストリームコンシューマーを組む前に、Lambdaが受け取るアイテムの正確な形 — どの属性が存在するか、ネストしたマップやリストがどう見えるか、NEW_IMAGEレコードが実際に何を含むか — を知っておく必要があります。
サンプルアイテムをプレーンなJSONとストリームレコードが使う属性値の形の間で変換するには、DynamoDB JSON Converterがブラウザ内で行います。そしてDynoTableでは、完全なアイテムを確認できます — DynamoDB-JSON形式も含めて — ので、フィールドの形を当て推量せず実データに対してNEW_IMAGEレコードをモデル化できます。

コンシューマーをローカルでテストしているなら、DynamoDB Localに対してテーブルを実行し、同じ方法で確認してください — DynamoDB Localへの接続を参照してください。
落とし穴と次のステップ
- 24時間はバックログではありません。 コンシューマーが1日ダウンしていると、レコードは期限切れになり失われます。Streamsはニアリアルタイムの反応のためであり、永続的なリプレイのためではありません — 履歴にはイベントそのものを保持してください。
- 必要な最小の
StreamViewTypeを選んでください。NEW_AND_OLD_IMAGESはペイロードを2倍にします。アイテムを再読み取りするためにキーだけが必要なら、KEYS_ONLYのほうが安価です。 - 順序付けはパーティションキー単位であり、グローバルではありません。 2つの異なるテナントのイベント間に順序保証はありません — 1つのテナントのパーティション内に限られます。
- TTL削除はシステム属性マーカー付きのストリームレコードとして現れます。 これが期限切れのアイテムをアーカイブする方法です — DynamoDB TTLを参照してください。
Streamsは監査ログをイベントソースに変えます。次の運用上の懸念は、アイテムのライフサイクルの反対側 — 古いイベントをDynamoDB TTLで自動的に期限切れにすることです。
Lambdaコードを1行書く前にストリームコンシューマーが受け取る正確なアイテムの形を確認するには、DynoTableをダウンロードしてください。


