AWS Labs製OSS「DynamoDB Optima」でDynamoDBのCapacity Mode・Table Class・Utilization最適化を試してみる

AWS Labs製OSS「DynamoDB Optima」でDynamoDBのCapacity Mode・Table Class・Utilization最適化を試してみる

DynamoDBのキャパシティモードやTable Classが本当に最適か気になったことはありませんか?AWS LabsがOSSで公開している`DynamoDB Optima`を使って、複数テーブル規模のコスト最適化分析を試してみたので、その内容をまとめます。
2026.08.03

はじめに

データ事業本部のkobayashiです。

DynamoDBを運用していると、テーブルのキャパシティモードやTable Classが今の使い方にとって本当に適切なのか気になるということはよくあるかと思います。CloudWatchメトリクスとCost and Usage Report(CUR)を突き合わせれば分析はできますが、複数アカウント・複数リージョン・数百テーブル規模になると自前で分析基盤を作るのはそれなりに手間がかかります。

そこで今回はAWS LabsがOSSで公開しているDynamoDBコスト最適化ツールDynamoDB Optimaを、discoverからanalyze-*まで試してみたのでその内容をまとめます。

DynamoDB Optimaとは

DynamoDB OptimaはAWS LabsがOSSとして公開しているDynamoDBコスト最適化プラットフォームで、リポジトリのREADMEでは以下のように3種類の分析軸が定義されています。

分析種別 ユースケース データソース 想定削減幅(README記載値)
Capacity Mode On-Demand ↔ Provisioned の切り替え判定 CloudWatchメトリクス キャパシティコストの30〜70%
Table Class Standard ↔ Standard-IA の切り替え判定 Cost & Usage Report ストレージコストの30〜60%
Utilization 過剰プロビジョニングされたキャパシティのライトサイジング CloudWatchメトリクス 無駄キャパシティの20〜50%

主な特徴としては以下になります。

  • AWS Organizationsに対応: --use-orgオプションでマネジメントアカウントから全メンバーアカウントを横断してテーブルをディスカバリ可能
  • DuckDBバックエンド: 収集したメトリクス・料金データはローカルのDuckDBに蓄積され、分析クエリが高速に走る
  • Streamlit製のGUIダッシュボード: dynamodb-optima guiで対話的な可視化がすぐ立ち上がる
  • AWS Pricing APIによる実勢価格計算: フリーティア込みでレコメンド金額を試算
  • チェックポイント機構(開発中・docs/command-reference.mdに「2026年2月時点で未検証(untested as of February 2026)」と明記): --resume / --operation-id / status / checkpointsはCLIには存在しますがdocsに「期待通り動作しない可能性がある」と書かれているため、現時点では利用しない前提で検討するのが安全(本記事も検証対象外としました)
  • 最小権限のIAM: マネジメントアカウント用に必要なアクションをREADME.mdで列挙。クロスアカウント時はOrganizationAccountAccessRole等をAssumeRoleする構成

分析ロジックのざっくり

docs/analysis-deep-dive.mdにロジックが明文化されており、大まかには以下のような形です。

  • Capacity Mode: CloudWatchメトリクスの14日ぶんからAutoScalingをシミュレーションしてOn-Demand/Provisionedの月次コストを比較
  • Table Class: CURからストレージ課金/スループット課金の比率を計算し、Standard-IAのほうが安くなるテーブルを候補として抽出
  • Utilization: --threshold(既定45%)を下回るテーブルを候補にし、Provisionedで極端に使用率が低ければOn-Demand切替、そうでなければキャパシティ削減を提案

docsとソースコードで細かい閾値や係数が食い違っている箇所もあるため、Table Class・Utilizationの推奨は最終的な想定コストを個別に確認するのが安全です。

利用可能なCLIコマンド

dynamodb-optima --helpで確認できるコマンド群は以下です。

コマンド 概要
version バージョン表示
health ローカルDB、AWS接続、システムリソースのヘルスチェック
discover DynamoDBテーブルとGSIをディスカバリ、料金データも取得
collect CloudWatchメトリクスを収集(既定14日ぶん)
collect-cur CURデータをS3から取得(Table Class分析用)
analyze-capacity On-Demand vs Provisionedの推奨を出力
analyze-table-class Standard vs Standard-IAの推奨を出力
analyze-utilization 過剰プロビジョニングの検出と推奨キャパシティ算出
gui Streamlitダッシュボードを起動
status / checkpoints 操作状態とチェックポイントの表示(開発中)

