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?

DynamoDBの機能と設計パターンについてDVA対策としてまとめてみる

0
Posted at

Partition Key

DynamoDBでは、データを識別するためにPrimary Keyを設定します。

最もシンプルなのがPartition Keyだけを使用する構成です。

UserId
────────
user001
user002
user003
Partition Key = UserId

とすると、UserIdによってItemを識別できます。

Partition Key + Sort Key

同じPartition Keyに複数のItemを保存したい場合は、Sort Keyを組み合わせます。

例えば注文履歴の場合、

Partition Key = UserId
Sort Key      = OrderId

とできます。

UserId    OrderId
────────  ────────
user001   order001
user001   order002
user001   order003
user002   order001

この場合、

UserId + OrderId

の組み合わせによってItemを一意に識別します。

同じユーザーの注文をまとめて取得したい場合にも便利です。

Query

特定のPartition Keyに属するデータを取得するときは、Queryを使用します。

UserId = user001

の注文だけ取得したい場合、

DynamoDB
 ↓
Query
 ↓
user001のデータ

とできます。

Sort Keyを使用して、

UserId = user001

かつ

OrderDate >= 2026-01-01

のように範囲を絞ることもできます。

Scan

Scanは、テーブルまたはIndexのデータを広く読み取ります。

DynamoDB Table
 ↓
Scan
 ↓
大量のItemを読み取り

Partition Keyを指定して効率的に検索するQueryと違い、Scanは大量のデータを読み取る可能性があります。

効率的に検索したい
→ Query

テーブル全体を確認したい
→ Scan

FilterExpression

ScanではFilterExpressionを使用して、条件に一致するItemだけを結果として返すこともできます。

ただし、FilterExpressionはデータを読み取った後に適用されます。

DynamoDB
 ↓
Scanで読み取り
 ↓
FilterExpression
 ↓
必要なItemだけ返す

そのため、FilterExpressionで結果を絞っても、Scanによって読み取られたデータに対するCapacity消費を減らすことはできません。

効率的に検索
→ Query / Index

Scan結果だけ絞り込み
→ FilterExpression

Parallel Scan

大容量のテーブルに対してScanを実行すると、読み取りに時間がかかる場合があります。

その場合、Parallel Scanを使用してScanを並列化できます。

DynamoDB Table
      │
      ├─ Segment 0 → Worker A
      ├─ Segment 1 → Worker B
      └─ Segment 2 → Worker C

TotalSegmentsで全体の分割数を指定し、それぞれの処理で異なるSegmentを指定します。

通常のScan
→ 順番にScan

Parallel Scan
→ 複数Segmentを並列にScan

ただし、並列化すると読み取りスループットを大量に消費する可能性があるため注意が必要です。

GSI(Global Secondary Index)

Primary Keyとは別の条件で検索したい場合に利用するのがGSIです。

元のテーブルが、

Partition Key = UserId
Sort Key      = OrderId

だったとします。

Status = SHIPPED

の注文を検索したくなった場合、元のPartition Keyでは効率的に検索できません。

そこで、

GSI

Partition Key = Status
Sort Key      = OrderDate

を作成します。

Original Table
UserId + OrderId

        ↓

GSI
Status + OrderDate

これによって、

SHIPPEDの注文を取得

といった別のアクセスパターンに対応できます。

Provisioned Capacity Modeでは、GSIに独自のRCU / WCUを設定します。

Table
RCU / WCU
   │
   ↓
GSI
独自のRCU / WCU

GSIへの書き込みは元テーブルへの書き込みに伴って発生するため、GSI側の書き込みCapacityが不足すると、元テーブルへの書き込みもThrottlingされる可能性があります。

LSI(Local Secondary Index)

LSIもSecondary Indexですが、GSIとは制約が異なります。

LSIでは、元テーブルと同じPartition Keyを使用し、Sort Keyだけ変更します。

例えば、

Table

Partition Key = UserId
Sort Key      = OrderId

に対して、

LSI

Partition Key = UserId
Sort Key      = OrderDate

のように設定できます。

つまり、

同じPartition Key
別のSort Key
→ LSI

です。

Provisioned Capacity Modeでは、LSIは元テーブルとRCU / WCUを共有します。

Table
 │
 └─ LSI

RCU / WCUを共有

また、LSIを持つテーブルでは、同じPartition Keyに属するItemの集合であるItem Collectionに10GBの制限があります。

同じPartition Key
      ↓
Item Collection
      ↓
最大10GB

GSI / LSIまとめ

