17
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ことしもGAOGAOまつりですAdvent Calendar 2021

Day 18

DynamoDBでBatchWriteItemを使用する際の注意点

Posted at

概要

DynamoDBを使用していて複数データを保存、削除する際、BatchWriteItemを使用することになる。
具体的な使用例と注意点をまとめる。

BatchWriteItem

データの保存、削除等をまとめて実行できる。
並列で処理されるため、パフォーマンスは上がる。
※レイテンシは低減されるが、消費キャパシティは変わらないのでコストが下がるわけではない。

基本的なルール

AWSのdocumentにはこのような記載がある。
BatchWriteItem - Amazon DynamoDB

The BatchWriteItem operation puts or deletes multiple items in one or more tables. A single call to BatchWriteItem can write up to 16 MB of data, which can comprise as many as 25 put or delete requests. Individual items to be written can be as large as 400 KB.

ポイントとしては、

  1. 最大25項目までまとめて登録できる
  2. 一度に送信できる最大のデータ量は16MB
  3. 項目一つに対しての最大のデータ量は400KB

Laravelを使用している場合

Laravelを使用するのであれば、GitHub - baopham/laravel-dynamodb: Eloquent syntax for DynamoDBを利用するとEloquentモデルでDynamoDBにアクセスできるようになる。

具体例

Putの例

以下のようにDynamoDb::marshalItem()に挿入したい値を連想配列で渡し、それをsetItemに渡す。
marshalItemとはAWS-SDKのMarshalerクラスに書かれている、DynamoDBのitem形式のフォーマットでJSON形式のテキストとPHPのArray型の変換ができるようになるメソッド)

$query = DynamoDb::table($table)
             ->setItem(DynamoDb::marshalItem($item->toArray()))
             ->prepare()
             ->query;

$putRequests[] = ['putRequest' => $query];

その後、以下のような形でbatchWriteItemを使う。

DynamoDb::newQuery()->setRequestItems([
        $table => $putRequests,
])
    ->prepare()
    ->batchWriteItem();

※この例はPutのケース、作成する項目が25件までなので注意が必要(25件以上の場合、ValidationErrorになる)

chunkする際に気をつける点

また、以下のような方法でchunkをする場合は注意が必要。
100件のUserを保存するケース。

$userPutRequestsChunk = $users->map(function ($user) use ($table) {
                return [
                    'PutRequest' => DynamoDb::table($table)
                        ->setItem(DynamoDb::marshalItem($user->toArray()))
                        ->prepare()
                        ->query
                ];
            })
            ->chunk(25)
            ->all();
  
foreach ($userPutRequestsChunk as $requests) {
    DynamoDb::newQuery()->setRequestItems([
        $table => array_values($requests->all()),
    ])
        ->prepare()
        ->batchWriteItem();
}

foreachの1ループ目は問題無いが、それ以降$requestのkeyが 25, 50, 75から始まるため、SerializationExceptionが返され1ループ目のデータしか保存されない。
そのため、keyが0から始まっていない場合はarray_values()等でkeyを振り直す必要がある。
SerializationExceptionの際は基本的にformatエラーのため、何が入っているか確認が必要。

必ずResponseを確認するべき

batchWriteItem成功時、全Requestが成功したとは限らないのが罠。
もしRequestが失敗した場合、Response内のUnprocessedItemsに失敗したデータが入るので、この中身が空になるまで再度処理をする必要がある。

まとめ

最後のResponseを確認しないといけない箇所は、DynamoDBを使用する上で必ず知っておくべきことだと感じた。

17
1
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
17
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?