2013年3月25日月曜日

DynamoDB:DynamoDBのプロビジョニングされたスループットを探ってみた

おちラボでは、昨年度からDynamoDBをバックエンドとするDBについて密かに?試作しているんですが、実はDynamoDB のキモとなる
プロビジョニングされたスループット
なるものについては、よくわからずに使っていました(つまり、そんなに本格的に使ってないということなんですけどね ^^; )。

で、最近、ネット界隈で、
DynamoDBにおけるスループット超過対策 〜 Fallback-Queueingパターン
なる記事が話題になっているようで、 DynamoDBの正体とその解決策に、なるほどーっと感心していたわけですが、、、

DynamoDBってそんなめんどくさいサービスなのか???
記事を読んでみて素朴な疑問が出てきたわけです。というか、1年間ちょこっと触ってみて個人的に感じたDynamoDBの欠点は、
  • テーブル毎に課金されるということはテーブルいっぱい作れない!!
ってことがまず1点。課金をケチろうと思ったら従来のRDBみたいな考え方ではアカンのですよね。で、今回の話題で発覚したのが、
  • リクエストスループットは、プロビジョニングされた容量を超えるとリクエストが失敗する
というさらなる欠点が、、、失敗したらどーなるの?データは反映されない?そんなのデータベースって使い物にならんだろう。と思うのは僕だけでしょうか?
で、その解決策として、上記のBLOGの解決策は秀作なんですが、これって元々のDynamoDBが奨励している使い方ではないですよね。いわゆる高等テクニックなわけで、ちょこっとプロトタイプ作ってみましたーみたいなレベルの我がラボのようなところではちょっと敷居が高すぎます。

例外処理で条件ワケするってのはどーも気持ち悪い
上記、BLOGを見ると「ProvisionedThroughputExceededException」というのが、プロビジョニングされた容量を超えた場合に発生するということがわかりました。(へぇ!へぇ!へぇ!へぇ!)
しかし、例外処理を条件分岐のように使うってのは、オブジェクト指向的に美しくないって習いませんでしたか?いや私も習ってませんが、どこかの本にそんなこと書いていた気がします。もっと、スマートなやり方ってないのかな?

getUnprocessedItemsメソッドというのがあるらしい!
ちょっといろいろぐぐってみると、getUnprocessedItemsというメソッドがあり、簡単にいうとBatchWriteItemのような処理で書き込みできなかったアイテムのリストを取り出すことができるということ。これを使えば、書き込みの再試行ができるというわけです!サンプルプログラムは下記のようになります。
do {
 batchWriteItemRequest.withRequestItems(requestItems);
 result = client.batchWriteItem(batchWriteItemRequest);
 requestItems = result.getUnprocessedItems();
} while (result.getUnprocessedItems().size() > 0);
ごらんのように、最初にrequestItemsを渡してバッチ実行したあと、getUnprocessedItemsメソッドでrequestItemsで取り残されたアイテムに更新し、もし取り残しがあれば再度バッチ実行するということです。この方法により、ループが回り続ける限り、登録は行われることになります。

ちょっと試してみた
getUnprocessedItemsメソッドで出力されるリストの中身を確認すれば、どんな感じに処理が失敗していくのかがわかります。空であれば、一発でバッチ登録は成功、そうでなければ失敗したということになります。条件として、
  • プロビジョニングスループットを1にしたテーブルを用意
  • batchWriteItemメソッドで、リミットの25件分のitemを一括登録する処理を20回繰り返す
というのを試してみました。挙動は予測するのはちょっと難しくて、最初の試行ではスムーズに登録完了しました。が、一度、中身を全て消して再度試行すると、途中のターンからリストに失敗したitemが残るようになりました。これはどういうことかというと、
  • 実際にリクエストしたスループット(Average Consumed Write Capactiy)の計算方法が単位時間によるもの
ということが想像出来ます、つまり単発的にデータを200件ほど追加するだけだと、プロビジョニングスループットを1にしていても問題なし。しかし、追加や削除などを繰り返すと、スループット平均値が上がってしまい、登録が失敗するということです。

上の図は、今回試した時のスループットのログです。赤線はプロビジョニングスループットの1です。青線の最大値は1.5です。
ちなみに、書き込みが失敗している場合、whileループが継続されてbatchwriteが行われるわけですが、ループを回るたびにitemのリストは1つずつ減って行きました。つまり、1item分しか処理されていないわけで、これってつまり、プロビジョニングスループットが1であるということなんですよね。

低レベルAPIでしかできないようだが、実は、、、、
getUnprocessedItemsメソッドを使えば、ループにより再処理ができ、漏れ無くデータを登録できることがわかりました。ただ、これが使えるのは、DynamoDBのSDKの低レベルAPIだけ。おちラボでは、高レベルAPIのmapperを使ってたんですが、これだとgetUnprocessedItemsメソッドが使えない模様です。もしかして、低レベルAPIで作り直し??
ちょっと気になって、高レベルAPIで同様の一括処理を試してみました。すると、データベースの中身を見てみましたが、時間はかかりますけどちゃんと入っているようです。どうやら高レベルAPIでは内部で同様の処理をしている模様(ソースを覗いたらはっきりするんでしょうけど)。つまり、、、再試行してくれててデータはちゃんとはいってるということ??

うーん、結局、気にしなくてもよかったのかなぁ。。。



0 件のコメント:

コメントを投稿