0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【図解】AWS DynamoDBとは。使い方4手順とRDSとの違いまとめ

0
Posted at

対象読者: AWSをこれから触る人。 AWS勉強シリーズの9本目で、今回はDynamoDBです。全体の地図は索引記事にあります。

前回のRDSに続いてデータベースの2つ目です。DynamoDBを調べると必ず出てくる、こういう疑問に引っかかった人向けに書きます。

  • 「NoSQLって、SQLが無いなら何で探すの?」
  • 「RDSがあるのに、なんでもう1個データベースが要るの?」

どちらも「鍵で一発で取るロッカーか、何でも聞ける図書館か」の違いで答えが出ます。

DynamoDBは巨大なコインロッカー。鍵で一発で取れるが、全部開ける(scan)は遅い。表の結合はできない
DynamoDBをコインロッカーに例えた図(筆者作成)。左が正しい使い方(鍵で一発)、右がやってはいけない使い方(全部開けて探す)です。

DynamoDBとは何か

Amazon DynamoDBは、鍵(キー)を指定して出し入れする方式のデータベースです。NoSQLと呼ばれる型のひとつで、サーバーの用意もOSの管理もありません(Lambdaと同じ「管理レス」型)。テーブルを作るときに決めるのは実質鍵の形だけで、中に入れるデータの列はバラバラでも構いません。

上の図の通り、コインロッカーだと思うのが一番近い。番号札(キー)を持っていれば、何億件入っていても一発で取れる。逆に「番号札を持っていない探し物」は全部の扉を開けて回る(scan)ことになり、遅くて高い。ここがRDS(何でも聞ける図書館)との根本の違いです。

今AWSの地図のどこにいるか

AWS入門の地図。IAM→S3→EC2→VPC→Lambda→RDSまで済み、今ここがDynamoDB。次回はCloudWatch

データベース編の2/2です。前回のRDSと今回のDynamoDBで、AWSの「データを置く場所」の二大選択肢が揃います。

何に使うか

  • 鍵が決まっている出し入れ: ユーザーIDでプロフィールを取る、注文IDで注文を取る。Webサービスの大半のアクセスはこれ
  • 書き込みが大量に来るもの: IoTのセンサーデータ、ゲームのスコア、アクセスログ。テーブルの結合が要らないデータはDynamoDB向き
  • Lambdaと組む: どちらも管理レスなので、「イベント→Lambda→DynamoDBに記録」はサーバー0台で組める定番の形
  • セッション情報: ログイン状態のような「キーで取れて、期限が来たら消えていい」データ(TTLという自動削除の仕組みがある)

今はこれだけ分かればOK

必須の3語 意味
テーブル ロッカーの棚全体。作るときに鍵の形だけ決める
パーティションキー 鍵の前半。「誰の」(user_id など)。必須
ソートキー 鍵の後半。「その中のどれ」(order_id など)。任意だが、付けると「同じ人の分をまとめて取る」ができる

インデックス(GSI/LSI)、キャパシティユニット、DynamoDB Streamsは後回しで大丈夫です。この記事にも出てきません。

仕組みの要点

鍵は「パーティションキー+ソートキー」の2段です。コインロッカーで言うと「taroさんの棚の、注文001の箱」。この2段があるおかげで、取り方が2種類になります。

  • get_item: 2段とも指定して1件を一発で取る
  • query: 前半だけ指定して同じ人の分をまとめて取る

そして大事な制約が1つ。テーブル同士の結合(JOIN)はできません。 RDSのように「注文テーブルとユーザーテーブルを繋いで一覧を出す」はDynamoDBの仕事ではない。結合が要る設計ならRDSを選びます。

このコードを動かす前提

この記事のコードはPython(boto3)です。動かす方法は2通りあります。

A. AWSアカウント無しで試す(おすすめ): motoというAWSのそっくりさんを使うと、課金もサインアップもなしでPCの中だけで動きます。

python3 -m venv venv
./venv/bin/pip install boto3 moto
from moto import mock_aws

@mock_aws            # この中のboto3呼び出しは全部ローカルの偽AWSに行く
def main() -> None:
    ...              # 以下の記事のコードをここに入れる

main()

B. 本物のAWSで動かす: 先にIAMユーザーとアクセスキーの設定が要ります。手順はIAM記事の「最初の1回だけやる手順」にあります。

使い方

やることは4手順です。

DynamoDBの使い方は4手順。①ロッカーを作る(create_table、鍵の形だけ決めればいい) ②入れる(put_item、中身は自由) ③鍵で一発で取る(get_item) ④同じ人の分をまとめて(query)

上の4コマがそのままコードの順番になります。

import boto3
ddb = boto3.client("dynamodb", region_name="ap-northeast-1")

# ① ロッカーを作る。決めるのは鍵の形だけ
ddb.create_table(
    TableName="orders",
    KeySchema=[{"AttributeName": "user_id", "KeyType": "HASH"},      # パーティションキー
               {"AttributeName": "order_id", "KeyType": "RANGE"}],   # ソートキー
    AttributeDefinitions=[{"AttributeName": "user_id", "AttributeType": "S"},
                          {"AttributeName": "order_id", "AttributeType": "S"}],
    BillingMode="PAY_PER_REQUEST")   # 使った分だけ課金するモード

# ② 入れる。中身の列は毎回違っていていい(2件目はprice無しでmemoがある)
ddb.put_item(TableName="orders", Item={"user_id": {"S": "taro"}, "order_id": {"S": "001"},
                                       "item": {"S": "りんご"}, "price": {"N": "150"}})
