Serverless Operations, inc

>_cd /blog/id_81an1c5tpe18

title

ExtendDB:DynamoDB互換のオープンソースアダプターを試してみた

AWSが2026年5月にオープンソースプロジェクト「ExtendDB」を公開しました。一言で言うと、DynamoDBのAPIをそのまま使いながら、PostgreSQLなど別のストレージで動かせるアダプターです。

なぜExtendDBが生まれたのか

Amazon DynamoDBはAWSを代表するNoSQLデータベースです。高速で使いやすく、多くのチームがDynamoDBを中心にアプリケーションを構築しています。しかしその分、DynamoDBへの依存度も高くなります。

問題になるのが、クラウドに接続できない環境です。たとえば航空会社の搭乗ゲートシステムや機内販売システムは、ネットワーク障害中でも動き続けなければなりません。しかしDynamoDBはAWS上のマネージドサービスのため、クラウド接続なしには使えません。結果として、開発チームはオンプレミス向けに別のデータアクセス層を作り、2つのコードベースを維持するという二重のコストを強いられてきました。

ExtendDBはこの課題を解決するために作られました。

ExtendDBとは何か

ExtendDBはRust製のアダプターで、DynamoDBのワイヤープロトコルを実装しています。アプリケーションから見るとDynamoDBと全く同じAPIに見えますが、実際のデータはPostgreSQLに保存されます。既存のAWS SDK・CLI・ツール類は一切変更不要で、エンドポイントのURLを差し替えるだけで接続先をDynamoDB↔ExtendDBで切り替えられます。

主なユースケースは3つです。

  1. ローカル開発・CI/CD ではクラウドへの依存なしにDynamoDBのコードをそのまま動かせます。テストがすぐ起動し、クリーンに終了します。
  2. オンプレミス・エアギャップ環境 では、クラウド非接続の環境でもDynamoDB APIを使い続けられます。冒頭の航空会社の例がまさにこのケースです。
  3. マルチクラウド・ハイブリッド では、PostgreSQLが動く場所ならどこでもDynamoDB APIを使えるため、インフラの選択肢が広がります。

技術的な特徴

ExtendDBはシングルバイナリで動作し、外部ランタイムは不要です。ストレージ層はRustのトレイトで抽象化されており、現在はPostgreSQLが実装されていますが、将来的にはCassandraなど他のバックエンドも追加できる設計になっています。セキュリティ面ではTLSが必須で、自己署名証明書を自動生成します。認証はAWS SDKと同じSigV4署名方式を採用しており、アプリコードの変更が不要です。

対応している操作も充実しており、テーブル操作・アイテムのCRUD・クエリ・スキャン・トランザクション・Streams・TTLなど、DynamoDBの主要な機能をカバーしています。

注意点

ExtendDBはあくまでv0.1の開発・実験段階のリリースです。マネージドDynamoDBの代替ではなく、パフォーマンス特性や運用特性は異なります。またグローバルテーブルやクロスリージョンレプリケーションは非対応です。認証情報はExtendDB独自の実装でAWS IAMとは別物のため、本番のAWSリソースと混在して使うことはできません。

開発・テスト・オンプレミス用途であれば、すぐに試せる面白いプロジェクトです。Apache 2.0ライセンスで公開されており、コントリビューションも歓迎されています。

さっそくやってみる

環境は Amazon Linux 2023 on Amazon EC2 を使います。

まずデータバックエンドとしてPostgreSQL16をインストールします。

sudo dnf update -y
sudo dnf install -y postgresql16 postgresql16-server

sudo postgresql-setup --initdb

sudo systemctl enable postgresql
sudo systemctl start postgresql

sudo systemctl status postgresql | head -5

Active: active (running) と表示されていれば成功です。

次にPostgresへ接続するユーザーを作成します。そのままデフォルトにシェルへアクセスしている ec2-user を作成します

sudo -u postgres psql -c "CREATE USER \"ec2-user\" WITH SUPERUSER PASSWORD 'mypassword';"

sudo sed -i 's/^local   all             all                                     peer/local   all             all                                     md5/' /var/lib/pgsql/data/pg_hba.conf
sudo sed -i 's/^host    all             all             127.0.0.1\/32            ident/host    all             all             127.0.0.1\/32            md5/' /var/lib/pgsql/data/pg_hba.conf

sudo cat /var/lib/pgsql/data/pg_hba.conf | grep -v "^#" | grep -v "^$"

sudo systemctl restart postgresql

次のステップではExtendDBの実装に使われているRustをインストールします。

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 途中の選択肢は「1」を押してデフォルトインストールします

source ~/.cargo/env

# 1.85以上であることを念のため確認します
rustc --version

必要な依存パッケージをインストールします

sudo dnf install -y git gcc openssl-devel pkg-config

ExtendDBGitからパッケージをダウンロードしビルドを行います。

git clone https://github.com/ExtendDB/extenddb.git
cd extenddb

cargo build --release

では ExtendDB を初期化して、起動します。

./target/release/extenddb init --pg-pass mypassword
./target/release/extenddb serve --config extenddb.toml

以下で表示される部分を保存しておきます。

 --- Creating default account '909818950741'...
    Account ID: 909818950741
<snip>
 ┌─────────────────────────────────────────────────┐
  │  Admin credentials (shown once, save them now)  │
  │                                                 │
  │  Username: admin                                │
  │  Password: n6cvY90YjtCQD9fQKuceDiJA             │
  └─────────────────────────────────────────────────┘