DynamoDB Optimaを試してみる

環境

今回使用した環境は以下の通りです。

Python 3.12.x
dynamodb-optima 1.0.0
boto3 1.40.61
duckdb 1.5.4
streamlit 1.58.0
リージョン: ap-northeast-1(単一アカウント)

前提条件

README.mdPrerequisitesセクションに以下が明記されています。

  • Python 3.12以上
  • AWS認証(aws configureもしくは環境変数)
  • 空きメモリ2GB程度
  • マネジメントアカウント側のIAM権限(DynamoDB ListTables / DescribeTable、CloudWatch GetMetricData / GetMetricStatistics、Pricing GetProducts、STS AssumeRole、Organizations DescribeOrganization / ListAccounts、CUR DescribeReportDefinitions
    • READMEのポリシー例にはdynamodb:ListTagsOfResourceも含まれていますが、これは将来拡張用で現時点では必須ではありません
  • Table Class分析を行う場合はCUR格納S3のListBucket/GetObject

Organizations関連の権限は--use-orgモードでのみ必要で、CURも Table Class分析を行わないなら不要です。

インストール

Optimaはpyproject.tomlで配布されているので、リポジトリをcloneしてからpip installで入れます。READMEでは開発依存も含む.[dev]が推奨されているので、テストやリンタも回したい場合はそちらを、CLIとGUIだけ動かしたい今回のケースは.のみでも動きます。

$ git clone https://github.com/awslabs/amazon-dynamodb-tools.git
$ cd amazon-dynamodb-tools/tools/dynamodb-optima
$ python3.12 -m venv .venv

# READMEの推奨(開発依存込み)
$ .venv/bin/pip install -e ".[dev]"

# 今回試した最小構成
$ .venv/bin/pip install -e .

インストール後、dynamodb-optimaコマンドが使えるようになります。

$ dynamodb-optima version
DynamoDB Optima version 1.0.0

--helpでコマンド一覧を確認します。

$ dynamodb-optima --help
Usage: dynamodb-optima [OPTIONS] COMMAND [ARGS]...

  DynamoDB Optima - Unified cost optimization and analysis platform for Amazon
  DynamoDB.

Options:
  --debug                   Enable debug mode
  --log-level TEXT          Set logging level
  --project-root DIRECTORY  Project root directory for data and logs (useful
                            for multi-organization setups)
  --help                    Show this message and exit.

Commands:
  analyze-capacity     Analyze capacity modes and generate On-Demand vs...
  analyze-table-class  Analyze table class and generate Standard ↔...
  analyze-utilization  Analyze provisioned capacity utilization and...
  checkpoints          Manage operation checkpoints.
  collect              Collect CloudWatch metrics for DynamoDB tables.
  collect-cur          Collect CUR data from S3 for table class analysis.
  discover             Discover DynamoDB tables and GSIs across AWS regions.
  gui                  Launch interactive Streamlit GUI for analysis and...
  health               Check system health and operational status.
  status               Show current operation status and checkpoint...
  version              Show version information.

healthコマンドでシステムチェック

healthはローカルDuckDB、AWS接続、システムリソースの状態を1コマンドで確認できます。

$ dynamodb-optima health
⚠️ System Health Status: WARNING

⚠️ System Resources: Disk usage high: 87.1%
   cpu_percent: 33.1
   memory_percent: 73.1
   memory_available_gb: 8.60
   disk_percent: 87.1
   disk_free_gb: 53.87
 Database: Database healthy (13 tables, 1.3 MB)
 Aws Connectivity: AWS connectivity healthy (all 3 services across 1 account)
   management_account_id: xxxxxxxxxxxx
   management_user_arn: arn:aws:sts::xxxxxxxxxxxx:assumed-role/xxxx/botocore-session-xxxxxxxxxx

   Optional Services (3/3):
 s3 (global): S3 bucket access (for CUR data)
 organizations (global): Organizations API (multi-account)
 pricing (us-east-1): Pricing API (cost calculations)

📊 System Metrics:
   CPU: 4.8%
   Memory: 73.9% (8.4 GB available)
   Disk: 87.1% (53.9 GB free)
   Uptime: 16s

DuckDB上に既に13テーブルの内部スキーマが用意されており、AWSの必須/オプションサービス(S3, Organizations, Pricing)すべてに疎通できていることがわかります。

discoverでDynamoDBテーブルを洗い出す

準備が整ったらdiscoverでDynamoDBテーブルを列挙します。今回はap-northeast-1の単一アカウントで実行しました。

$ dynamodb-optima discover --regions ap-northeast-1
🔍 Starting discovery across 1 regions...

...
 Discovery completed successfully!

💰 Collecting DynamoDB pricing data...

 Pricing data collection complete!

📊 Discovery Summary:
   Total tables: 140
   Total GSIs: 99

   By Region:
      ap-northeast-1: 140 tables, 99 GSIs
         (140 On-Demand, 0 Provisioned)

📊 Discovering CUR reports with HOURLY granularity...

⚠️  No HOURLY Parquet CUR reports found
   To enable table class analysis:
   1. Enable Cost and Usage Reports in AWS Billing Console
   2. Configure report with:
      - Format: Parquet
      - Granularity: HOURLY (required)
      - Include Resource IDs: Recommended

💡 Next steps:
   1. Run 'dynamodb-optima collect' to gather CloudWatch metrics
   2. Run 'dynamodb-optima analyze-capacity' for capacity mode analysis

140テーブル・99GSIが検出され、すべてOn-Demandモードで運用されていることがわかりました。実行後はローカルのdata/metrics_collector.db(DuckDB)にディスカバリ結果と料金データが書き込まれています。

$ ls -lh data/
-rw-r--r--@ 5.0M metrics_collector.db

CURのHOURLY Parquetレポートが見つからないという警告が出ていますが、これはこちらのアカウントで AWS Billingコンソール上でCUR設定を行っていない ためです。Table Class分析はCUR必須なので、そちらを試したい場合は事前にCUR設定を作っておく必要があります。CUR設定は Format: Parquet, Granularity: HOURLY, Include Resource IDs: 有効 の3点セットが要件になっています。

collectで14日ぶんのCloudWatchメトリクスを収集する

discoverで見つけた140テーブル+99GSIに対して、collectで14日ぶんのCloudWatchメトリクスを取得します。今回は絞り込みなしで全リソース対象で実行しました。

$ dynamodb-optima collect --days 14

📊 CloudWatch Metrics Collection
   Time range: 2026-07-03 to 2026-07-17 (14 days)
   Regions: 1 discovered
   Tables: All discovered
   Accounts: 1
   Metrics: Standard (8 configurations)

  AWS credentials validated successfully
  Resources prepared for collection
Collecting 239 resources
...
Metrics collection completed.

 Collection completed successfully!

📊 Collection Summary:
   Accounts accessed: 1
   Total metrics collected: 0
   Resources processed: 239
   Successful collections: 239
   Failed collections: 0
   Regions processed: 1
   Duration: 0:26:31.122306

💾 Database Summary:
   Total metrics in database: 23,992,468
   Total resources: 206
   Total regions: 1

💡 Next steps:
   1. Run 'dynamodb-optima analyze-capacity' to optimize capacity modes
   2. Run 'dynamodb-optima analyze-utilization' to check usage patterns

26分31秒 で239リソースぶんのメトリクスが集まり、DuckDB上には約 2400万件 のメトリクスレコードが蓄積されました。CloudWatch API呼び出しはGetMetricDataが中心で、金額としてはほぼ無視できる範囲です。README記載の10〜60分の目安に対して26分だったので概ね想定内でした。

なお、Total metrics collected: 0という表示は、表示側の集計値と実際のDB挿入件数が別扱いになっているために出るもので、実際にはDBに2400万件書き込まれています。実DBの内容はTotal metrics in database側を参照するのが正しいです。

analyze-capacityでOn-Demand/Provisionedを比較する

メトリクスが揃ったらanalyze-capacityで「今のCapacity Modeとレコメンドの差」を分析します。まずはデフォルト(--min-savings 10.0)で流します。

$ dynamodb-optima analyze-capacity
Analyzing all tables...
Analysis window: 14 days

No recommendations found with the specified criteria.

「月$10以上の節約になるテーブルはない」という結果になったので、しきい値を--min-savings 0まで下げて全レコメンドを見てみます。

$ dynamodb-optima analyze-capacity --min-savings 0
+----------------------------+----------------+---------+-----------+---------------+-------------+------------+-----------+----------+------+
| Table                      | Region         | Class   | Current   | Recommended   | Curr Cost   | Rec Cost   | Savings   | Save %   | OK   |
+----------------------------+----------------+---------+-----------+---------------+-------------+------------+-----------+----------+------+
| (table redacted)           | ap-northeast-1 | STA     | ON_DEMAND | ON_DEMAND     | $0.01       | $0.01      | $0.00     | 0.0%     |    |
| (table redacted)           | ap-northeast-1 | STA     | ON_DEMAND | ON_DEMAND     | $0.00       | $0.00      | $0.00     | 0.0%     |    |
| ...                        | ...            | ...     | ...       | ...           | ...         | ...        | ...       | ...      | ...  |
+----------------------------+----------------+---------+-----------+---------------+-------------+------------+-----------+----------+------+

================================================================================
Total potential savings: $0.00/month
Not optimized: 0 out of 242 recommendations
================================================================================

242件のレコメンドが並び、すべてCurrent=ON_DEMAND, Recommended=ON_DEMAND, Savings=$0.00となりました。今回の対象アカウントはトラフィックがほぼ動いていないサンドボックス相当だったため、「そもそもコストがほぼ発生していない → 切り替えても節約にならない → 現状維持がベスト」という妥当な判断が下されたと読めます。Not optimized: 0 out of 242 recommendationsマークも「すでに最適」の意味で、実運用テーブルであればここにが付いてキャパシティモード変更の提案が出てくることになります。

analyze-utilizationで過剰プロビジョニングを探す

続けてanalyze-utilizationもかけてみます。

$ dynamodb-optima analyze-utilization --min-savings 0
Analyzing utilization for all provisioned tables...
Analysis window: 14 days
Utilization threshold: 45.0%

No underutilized resources found with the specified criteria.

💡 This is good news! Your provisioned capacity appears well-utilized.

今回のアカウントには先ほどのdiscover結果でProvisionedモードのテーブルが0件だったので、analyze-utilizationは原理的にレコメンド対象がなく「解析対象なし=過剰プロビジョニング検出ゼロ」となりました。Provisionedモードでtargetした使用率を大幅に下回るテーブルがある環境では、ここに「現行RCU/WCU → 推奨値 → 想定節約額」の一覧が並ぶ想定です。

--table書式の使い分けとCUR分析

分析コマンドの--table引数は、analyze-capacityanalyze-utilizationで書式が違うため注意が必要です。

# analyze-capacityは account_id:region:table_name
$ dynamodb-optima analyze-capacity --table 123456789012:ap-northeast-1:my-table --min-savings 0

# analyze-utilizationは CLIヘルプ上は region:table_name
$ dynamodb-optima analyze-utilization --table ap-northeast-1:my-table

ただしanalyze-utilization --tableは、1.0.0時点のソースコード(commands/analysis/analyze_utilization.py)で呼び出し側とanalysis/utilization.py:analyze_tableの引数位置がずれており(呼び出し側は(region, table_name, days, threshold, min_savings)を渡すのに対し、被呼び出し側は(account_id, region, table_name, days, threshold, min_savings)を期待)、単一アカウント環境では引数の位置ズレが発生する疑いがあります。テーブル絞り込みはanalyze-utilization側では避けて全件解析後にレコメンドを絞り込むか、必要であれば--min-savingsとテキスト検索で絞る方が安全そうです。

Table Class分析(Standard ↔ Standard-IA)については、今回の環境ではCURが設定されていないため実測できませんでした。CURを設定済みの環境であれば以下のようにcollect-curanalyze-table-classの順で分析できます。

# 3か月ぶんのCURデータを取得
$ dynamodb-optima collect-cur --months 3

# 分析:Standard→Standard-IAで月50USD以上の節約が見込めるテーブルを抽出
$ dynamodb-optima analyze-table-class

# 6か月ぶん・100USD以上に条件を厳しくする(先に6か月ぶんの収集が必要)
$ dynamodb-optima collect-cur --months 6 --force
$ dynamodb-optima analyze-table-class --min-savings 100 --months 6

analyze-table-class --monthsは「分析対象のCURデータ期間」なので、collect-cur --monthsで事前に必要な期間ぶんのCURを取得しておく必要があります。既存のCURデータを再収集する場合は--forceを付けます。

いずれの分析コマンドも--format table|json|csvで出力形式を切り替えられます。

Streamlit GUIで可視化する

guiサブコマンドでStreamlitダッシュボードが立ち上がります。

$ dynamodb-optima gui
# ブラウザで http://localhost:8501 を開く

なお、dynamodb-optima guiは内部でstreamlitコマンドをPATH検索してサブプロセス起動するため、複数のvenvが混在している環境だと別venvのstreamlitがロードされてModuleNotFoundError: No module named 'dynamodb_optima'で落ちることがあります。その場合はPATH="$PWD/.venv/bin:$PATH" dynamodb-optima guiのようにOptimaを入れたvenvのbinをPATH先頭に置いてから起動すると解消します。

また、GUI起動中はStreamlitがDuckDBファイルを排他ロックするので、あとからanalyze-capacity / analyze-utilizationを追い焚きしたい場合は一度GUIを止めてから実行する必要があります。

トップの Cost Optimization Dashboard ではKPIカード(Monthly Savings、Total Recommendations、Tables Analyzed、Optimization Rate)とレコメンド分布グラフ、Top Savings Opportunities一覧を確認できます。今回の環境ではすべてOn-Demandかつ課金が発生していないので節約額は$0.00表示ですが、Recommendations by TypeにCapacity Modeカテゴリの件数(今回は137件)が積まれています。

スクリーンショット 2026-07-25 6.35.08

サイドバーの Capacity Mode Analysis ではOn-Demand ↔ Provisionedの変更提案がテーブル単位で並びます。上部にはTop 10 Tables by SavingsとRecommendation Distribution(To ON_DEMAND / To PROVISIONED の円グラフ)が表示され、下部の Detailed Recommendations では各テーブルの提案内容を展開できます。今回は全テーブルOn-Demandで節約額$0.00のため、Mode Changesは「137 → On-Demand」「0 → Provisioned」と現状維持推奨に集約されています。

スクリーンショット_2026-07-25_6_35_28

Utilization Analysis は過剰プロビジョニングされたテーブルを一覧表示するビューで、今回のようにProvisionedモードのテーブルが0件だと「No utilization recommendations found matching the current filters.」の空表示になります。Provisionedモードのテーブルがある環境では、現行RCU/WCUと推奨キャパシティ・想定節約額の一覧がここに並びます。

スクリーンショット 2026-07-25 6.40.01

サイドバーのフィルタからは、Minimum Monthly Savingsのしきい値変更、Region / Account でのフィルタ、Table Name (regex)による正規表現絞り込みが対話的に行えます。CLIから同じ分析結果をたぐりに行くよりも見通しがよく、Organizations規模の分析結果を眺めるときは重宝しそうです。

AWS Organizationsでの複数アカウント運用

単一アカウントだけでなく--use-orgオプションを付けることで、AWS Organizationsを通じて全メンバーアカウントを横断ディスカバリできます。

# Organizations全体(全アカウント、全リージョン)
$ dynamodb-optima discover --use-org

# カスタムロール名を指定
$ dynamodb-optima discover --use-org --org-role CustomRole

# 特定アカウントをスキップ
$ dynamodb-optima discover --use-org --skip-accounts 111122223333,444455556666

CLI/config上の既定アシューム対象はOrganizationAccountAccessRoleですが、各メンバーアカウント側にこのロール(もしくは指定した独自ロール)が必要になります。docs/aws-organizations-setup.mdではMetricsCollectorRoleを作る例が示されているので、そのガイドに従う場合は--org-role MetricsCollectorRoleを明示的に指定します。詳細な設定手順は同ドキュメントにまとめられているのでOrganizations環境で使うときはそちらを参照するとよいです。

プロジェクトの分離

複数のOrganizationやチェックポイントを混ぜたくない場合は--project-rootでデータディレクトリを分離できます。

$ mkdir org-a
$ dynamodb-optima --project-root org-a discover --use-org

org-a配下にDuckDBファイル、チェックポイント、ログがまとめて出力されるので、Organizationごと・環境ごとに使い分けられます。

まとめ

AWS Labs製のDynamoDBコスト最適化ツール DynamoDB Optima を、discoverからguiまで一通り試してみました。pip install -e .だけでCLIとStreamlit GUIが揃い、複数アカウント・複数リージョン規模のDynamoDBに対してキャパシティモード・Table Class・過剰プロビジョニングのレコメンドを一気に得られるので、DynamoDBのコスト最適化に取り組んでいる方はぜひ試してみてください。

最後まで読んで頂いてありがとうございました。

この記事をシェアする

関連記事