上級読了 2 分

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**を選びます。これは各レコードが変更されたアイテムをどれだけ運ぶかを制御します:

StreamViewTypeeach record contains
KEYS_ONLYonly the key attributes of the changed item
NEW_IMAGEthe entire item as it looks after the change
OLD_IMAGEthe entire item as it looked before the change
NEW_AND_OLD_IMAGESboth the before and after images

レコードは各パーティションキー内で順序付けされ、ストリームはテーブルと同じパーティション構造に沿ってシャーディングされます。保持期間は24時間です — Streamsは反応のためのバッファであり、恒久的な履歴ではありません。永続的な履歴には、イベントそのものを保存します(まさにこの監査ログテーブルがすでにそうしているものです)。

ネイティブのコンシューマーはLambdaトリガーです。DynamoDBは新しいストリームレコードのバッチが届くたびに、それを引数として関数を呼び出します。

LambdaStream"DynamoDB"AppLambdaStream"DynamoDB"App"Put EVENT role.granted""change record (NEW_IMAGE)""batch of records""if action is sensitive →alert"

実例:機密性の高い監査イベントでアラート

監査ログテーブルにはNEW_IMAGEのストリームが設定されており、各レコードは完全な新しいイベントを運びます。Lambdaがバッチを消費し、重要なレコードだけを転送します:

stream record (NEW_IMAGE)consumer action
TENANT#acmeEVENT#…#a2action=invoice.exportsend to SIEM
TENANT#globex EVENT#…#b9 action=role.grantedpage on-call
TENANT#acmeEVENT#…#a1action=login.successignore

この関数はテーブルに一切触れません — ストリームが渡すものだけに純粋に反応します。ポーリングもスキャンもなく、書き込みから数秒以内にアラートが発火します。レコードはパーティションキーごとに順序付けされているため、あるテナントのすべてのイベントは書き込まれた順序で届きます。

これは下流のコピーを維持する標準的な方法でもあります。ストリームコンシューマーは各イベントを全文監査検索のためにOpenSearchへ投影したり、件数を集計したりできます — すべて同じ変更ログから派生します。

DynoTableでの実践

ストリームコンシューマーを組む前に、Lambdaが受け取るアイテムの正確な形 — どの属性が存在するか、ネストしたマップやリストがどう見えるか、NEW_IMAGEレコードが実際に何を含むか — を知っておく必要があります。

サンプルアイテムをプレーンなJSONとストリームレコードが使う属性値の形の間で変換するには、DynamoDB JSON Converterがブラウザ内で行います。そしてDynoTableでは、完全なアイテムを確認できます — DynamoDB-JSON形式も含めて — ので、フィールドの形を当て推量せず実データに対してNEW_IMAGEレコードをモデル化できます。

Lambdaコンシューマーが受け取るNEW_IMAGEストリームレコードをモデル化するため、監査イベントアイテムをDynoTableで確認しているところ。
Lambdaコンシューマーが受け取るNEW_IMAGEストリームレコードをモデル化するため、監査イベントアイテムをDynoTableで確認しているところ。

コンシューマーをローカルでテストしているなら、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をダウンロードしてください。

更新日