- 大江聖太郎
- 約 1,700 文字
- 500 View
はじめに
こんにちは、TIG所属の大江です。
性能テストを実施する際、テスト用の大量データを投入する場合があります。本番相当のデータを入れるために、数千万ないしは数億のデータが必要になる場合もあり、データ生成には一工夫を要です。
本記事では、大量データをDynamoDB/OpenSearch Serviceに投入した際、直面した壁と対応を紹介します。
投入方針
様々な方法を調査した結果、以下の方法で投入するのが、効率が良いという結論に至りました。
これらの方法で投入するには、入力データをJSONファイル形式である必要があります。
また、対象システムでは数種のユニークIDを各項目に割り振る必要がありました。
そこで、Goのtext/templateパッケージを使いることにしました。
以下、生成スクリプトでデータ生成した際に直面した課題と解決策を紹介します。
※実際に使ったコードではOpenSearch用、DynamoDB用のJSONファイルを作成しましたが、記事の簡略化のためにOpenSearch用のもののみ記載いたします。また実際には1億5千万件のデータを生成しましたが、スクリプト実行時の軽量化のために、本記事のコード上では1万件で処理時間の計測をしています。
ダミーデータ生成スクリプト
まず1万件でどの程度の性能になるか計測します。
愚直な実装
ユニークなIDの採番としてrx/xidを用います。テンプレートはシンプルに留めており、おそらく大体の方がこのような実装から始めると思います。
package main |
{ "index": { "_index": "indexname" } } |
{ "index": { "_index": "indexname" } } |
処理時間: 241.1586ms |
こちらの方法だと1万行に0.25秒で処理を終えることができ、1億5千万件のデータ生成を約1時間で終えられます1。
text/template実装
少しトリッキーな実装ですが、text/templateパッケージのrangeを用いて、テンプレート側でループを回した方が高速かも?と疑問に思ったので試してみます。
rangeはテンプレートに配列を渡し、テンプレート側で受け取った配列データを回してテキストを生成するものです。
// ... 中略 ... |
{{range $i, $v := $.ItemIds -}} |
処理時間: 277.9832ms |
実行時間は1つ目の愚直な実装版と大差は無く、text/template版が少し遅いかも?という内容でした。どちらも1億5千万件のデータ生成を約1時間で終えられそうだと分かったため、せっかくですのでtext/templateのrangeを使ったコードを採用します。
想定外の問題
しかしいざ1億5千万件を生成しようとした際、想定外の問題が生じてしまいました…。それはローカルPCの容量不足です🔥。
1万件でも数GBにも上るテキストファイルが生成されます。1億5千万件のデータでは数TBにのぼり、とてもローカルPCで保存できませんでした。
そこで、Lambda関数を非同期で数万件ずつ複数実行し、そこからS3に直接アップロードする方法を取りました。
ローカルの容量不足への対応として、AWS Lambda上で動かす
Lambdaの処理の流れとしては以下です。
1.エフェメラルストレージにファイルを生成する
2.生成されたファイルをs3に上げる
3.エフェメラルストレージからファイルを削除する2
package main |
こちらのLambdaを非同期で実行し、それぞれのLambdaで分割してテストデータファイルを生成することで、無事必要なテストデータを得ることが出来ました。
データ投入
最後に、S3に生成されたデータをOpenSearch、DynamoDBにそれぞれ投入します。
DynamoDBはコンソールよりS3バケットの対象ディレクトリを指定してインポートします。
OpenSearchに対しては以下のようなシェルを回してBulk APIを実行し、データを投入しました。
|
無事1億5千万件のテストデータを投入できました!
まとめ
大量のデータを作る、入れるというのはテストの準備段階ですが、意外と骨の折れることの多い作業です。
そんなときの一助になれれば幸いです。