項目 GSI LSI
Partition Key 元テーブルと別でもよい 元テーブルと同じ
Sort Key 任意 必須・元テーブルとは別の属性
後から追加 可能 不可
Provisioned Capacity 独自 元テーブルと共有
Eventually Consistent Read 可能 可能
Strongly Consistent Read 不可 選択可能
Item Collection 10GB制限 なし あり

GetItem

Primary Keyが分かっていて、1件のItemを取得したい場合はGetItemを使用します。

Primary Key
 ↓
GetItem
 ↓
1 Item

BatchGetItem

複数のItemをまとめて取得したい場合はBatchGetItemを使用できます。

Key A ─┐
Key B ─┼→ BatchGetItem → DynamoDB
Key C ─┘

1件ずつGetItemを繰り返すのではなく、複数のKeyをまとめてリクエストできます。

1回のBatchGetItemでは、最大100 Item、合計16MBまで取得できます。

ただし、すべてのItemが必ず1回で返ってくるとは限りません。

処理できなかったKeyは、

UnprocessedKeys

として返されます。

BatchGetItem
 ↓
UnprocessedKeys
 ↓
Exponential Backoff
 ↓
Retry

UnprocessedKeysを再試行するときは、Exponential Backoffを利用します。

RetryとExponential Backoff

DynamoDBではスロットリングなどによって、一時的にリクエストを処理できない場合があります。

その場合、すぐに大量のRetryを繰り返すのではなく、Exponential Backoffを利用します。

失敗
 ↓
少し待つ
 ↓
Retry
 ↓
さらに長く待つ
 ↓
Retry

Retry間隔を徐々に長くすることで、サービスへさらに負荷をかけることを防ぎます。

Conditional Write

同じデータを重複して登録したくない場合などは、Conditional Writeを利用できます。

例えば注文IDを初回だけ登録したい場合、

OrderId = order001

に対して、

attribute_not_exists(OrderId)

という条件を設定できます。

OrderIdなし
→ Write成功

OrderIdあり
→ Write失敗

これによって重複登録を防止できます。

Lambdaの冪等性を実装するときにも利用できます。

Lambda
 ↓
Conditional Write
 ↓
DynamoDB

Optimistic Locking

同じItemを複数の処理が更新する場合、更新の競合が発生する可能性があります。

例えば、

Version = 1

のItemを取得したあと、

Versionがまだ1なら更新

という条件を付けます。

実装では、Conditional WriteのConditionExpressionを利用できます。

ConditionExpression
Version = :expected
取得時
Version = 1
 ↓
Versionがまだ1?
 ├─ YES → Update → Version = 2
 └─ NO  → Update失敗

他の処理が先に更新してVersionが2になっていれば、条件に一致しないため更新を失敗させることができます。

これを Optimistic Lockingと呼びます。

DynamoDB TTL

一定期間が経過したItemを自動的に削除したい場合は**TTL(Time To Live)**を利用します。

Session
 ↓
ExpirationTime
 ↓
期限切れ
 ↓
TTLによる削除

ただし、TTLは期限になった瞬間に即座にItemを削除する仕組みではありません。

期限切れのItemはバックグラウンドで削除されるため、期限切れ後もしばらく読み取れる可能性があります。

厳密に有効期限を判定したい
→ Application側でもExpirationTimeを確認

TTLによる削除では、元のリージョンでWrite Capacityを消費しません。

また、TTLによって削除されたItemの削除イベントはDynamoDB Streamsにも記録されます。

TTLによる削除
 ↓
DynamoDB Streams
 ↓
Lambda
 ↓
後続処理

DynamoDB Streams

DynamoDBのデータ変更をイベントとして取得したい場合は、DynamoDB Streamsを利用します。

例えば、

DynamoDB
 ↓
INSERT / MODIFY / REMOVE
 ↓
DynamoDB Streams
 ↓
Event Source Mapping
 ↓
Lambda

という構成にできます。

例えば注文が登録されたら、

注文登録
 ↓
DynamoDB
 ↓
Streams
 ↓
Lambda
 ↓
メール送信

のようなイベント駆動処理を実装できます。

Streamsを有効にしただけではLambdaと自動的に接続されないため、Lambdaとの連携にはEvent Source Mappingを設定します。

DynamoDB StreamsのStream View Type

Streamsへどの情報を記録するか設定できます。

主な種類は以下です。

Stream View Type 内容
KEYS_ONLY Keyのみ
NEW_IMAGE 更新後のItem
OLD_IMAGE 更新前のItem
NEW_AND_OLD_IMAGES 更新前と更新後

DAX

DynamoDBへの読み取りアクセスが非常に多い場合、DynamoDB Accelerator(DAX) を利用できます。

