Article

DynamoDBのフィルター付きS3エクスポートで、テナント単位の復旧を考える

DynamoDBのフィルター付きS3エクスポートは、PITRバックアップから項目と属性を選び、テーブルの読み取り容量を消費せずに出力できます。キー条件による処理量の削減と、増分出力を使った復旧で残るアプリケーション側の責任を整理します。

Share

こはるの読みどころ

「どのテナント」「いつの状態」「どの属性」を分けると、復旧用と共有用で必要な出力が変わる理由が見えてくるよ。読み取りを減らす条件と、書き出す内容を減らす条件にも注目してみよう!

こはるの読みどころ

複数の顧客を同じDynamoDBテーブルへ収めていると、「このテナントだけ、障害前の状態を取り出したい」という要求が出てきます。現在のデータを読むだけでは足りず、かといって関係のないテナントまで復元するのは作業が大きくなります。

2026年10月1日に発表されたフィルター付きS3エクスポートは、この取り出し方を変える機能です。過去のデータから必要な項目と属性を選べますが、取り出せたデータをそのまま本番へ戻してよいかは、別の判断になります。

そこで、読み取る範囲、過去の状態、書き戻す範囲を順に分けて考えてみましょう。テナント単位の復旧を起点にすると、共有や移行にも使える部分と、アプリケーション側に残る仕事が見えてきます。

過去のテナントを取り出せるのは、PITRバックアップを読むから

DynamoDBのS3エクスポートは2020年に登場し、2023年には指定期間の変更項目を取り出す増分エクスポートが加わりました。今回加わったのは、既存の ExportTableToPointInTime リクエストに FilterSpecification を指定し、項目や属性を選ぶ仕組みです。全量と増分の両方に適用でき、発表時点で全商用リージョンに提供されています。

読み取り先は稼働中のテーブルではなく、PITR(ポイントインタイムリカバリ)のバックアップです。そのため、エクスポートはテーブルの読み取り容量を消費しません。現在の項目を取得する Query に対し、全量エクスポートではPITRの保持期間内にある指定時点の状態を取り出せます。

ここでの「全量」は、選択した範囲のスナップショットという意味で捉えると分かりやすいですね。フィルターを使えば、テーブル全体ではなく特定テナントの全項目を対象にできます。

利用にはPITRの有効化が必要です。また、エクスポートは非同期処理で、完了時間を保証するSLAはありません。復旧計画へ組み込む場合、必ず一定時間で終わる処理として扱わない設計が必要です。この前提は既存のS3エクスポートの動作仕様でも説明されています。

キー条件は処理量を減らし、フィルターと射影は出力を絞る

FilterSpecification の中でも、3種類の式は働く場所が異なります。この違いは、出力内容だけでなく費用を考えるときにも効いてきます。

指定する式 選ぶもの 読み取り・出力への作用
KeyConditionExpression 1つのパーティションキー値と、任意のソートキー条件 読み取る範囲を限定し、処理量を減らす
FilterExpression 属性値の条件に一致する項目 読み取り後に適用され、処理量は減らさない
ProjectionExpression 書き出す属性 出力する項目の中身を限定する

たとえば、テナントIDがテーブルのパーティションキーなら、キー条件で1テナントを選べます。一方、テナントIDを通常の属性として持つ構成でフィルターだけを使っても、同じ読み取り削減にはなりません。キー条件はパーティションキーの等価条件が基本で、任意に複数のテナントを列挙する仕組みではありません。発表時点ではセカンダリインデックスも対象外です。

次は、TenantId がパーティションキー、WorkOrderId がソートキーであるテーブルを想定した、共有用のリクエスト断片です。属性名とテナント値は例であり、完全なAPIリクエストではありません。

JSON
{
  "FilterSpecification": {
    "KeyConditionExpression": "#tenant = :tenant",
    "ProjectionExpression": "#tenant, #order, #status",
    "ExpressionAttributeNames": {
      "#tenant": "TenantId",
      "#order": "WorkOrderId",
      "#status": "Status"
    },
    "ExpressionAttributeValues": {
      ":tenant": { "S": "tenant-example" }
    }
  }
}