ddb.put_item(TableName="orders", Item={"user_id": {"S": "taro"}, "order_id": {"S": "002"},
                                       "item": {"S": "みかん"}, "memo": {"S": "急ぎ"}})
ddb.put_item(TableName="orders", Item={"user_id": {"S": "hana"}, "order_id": {"S": "001"},
                                       "item": {"S": "バナナ"}})

# ③ 鍵で一発で取る
got = ddb.get_item(TableName="orders", Key={"user_id": {"S": "taro"}, "order_id": {"S": "001"}})
print(got["Item"]["item"]["S"])   # -> りんご

# ④ 同じ人の分をまとめて取る(前半の鍵だけ指定)
q = ddb.query(TableName="orders",
              KeyConditionExpression="user_id = :u",
              ExpressionAttributeValues={":u": {"S": "taro"}})
print(q["Count"])                                  # -> 2
print([i["order_id"]["S"] for i in q["Items"]])    # -> ['001', '002']

値の書き方が {"S": "taro"} と一段深いのは、DynamoDBが型を明示させる仕様だからです(Sが文字列、Nが数値)。毎回書くのが面倒な場合は boto3.resource("dynamodb") を使うと普通の辞書で書けますが、最初はこの生の形で「型を必ず持っている」ことを見ておくのが後で効きます。

今あなたが作ったもの

  • 容量の宣言なしで、何件でも入るテーブルが1つ(motoでは即ACTIVE。実AWSでも十数秒で、RDSの数分とは桁が違う)
  • 列がバラバラの3件(priceがある注文、memoがある注文、どちらも無い注文)が同居している
  • taroの注文2件が query 一発でまとめて返ってくる

RDSでは「テーブル定義に無い列は入れられない」でしたが、DynamoDBは鍵さえ合っていれば中身は自由。ここが一番の性格の違いです。

実際に叩くと止まるところ

間違えたときに何が返るか、実際に叩きました。

やったこと 返ってきたエラー 意味
鍵の片方(user_idだけ)で get_item ValidationException get_itemは2段とも必須。前半だけで取りたいならquery
鍵以外の列(item)で query ValidationException: Query condition missed key schema element: user_id queryは鍵でしか探せない。コインロッカーは「中身がりんごの箱」では開かない
無いテーブルに put_item ResourceNotFoundException テーブル名のタイプミスか、別リージョンを見ている
同名テーブルを再作成 ResourceInUseException: Table already exists 作り直しは削除してから
無いキーで get_item エラーにならず、Item が無い応答が返る 「無い」は正常応答。if "Item" in got: で確認する癖を付ける

2つ目が一番大事です。「商品名で検索したい」と思った瞬間にDynamoDBの設計は行き詰まります。先に「どの鍵で取るか」を決めてからテーブルを作るのがDynamoDBの作法で、後から検索条件を足せるRDSとは順番が逆です。

似たサービスとの使い分け

迷うところ 答え
RDSかDynamoDBか 結合や集計や複雑な検索が要るならRDS。鍵で取るだけの大量アクセスならDynamoDB
「両方の性質が要る」 実務ではよくある。注文の本体はRDS、セッションやカウンタはDynamoDB、のように併用する
scanで全件取りたくなった 件数が少ない管理画面ならあり。ユーザー向けの機能でscanが要る設計は、鍵の設計かサービス選定を間違えている
S3との違い S3はファイル(写真・動画・大きな塊)、DynamoDBはデータ1件ずつ(400KB上限)。「番号札で取る」発想は同じ

料金の考え方

BillingMode="PAY_PER_REQUEST"(オンデマンド)なら、読み書きの回数だけの課金です。東京リージョンで書き込み100万回 約0.71 USD、読み取り100万回 約0.14 USD(2024年11月の値下げ後の単価。2026年8月に料金表で確認)、保存は1GBあたり月0.285 USD。無料枠として25GBの保存が常設です(読み書きのオンデマンド課金は無料枠が無いので、大量アクセスの負荷試験だけ注意)。

RDSとの一番の違いは、使っていない時間の料金がゼロなこと。RDSは止め忘れると待機料金がかかり続けますが(前回の記事の「止めたのに請求が来る」)、DynamoDBのオンデマンドは触らなければ保存料だけです。学習用に置きっぱなしにできる数少ないサービスです。

よくある注意点

  • scanを日常の道具にしない。 全件を開けて回るので、件数に比例して遅く・高くなる。上の図の右側の人にならない
  • 1件400KBまで。 写真や動画そのものは入らない。S3に置いて、DynamoDBにはS3のキーを入れる
  • 後から鍵は変えられない。 パーティションキーとソートキーはテーブル作成時に固定。変えたくなったら新テーブルに移す。だから「どの鍵で取るか」を最初に考える
  • JOINは無い。 複数テーブルを繋ぐ発想を持ち込まない。繋ぎたくなったらRDSに戻る

まとめ

冒頭の2つの疑問に戻ります。

  • 「SQLが無いなら何で探すの?」→ 鍵で探します。get_item(2段の鍵で1件)とquery(前半の鍵でまとめて)の2つが基本で、鍵以外では探さないのが作法です
  • 「RDSがあるのになんで要るの?」→ 図書館(RDS)は何でも聞けるが司書の席(サーバー)が要る。ロッカー(DynamoDB)は鍵で取るだけだが、席が無いので待機料金ゼロで無限に並べられる。用途が違います

データベース編はこれで2/2です。次はCloudWatch(監視)を予定しています。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?