DAXはDynamoDB向けのインメモリキャッシュです。

Application
 ↓
DAX
 ↓
DynamoDB

頻繁に読み取られるデータをDAXから返すことで、低レイテンシでアクセスできます。

DAXのキャッシュは、Eventually Consistent Readを高速化する用途に向いています。

Strongly Consistent Readを要求した場合は、DAXのキャッシュを利用せずDynamoDBから読み取ります。

Eventually Consistent Read
→ DAX Cache

Strongly Consistent Read
→ DynamoDB

DynamoDBの読み取り整合性

Eventually Consistent Read

最新の書き込みがすぐに読み取りへ反映されない可能性があります。

Write
 ↓
少し時間差
 ↓
Read

Strongly Consistent Read

最新の書き込み結果を反映した読み取りを行います。

Write
 ↓
Read
 ↓
最新データ

常にStrongly Consistent Readが必要とは限らないため、アプリケーションの要件に応じて選択します。

GSIではStrongly Consistent Readは利用できず、Eventually Consistent Readのみです。

LSIではEventually Consistent Readに加えて、Strongly Consistent Readも選択できます。

なお、Global Tablesのリージョン間レプリケーションにStrong Consistencyが保証されるという意味ではありません。

RCU / WCU

Provisioned Capacityでは、読み取りと書き込みに使用するキャパシティを設定します。

重要なのは、Itemサイズをそのまま計算するのではなく、

Read
→ 4KB単位で切り上げ

Write
→ 1KB単位で切り上げ

てから計算することです。

RCU

RCU(Read Capacity Unit)は読み取り性能を表します。

4KBまでのItemを1秒間に1回読み取る場合、

Strongly Consistent Read
→ 1 RCU

Eventually Consistent Read
→ 0.5 RCU

Transactional Read
→ 2 RCU

となります。

Strongly Consistent Read

必要RCU
=
4KB単位に切り上げたサイズ
×
1秒あたりの読み取り回数

例えば8KBのItemを毎秒10回読み取る場合、

8KB ÷ 4KB
= 2

2 × 10
= 20 RCU

となります。

Eventually Consistent Read

Eventually Consistent Readでは、Strongly Consistent Readの半分のRCUで読み取れます。

例えば6KBのItemを毎秒10回読み取る場合、

6KB
 ↓
4KB単位で切り上げ
 ↓
8KB相当

8KB ÷ 4KB
= 2

2 × 10 ÷ 2
= 10 RCU

となります。

RCUの切り上げは、1回の読み取りごとに行う点に注意します。

複数のItemサイズを先に合計してから、一度だけ4KB単位へ切り上げるわけではありません。

Transactional Read

Transactional Readでは、通常のStrongly Consistent Readの2倍のRCUを消費します。

4KBまで

Strong Read
→ 1 RCU

Transactional Read
→ 2 RCU

WCU

WCU(Write Capacity Unit)は書き込み性能を表します。

1KBまでのItemを1秒間に1回書き込む場合、

Standard Write
→ 1 WCU

Transactional Write
→ 2 WCU

となります。

Standard Write

必要WCU
=
1KB単位に切り上げたサイズ
×
1秒あたりの書き込み回数

例えば2.5KBのItemを毎秒5回書き込む場合、

2.5KB
 ↓
1KB単位で切り上げ
 ↓
3KB

3 × 5
= 15 WCU

となります。

Transactional Write

Transactional Writeでは、Standard Writeの2倍のWCUを消費します。

1KBまで

Standard Write
→ 1 WCU

Transactional Write
→ 2 WCU

RCU / WCUの覚え方

Read
→ 4KB単位

Write
→ 1KB単位


Strong Read
→ ×1

Eventually Read
→ ×0.5

Transactional Read
→ ×2


Standard Write
→ ×1

Transactional Write
→ ×2

DynamoDBの400KB制限

DynamoDBでは、1つのItemの最大サイズは400KBです。

この400KBにはデータの値だけではなく、属性名などもItemサイズとして含まれます。

そのため、

画像
PDF
動画
巨大なJSON
大容量テキスト

などをDynamoDBへ直接保存する用途には向いていません。

このような場合は、大容量データ本体をAmazon S3へ保存し、DynamoDBにはS3オブジェクトを参照する情報やメタデータを保存します。

        Application
         │       │
         │       │
         ▼       ▼
        S3     DynamoDB
         │       │
   大容量データ   S3 Object Key
                メタデータ

つまり、

大容量データ本体
→ S3

検索・管理に必要な情報
→ DynamoDB

という役割分担にします。

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?