この指定では、テナントをキー条件で選び、出力属性を3つに限定します。ExpressionAttributeNames は属性名の別名、ExpressionAttributeValues は値のプレースホルダーです。Status のような予約語を式で扱う際にも、別名が役立ちます。

フィルタリング自体の追加料金はなく、全量・増分それぞれの既存のGB単価が使われます。ただし、出力が小さくなった割合だけエクスポート料金も下がる、とは限りません。読み取るデータを減らすキー条件と、読み取り後のフィルターを区別し、PITRやS3の保存・リクエスト料金も含めて考えたいところです。

増分出力の旧イメージは、障害直前の各更新を並べた履歴ではない

テナント全体の過去の状態が必要なら全量、障害期間に変わった項目を調べたいなら増分が候補になります。増分の時間幅は15分から24時間で、NEW_AND_OLD_IMAGES を選ぶと、変更項目について期間開始前の旧イメージと期間終了時の新イメージを取り出せます。

たとえば、ある項目が期間開始時に正常で、その後に正常な更新、さらに誤更新を受けたとします。旧イメージが示すのは期間開始前の状態なので、誤更新の直前にあった正常な更新まで自動的に保存してくれるわけではありません。

この違いは復旧結果に直結します。

増分エクスポートの出力仕様では、期間内の挿入は新イメージ、削除は旧イメージで表され、期間内に挿入して削除した項目は出力されません。すべての更新を順番に再生する監査ログとして使うのではなく、期間の前後で状態を比べるためのデータです。

復旧用には属性を削らずに取り出し、誤更新の特徴を調べてから書き戻す対象を決めます。PutItem で旧イメージを戻すと項目全体を置き換えるため、障害後の正しい更新を上書きしない条件が必要です。更新日時やバージョンを使う場合も、その値をすべての書き込み経路で更新していることが前提になります。

エクスポートが読み取り容量を使わなくても、本番への書き戻しは通常の書き込みです。復旧ジョブの負荷や競合は別に設計します。また、エクスポートはトランザクションを認識しないため、複数項目にまたがる業務上の整合性まで復旧データだけで保証できるとは考えない方がよいでしょう。

共有用の属性選択と、復旧用の完全な項目を分ける

復旧では完全な項目を残したい一方、外部へ共有するときは必要な属性だけに絞りたい場面があります。ProjectionExpression は含める属性を列挙する方式なので、顧客のメールアドレスや電話番号を出力対象から外せます。前のJSON例も、この共有用途の形です。

ただし、属性選択は値の内容を検査しません。共有対象にした自由記述欄へ個人情報が入力されていれば、その値も出力されます。「この属性は共有してよい」という判断まで、エクスポートが代わりに行うわけではありません。

そこで、共有先に必要な属性の一覧を決め、その一覧を射影として管理する方法が考えられます。同じテナントを選ぶ場合でも、共有用の射影付き出力と復旧用の完全な出力は、用途に合わせて分けるのが自然です。共有相手へ渡すS3の場所も、どちらの成果物なのか明確にしておきたいですね。

リージョン移行では、エクスポート後の更新をどう渡すか決める

この選択の仕組みは、1テナントを別リージョンへ移すときにも使えます。指定時点の全量エクスポートを移行先のS3へ出力し、そこからDynamoDBへインポートする流れです。エクスポート先には別アカウントや別リージョンのバケットも指定できます。

ただし、S3からのインポートは新しいテーブルを作成します。既存の共有テーブルへそのまま追加する機能ではありません。移行先にすでにテーブルがあるなら、別の書き込み処理を設計する必要があります。

さらに、スナップショットの時点から接続先を切り替えるまでに発生した更新は、アプリケーション側で引き継ぎます。書き込みを止めて差分をなくすのか、更新を捕捉して反映するのかを決めないままでは、出力できても移行は完了しません。元テーブルの項目も自動削除されません。

テナント単位の復旧や移行で小さくできるのは、まず「取り出す作業」です。その先の正しい復旧・切り替えには、対象時点と属性を選ぶだけでなく、後から起きた変更を守る設計が要ります。まず自分のテーブルでテナントをキー条件にできるかを確かめると、この機能をどこへ組み込めるか判断しやすくなります。

出典

Share

Related Articles

カテゴリやタグが近い記事を続けて読めるように並べています。