Amazon DynamoDB を構築してみた!~ SAA 試験対策にもなる実践記 ~
はじめに
AWS のフルマネージド型 NoSQL データベースサービスである Amazon DynamoDB を実際に構築してみた経験についてご紹介します。
実は、私は現在、AWS 認定ソリューションアーキテクト – アソシエイト (SAA) の資格取得に向けて学習を進めているのですが、DynamoDB に関する問題で特に苦戦することが多く、「実際に手を動かして理解を深めよう!」と考え、今回の構築に至りました。
このブログが、SAA の試験勉強をされている方や、これから DynamoDB を使ってみようと考えている方の参考になれば幸いです。
なぜ DynamoDB を選んだのか?(SAA 試験対策の観点から)
数あるデータベースサービスの中から、なぜ私が DynamoDB を選んだのか、その理由を簡単にご説明します。SAA の試験対策という観点も踏まえながら見ていきましょう。
スケーラビリティの高さ: SAA の試験では、Web アプリケーションの急激なアクセス増加に対応する設計がよく問われます。DynamoDB は自動的にスケールしてくれるため、こうした要件にマッチします。実際に構築することで、この概念を体感したかったのです。
フルマネージドサービス: SAA の試験では、運用負荷の軽減やコスト最適化の観点も重要です。DynamoDB はパッチ適用やバックアップなど、AWS が全て管理してくれるフルマネージドサービスであり、このメリットを実感したかったのが理由の一つです。
低レイテンシ: リアルタイム性が求められるユースケースは SAA でも頻出です。DynamoDB の高速な読み書き性能は、そうした要件を満たす上で不可欠であり、その性能を体感するためにも構築は有効だと考えました。
コスト効率: SAA の試験では、最適なサービス選択とコスト最適化が問われます。DynamoDB の使用量に応じた課金体系や、オンデマンド / プロビジョニング済みキャパシティ の選択は、まさに試験で問われる知識と直結します。
NoSQL データベースの理解: リレーショナルデータベースは普段から触れる機会が多いのですが、NoSQL データベース、特にキーバリュー型データベースの設計思想や使い方を深く理解することが、SAA の試験問題に対応する上で非常に重要だと感じました。
準備
AWS マネジメントコンソールにログイン
まずは、AWS マネジメントコンソールにログインし、DynamoDB のサービス画面へ移動します。
テーブルの作成
「テーブルの作成」ボタンをクリックし、以下の項目を設定していきます。
- テーブル名: 例: your-application-data (分かりやすい名前をつけましょう)
-
プライマリキー:
- パーティションキー: 例: user_id (データの分散を担うキーです。カーディナリティが高いものを選択するという SAA の鉄則を意識しました。)
- (オプション) ソートキー: 例: timestamp (パーティションキー内でデータをソートするために使います。プライマリキー設計の重要性を体感する上で、あえて複合プライマリキーを選んでみました。)
-
設定のカスタマイズ (読み込み/書き込みキャパシティモード):
- オンデマンド: アクセスパターンが予測できない場合や、突発的なアクセス増加に対応したい場合に適しています。費用対効果とスケーラビリティのバランスを学ぶため、今回はオンデマンドを選択しました。
- プロビジョニング済み: アクセスパターンが予測でき、一定のトラフィックが見込まれる場合にコスト効率が良いです。
-
(オプション) セカンダリインデックス: SAA の試験で頻繁に問われる、プライマリキー以外の属性での検索を可能にするための重要な要素です。
- グローバルセカンダリインデックス (GSI): プライマリキー以外の属性で検索したい場合に作成します。例: email-index (GSI のパーティションキー / ソートキーも設定します)。「なぜ GSI が必要なのか」「GSI のパーティションキー選定の注意点」などを意識しながら設定しました。
- ローカルセカンダリインデックス (LSI): プライマリキーと同じパーティションキーで、異なるソートキーを持つ場合に作成します。
- (オプション) 暗号化: デフォルトで AWS マネージドキーによる暗号化が有効になっていますが、KMS キーをカスタマイズすることも可能です。データのセキュリティも SAA で重要なポイントです。
- (オプション) タグ: リソース管理のためにタグを設定しておきましょう。
テーブル作成画面の例(イメージ)
DynamoDB テーブル作成画面(基本設定)
キャパシティモード選択画面
グローバルセカンダリインデックス(GSI)の設定
暗号化の設定
これらの設定が完了したら、「テーブルの作成」をクリックします。
データ登録
テーブルが作成されたら、実際にデータを投入してみましょう。ここでも「項目(Item)の構造」や「アトミック性」といった DynamoDB 特有の概念を意識しながら行いました。
AWS マネジメントコンソールの「項目」タブから手動で項目を追加する方法や、AWS CLI、SDK を使ってデータを投入する方法があります。今回は Python の boto3 を使って試しました。
import boto3
AWS_REGION = 'ap-northeast-1'
DYNAMODB_TABLE_NAME = 'dynamoDB-test'
dynamodb = boto3.resource('dynamodb', region_name=AWS_REGION)
table = dynamodb.Table(DYNAMODB_TABLE_NAME)
item = {
'user_id': 'user123',
'timestamp': '2025-06-10T15:00:00Z',
'username': 'taro yamada',
'email': 'taro@example.com',
'status': 'active'
}
try:
response = table.put_item(Item=item)
print('PutItem succeeded:', response)
except Exception as e:
print(f'Error putting item: {e}')
# --- AWS CLI で実行する場合の参考 ---
# aws dynamodb put-item \
# --table-name dynamoDB-test \
# --item '{
# "user_id": {"S": "user123"},
# "timestamp": {"S": "2025-06-10T15:00:00Z"},
# "username": {"S": "taro yamada"},
# "email": {"S": "taro@example.com"},
# "status": {"S": "active"}
# }'
# --return-consumed-capacity TOTAL # キャパシティユニット消費量を確認したい場合
実行結果
murofushi@K205-123 dynamo-db-test % python add_item.py
PutItem succeeded: {'ResponseMetadata': {'RequestId': 'GBJP30RQO124RG3LVB9SI945KNVV4KQNSO5AEMVJF66Q9ASUAAJG', 'HTTPStatusCode': 200, 'HTTPHeaders': {'server': 'Server', 'date': 'Tue, 10 Jun 2025 10:52:46 GMT', 'content-type': 'application/x-amz-json-1.0', 'content-length': '2', 'connection': 'keep-alive', 'x-amzn-requestid': 'GBJP30RQO124RG3LVB9SI945KNVV4KQNSO5AEMVJF66Q9ASUAAJG', 'x-amz-crc32': '2745614147'}, 'RetryAttempts': 0}}
DynamoDB マネジメントコンソールでの項目確認画面
データ取得
投入したデータが正しく取得できるか確認してみましょう。特に、GetItem と Query、Scan の違いは SAA の重要論点です。
import boto3
from boto3.dynamodb.conditions import Key
AWS_REGION = 'ap-northeast-1'
DYNAMODB_TABLE_NAME = 'dynamoDB-test'
dynamodb = boto3.resource('dynamodb', region_name=AWS_REGION)
table = dynamodb.Table(DYNAMODB_TABLE_NAME)
user_id = 'user123'
timestamp_prefix = '2025-06-10'
try:
response = table.query(
KeyConditionExpression=Key('user_id').eq(user_id) & Key('timestamp').begins_with(timestamp_prefix)
)
items = response.get('Items')
print('Query succeeded:', items)
print()
# GSIを使ったQuery(Scanとの違いを意識!)
# email-index はGSI作成時に指定したインデックス名に合わせる
response = table.query(
IndexName='email-index',
KeyConditionExpression=Key('email').eq('taro@example.com')
)
items = response.get('Items')
print("Query (GSI) succeeded:", items)
print()
# 注意!Scanは大規模データではパフォーマンス問題に繋がる可能性があるため、
# 基本的には推奨されません。SAAでも「Scanは避けるべき」という選択肢がよく出ます。
# あえて試す場合は、データ量に注意して、そのパフォーマンス特性を実感してみましょう。
response = table.scan()
items = response.get('Items')
print("Scan succeeded:", items)
print()
except Exception as e:
print(f'Error querying items: {e}')
# --- AWS CLI で実行する場合の参考 ---
# テーブル一覧の表示
# aws dynamodb list-tables
# テーブルの詳細情報の確認
# aws dynamodb describe-table --table-name dynamoDB-test
# 項目(データ)の取得(GetItem)
# aws dynamodb get-item \
# --table-name dynamoDB-test \
# --key '{"user_id": {"S": "user123"}, "timestamp": {"S": "2025-06-10T15:00:00Z"}}'
# 項目(データ)のクエリ(プライマリキー)
# aws dynamodb query \
# --table-name dynamoDB-test \
# --key-condition-expression "user_id = :uid and begins_with(timestamp, :ts_prefix)" \
# --expression-attribute-values '{":uid": {"S": "user123"}, ":ts_prefix": {"S": "2025-06-10"}}'
# 項目(データ)のクエリ(GSI)
# GSIを作成済みの場合のみ
# aws dynamodb query \
# --table-name dynamoDB-test \
# --index-name email-index \
# --key-condition-expression "email = :email_val" \
# --expression-attribute-values '{":email_val": {"S": "taro@example.com"}}'
実行結果
murofushi@K205-123 dynamo-db-test % python query_items.py
Query succeeded: [{'user_id': 'user123', 'username': 'taro yamada', 'email': 'taro@example.com', 'status': 'active', 'timestamp': '2025-06-10T10:00:00Z'}, {'user_id': 'user123', 'username': 'taro yamada', 'email': 'taro@example.com', 'status': 'active', 'timestamp': '2025-06-10T15:00:00Z'}]
Query (GSI) succeeded: [{'user_id': 'user123', 'username': 'taro yamada', 'email': 'taro@example.com', 'status': 'active', 'timestamp': '2025-06-10T15:00:00Z'}, {'user_id': 'user123', 'username': 'taro yamada', 'email': 'taro@example.com', 'status': 'active', 'timestamp': '2025-06-10T10:00:00Z'}]
Scan succeeded: [{'user_id': 'user123', 'username': 'taro yamada', 'email': 'taro@example.com', 'status': 'active', 'timestamp': '2025-06-10T10:00:00Z'}, {'user_id': 'user123', 'username': 'taro yamada', 'email': 'taro@example.com', 'status': 'active', 'timestamp': '2025-06-10T15:00:00Z'}, {'user_id': 'user456', 'username': 'hanako sato', 'email': 'hanako@example.com', 'status': 'inactive', 'timestamp': '2025-06-10T11:00:00Z'}]
メリット
- 構築の容易さ: フルマネージドなので、データベースサーバーのプロビジョニングや OS 設定といった複雑な作業が不要。これは SAA 試験における運用負荷軽減の選択肢そのものです。
- スケーラビリティ: オンデマンドモードを選択すれば、急なアクセス増にも自動的に対応可能。Web アプリケーションの設計でパフォーマンス要件を満たす重要な要素です。
- パフォーマンス: プライマリキーや GSI を適切に設計することで、非常に低レイテンシでのデータアクセスが可能。リアルタイム処理が求められるシナリオで DynamoDB が選ばれる理由を体感できました。
- 運用負荷の低減: バックアップ、パッチ適用、高可用性などは AWS が管理してくれるため、運用の手間が大幅に削減される。SA で問われるサービス選択の大きな決め手の一つです。
デメリット
- データモデリングの重要性: リレーショナルデータベースとは異なり、JOIN 操作ができないため、事前にアクセスパターンを徹底的に分析し、それに基づいたテーブル設計(プライマリキー、GSI)が不可欠。ここを怠ると、後で取り返しのつかないパフォーマンス問題やコスト増加に繋がることが分かりました。これは SAA の試験でも特に問われるポイントです。
- 複雑なクエリの制約: SQL のような自由なクエリが難しく、Scan の使用は避けるべき。必要なデータは GSI などを活用して Query で取得するという基本原則を再認識しました。
- 初期学習コスト: NoSQL データベース、特にキーバリュー型のデータモデリングには RDB とは異なる思考が必要で、慣れるまで時間がかかるかもしれません。
まとめ
今回は、Amazon DynamoDB の構築から簡単なデータ操作までをご紹介しました。SAA の試験対策として実際に手を動かしてみることで、座学だけでは得られない多くの気づきがありました。
DynamoDB は、そのスケーラビリティと高速性、そしてフルマネージドという特性から、様々なアプリケーションのバックエンドとして非常に強力な選択肢となります。しかし、その特性を最大限に活かすためには、適切なデータモデル設計が不可欠であると、今回の構築を通じて改めて痛感しました。
この経験が、SAA の試験合格、そしてその先のソリューションアーキテクトとしてのキャリアに繋がることを期待しています。
今後の展望
DynamoDB Streams を使ったデータ連携: Lambda との連携など、SAA で問われるアーキテクチャのパターンを試したいです。
DAX (DynamoDB Accelerator) を使ったパフォーマンス改善: さらに高速化するためのキャッシュレイヤーの理解を深めたいです。
DynamoDB のエラーハンドリングやスロットリングへの対応: 本番環境での信頼性設計を深めたいと考えています。
Discussion