DynamoDB に大量データを Promise.all で書き込み、読込みしてみる

2022.06.02

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

おはようございます、もきゅりんです。

Shall we promise all ?

タイトルのような検証があったのですが、 結果、不要になったためお焚き上げとして ブログにしておきました。

やること

このブログでやることは、以下です。

AWS SDK for JavaScript V2, V3(V2互換API) を使い、単一の既存テーブルに対して、パーティションキー(ハッシュキー)を用いて

  1. 大量データを投入する
  2. 投入した大量データを読み込む

GitHubリポジトリ にサンプルコードをあげていますので、ご自由に検証下さい。

各ディレクトリで npm install の上、ts-node コマンドで実行します。

背景として

DDB への大量データの投入ですが、新規テーブルで対応する場合、 DynamoDBのテーブルにCSVファイルから一括でデータをimportしてみた で対応するも良いでしょうし、新規だろうと既存テーブルだろうと、 Lambda(python3.6)を使って大量のデータをDynamoDBに追加するときはbatch_writerが便利 なら わざわざ Promise all や for…of などを利用することなく比較的スムーズにデータ投入できます。

でも、 今回は Node.js を使って、かつ、既存テーブルを対象としたかった のです。。

そして、 BatchWriteItem では最大16MBデータまたは最大25個のアイテムの書き込みまたは削除操作の制限、 BatchGetItem では最大16MBデータまたは最大100個のアイテムの読み込みが仕様制限になります。

そのため Promise.all を入用とした次第です。

ちなみに余談なのですが、CloudFormation を使った DDB テーブルへ csv を使ったデータ投入において、Excelファイルから csv ファイルにした場合、 BOM (Byte Order Mark) のせいでそのままテンプレートを利用するとコケます。

(このテンプレートの例外処理のエラーメッセージだと何も原因がわからないので、自分はとりあえず基底クラス Exception を指定しました)

Excel ファイルから csvファイルを作成する場合、 Lambda のコード箇所を下記のように修正して利用しましょう。

"   ## for row in csv.DictReader(codecs.getreader('utf-8')(obj)):",
"   for row in csv.DictReader(codecs.getreader('utf-8-sig')(obj)):",
"      if len(batch) >= batch_size:",
"         write_to_dynamo(batch)",
"         batch.clear()",

残りは、いくつか留意点などだけ記載しておきます。

その他

使用される認証情報の優先順位が異なるので、v2, v3 との切り替え時に困惑しました。

そのため、サンプルデータの json データの形式も異なります。

ちなみに、json データは、https://json-generator.com/ でテキトーに生成しています。

  • 書き込み対応のファイルでは、for…of と Promise.all の両方を記載しています。

数百レコード程度ではDDBの負荷も大したことはないので、 Promise.all でも支障ないと思いますが、数千レコードになってくるとスロットリングする可能性もあると 広島 からアドバイスを貰いました。

データ量によっては for…of を選択して実行します。

以上です。

どなたかの参考になれば幸いです。

参考