extendDBへアクセスするためのシークレットを発行します。 <admin-passowrd><account-id>は環境ごとに異なりますので置き換えて下さい。

>./target/release/extenddb manage \
  --user admin --password '<admin-password>' \
  create-user --account-id <account-id> --user-name myuser

./target/release/extenddb manage \
  --user admin --password '<admin-password>' \
  put-user-policy --account-id <account-id> --user-name myuser \
  --policy-name full-access \
  --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"dynamodb:*","Resource":"*"}]}'

./target/release/extenddb manage \
  --user admin --password '<admin-password>' \
  create-access-key --account-id <account-id> --user-name myuser

そうするとダミーのIAMクレデンシャルが発行されます。これはAWSアカウントとは紐づいていませんので注意してください。ただし環境を切り替えればそのままDynamoDBへ接続できるのがExtendDBの特徴ですので、本物と同じ構造をしています。

IAM user created
{
  "access_key_id": "AKIAEXTENDDBE3K2Y6FY",
  "secret_access_key": "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"
}

発行されたクレデンシャルを環境変数にセットします。

export AWS_ACCESS_KEY_ID="AKIAEXTENDDBE3K2Y6FY"
export AWS_SECRET_ACCESS_KEY="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"
export AWS_CA_BUNDLE=~/.extenddb/tls/cert.pem

では AWS CLI でDynamo DBと同じ操作を行います。

# テーブル作成
aws dynamodb create-table \
  --table-name Orders \
  --attribute-definitions AttributeName=PK,AttributeType=S AttributeName=SK,AttributeType=S \
  --key-schema AttributeName=PK,KeyType=HASH AttributeName=SK,KeyType=RANGE \
  --billing-mode PAY_PER_REQUEST \
  --endpoint-url https://127.0.0.1:8000 \
  --region us-east-1

# アイテムの書き込み
aws dynamodb put-item \
  --table-name Orders \
  --item '{"PK":{"S":"CUSTOMER#123"},"SK":{"S":"ORDER#2026-001"},"total":{"N":"49.99"}}' \
  --endpoint-url https://127.0.0.1:8000 \
  --region us-east-1

# クエリで取得
aws dynamodb query \
  --table-name Orders \
  --key-condition-expression "PK = :pk" \
  --expression-attribute-values '{":pk":{"S":"CUSTOMER#123"}}' \
  --endpoint-url https://127.0.0.1:8000 \
  --region us-east-1
{
    "TableDescription": {
        "AttributeDefinitions": [
            {
                "AttributeName": "PK",
                "AttributeType": "S"
            },
            {
                "AttributeName": "SK",
                "AttributeType": "S"
            }
        ],
        "TableName": "Orders",
        "KeySchema": [
            {
                "AttributeName": "PK",
                "KeyType": "HASH"
            },
            {
                "AttributeName": "SK",
                "KeyType": "RANGE"
            }
        ],
        "TableStatus": "CREATING",
        "CreationDateTime": "2026-05-23T02:32:54.944013+00:00",
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "ReadCapacityUnits": 0,
            "WriteCapacityUnits": 0
        },
        "TableSizeBytes": 0,
        "ItemCount": 0,
        "TableArn": "arn:aws:dynamodb:us-east-1:909818950741:table/Orders",
        "TableId": "dd6c0856-48ae-4519-a793-45118e33b44c",
        "BillingModeSummary": {
            "BillingMode": "PAY_PER_REQUEST",
            "LastUpdateToPayPerRequestDateTime": "2026-05-23T02:32:54.944013+00:00"
        },
        "DeletionProtectionEnabled": false
    }
}

{
    "Items": [
        {
            "PK": {
                "S": "CUSTOMER#123"
            },
            "SK": {
                "S": "ORDER#2026-001"
            },
            "total": {
                "N": "49.99"
            }
        }
    ],
    "Count": 1,
    "ScannedCount": 1,
    "ConsumedCapacity": null
}

環境構築完了です!

PostgreSQL の中身

psql "postgresql://ec2-user:mypassword@localhost:5432/extenddb"
\dt
                           List of relations
 Schema |                   Name                    | Type  |  Owner   
--------+-------------------------------------------+-------+----------
 public | _ddb_dd6c0856-48ae-4519-a793-45118e33b44c | table | extenddb
 public | idempotency_tokens                        | table | extenddb
 public | stream_records                            | table | extenddb
 public | stream_shards                             | table | extenddb
(4 rows)
SELECT * FROM "_ddb_dd6c0856-48ae-4519-a793-45118e33b44c";
      pk      |      sk_s      | sk_n | sk_b |                                       item_data                                       
--------------+----------------+------+------+---------------------------------------------------------------------------------------
 CUSTOMER#123 | ORDER#2026-001 |      |      | {"PK": {"S": "CUSTOMER#123"}, "SK": {"S": "ORDER#2026-001"}, "total": {"N": "49.99"}}
(1 row)

DynamoDBのアイテムではそのままjsonとして格納されているようです。このため検索などにおけるパフォーマンスは注意が必要です。

Written by
編集部

亀田 治伸

Kameda Harunobu

  • Facebook->
  • X->
  • GitHub->

Share

Facebook->X->
Back
to list
<-