Amazon QLDBのアプリケーション開発における注意点
Amazon QLDBを触った際の感想文である
AWSにQLDBというイミュータブルなデータベースがある。
ちょいと触る機会があったのだが、いかんせん事例とかこんな感じで使ったみたいな情報がなく、AWSの公式チュートリアルくらいしか情報がないので、こいつを使う上での注意点をいくつか記載する。
なお、作ったのコマンドライン処理なのでWEB画面からどう呼び出すかとかは知らん。
実際に直面した問題を面白おかしく書くので、信じるか信じないかはあなた次第。
そもそもQLDBって何よ?
ざっくりいうと、QLDBってのはブロックチェーン的でイミュータブルで改変不可能なレジャーだぜ!
真面目に書くと、登録されたデータをハッシュ値で管理して、データの更新とか削除があった場合は、ブロックチェーンと同じようにハッシュ値を使ってハッシュキー繋いでいって、過去データの改変履歴を管理して、改ざんできないしトレースできるようにしてるけど、ブロックチェーンみたいにいろんなところに分散せず、AWSの一か所で集中管理してるデータベース、みたいな感じかな?知らんけど。
まぁ、大事なデータが誰かに弄られてないかチェックできるデータベースや!ってのだけ覚えて帰ってもろたらええですわ。
死亡フラグ満載なQLDBのリミット
まず前提として、QLDBには下記のようなリミットがあり、これをよーく理解しとく必要がある。この内容をちゃんと理解しておかないと、後述のように死亡フラグが立ちまくる。
Quotas and limits in Amazon QLDB - Amazon Quantum Ledger Database (Amazon QLDB)
Resource | Fixed quota |
---|---|
Number of concurrent active sessions | 1500 |
Number of active tables | 20 |
Number of total tables (active and inactive)NoteIn QLDB, dropped tables are considered inactive and count against this total quota. | 40 |
Number of indexes per table | 5 |
Number of documents in a transaction | 40 |
Number of revisions to redact in a transaction | 1 |
Document size (encoded in IonBinary format) | 128 KB |
Statement parameter size (IonBinary format) | 128 KB |
Statement parameter size (IonText format) | 1 MB |
Statement string length | 100,000 characters |
Transaction size | 4 MB |
Transaction timeout | 30 seconds |
Expiration period for completed journal export jobs | 7 days |
Expiration period for terminal journal streams | 7 days |
QLDB?まぁデータベースだから普通に使えんだろ…?(←ほんとにこんなノリでスタートした)くらいな気持ちで触り始めると上記リミットに潜む死亡フラグが容易に立つ。
「AWSのチュートリアルやっとけば大体わかるやろ!」→死亡
QLDBを使った開発をするために、AWS公式のチュートリアルがあるので、これさえやっとけばQLDBは完璧!…なわけがない。
ホントにお試しの要素しか書いてなくて、JavaとかPythonで開発する際の例とかも載ってるんだけど、これらが絶妙にかゆいところに手が届かないレベルのコードなので、実際の処理を書くときにかなり苦労した。
余談だが、PythonドライバーのサンプルだとQLDBのエンドポイント指定する方法がたまたま構文の中にあってなんとなくわかるけど、JAVAドライバーだとどうやって指定するかJavaDocをひたすら漁らないと分からなかった。
多分、Pythonが一番簡単にQLDBの処理が書けるのでは?
詳しいコードの書き方については各自苦しめばいいと思うよ?
次からは実装していく中でリミットに潜んでいた死亡フラグについて紹介していこう。
「トランザクションのタイムアウトが30秒か~、まぁDBにクエリ投げて、DB側でのPartiQLの処理が30秒超えたらタイムアウトするんやろなー」→死亡
リミットの中にTransaction Timeout = 30 secondというのがある。
これ、ホントにトランザクション開始して、結果レコードが最後まで手元に帰ってくるまでのトランザクションが30秒以内である必要がある。
これが割と厳しくて、そこそこ良いネットワークでAWS外のネットワークにあるクライアントから処理実行してたんだけど、1回のクエリで最大5000件~6000件くらいまでじゃないとトランザクションがタイムアウトすることが判明。
しかも、どうやらマネージドサービスであるQLDB側の負荷によって処理速度が違うらしく、同じクエリ実行しても同じ時間で取り出しできるデータ量が違うらしいので、絶対この件数に収まればOKというのが言えないこともテストで判明。
しょうがないのでインデックス対象のカラムのデータに、追加でデータを分散するためのキー(例えばAからZまでに分けるとか)を付与して、SelectするときにA-Zまでをループさせ、1回あたりのトランザクションが5000件をさらに下回る件数に収まるようにして1日分のデータをタイムアウトすることなく取得できるように工夫。
「チュートリアルでJSONみたいなの(ION)を指定してインサートしてるから、全データをION形式にして渡せばええんやろ?→死亡」
チュートリアルに書いてあるインサートのサンプルは以下のようなもの。↓
INSERT INTO Vehicle
<< {
'VIN' : '1N4AL11D75C109151',
'Type' : 'Sedan',
'Year' : 2011,
'Make' : 'Audi',
'Model' : 'A5',
'Color' : 'Silver'
} >>
JSONのスーパーセットらしいION形式のデータを<<と>>で囲んで渡してやれば複数データをINSERTできるというチュートリアルになっている。
これを見て、チュートリアルも全部やって、あーじゃあ全データをJSONみたいなION形式にして、INSERT文の後にくっつけたら容易にデータ突っ込めるんやな!と思うのが死亡フラグ。
「Statement string length=100,000 characters」なんだよ。。。
つまり、命令文が100,000文字超えたらNGで、それはION形式のデータも含まれるので、安易に数万データをION形式でぶち込もうとしたら当然できない。
そして、チュートリアルにはそれ以外のINSERT文に関する詳しい記載はほぼないといっても過言じゃない。
ほんならどうやってINSERTすればええんや!!
ご安心あれ、ION形式でデータを渡さなくても、下記のように配列にデータ入れて、トランザクションの処理を実行したらデータをINSERTできるよ!
// Insert a document
qldbDriver.execute(txn -> {
System.out.println("Inserting a document");
IonStruct person = ionSys.newEmptyStruct();
person.put("firstName").newString("John");
person.put("lastName").newString("Doe");
person.put("age").newInt(32);
txn.execute("INSERT INTO People ?", person);
});
「よし、じゃあ数万件のデータを配列に設定してINSERTしたるわ!」→死亡
調子に乗って数千件とかデータを登録しようとすると引っかかるのがこれ。
「Number of documents in a transaction=40」
1回のトランザクションで変更可能なドキュメントの上限が40。
これ、つまり一回のexecuteの中で40レコードしか処理できず、それを超えたらエラーで落ちるということを意味する。
つまり、1回で処理する配列のサイズは40までってこと。
すなわち、数万件データがある場合は、40レコード毎に分割して、トランザクションをループするしかないってことである。
しかも、qldbDriver.executeを実行する前後でセッションの開始、終了をする必要がある。
雑に書くと、対象レコードが存在する間、下記の処理をひたすら繰り返す必要がある。
--
対象レコードから40件配列に格納
↓
セッション開始処理
↓
execute(40件分)
↓
セッション終了処理
--
また、DELETEとかUPDATEも同様で、普通のDBのSQLでやりがちな、同じ日付のデータを一括で消すとか更新するみたいなSQLは対象が40件以内じゃないとエラーになるので、実質無理ってこと。
DELETEもINSERTと同様に40件ずつ処理を回す必要があるよ!
また、「変更可能なドキュメント数」なので、1トランザクション内で挿入、削除、更新を複数行う場合、すべての処理で合わせて40ドキュメントであることも注意ポイント。
実はAWSコンソールのQLDBエディタからDELETE文実行してもこのリミットに引っかかるのだが、チュートリアルのデータが少ないのでチュートリアルやっただけだと気づかないのが絶妙な罠。
「インデックス張れるな、じゃあ複合キーだ!」→死亡
ハイ残念でしたー、QLDBのインデックスは1インデックスに対して1カラムにしか張れませんー!
複合キー無理ですー!
インデックス張ってない項目をWHERE句に指定したらパフォーマンス全然出ませんー!
しょうがないのでインデックス対象のカラムのデータに、追加でデータを分散するためのキー(例えばAからZまでに分けるとか)を付与したんだよ!(前述)
これ、RDBMSに慣れてる人は地味にはまると思う。
QLDBを使ってみた感想
以上がQLDBを触ってみてハマったことである。
すべての地雷を踏み抜いたものの、なんとか完成させた。
単純にデータをINSERTするだけのプログラムだったんだけど、普通のDBの感覚でいると勝手が違うので注意してほしい。
どれもこれも公式ドキュメントに書いてはいるが、まさかそんな意味だとは思わなかったというポイントに引っかかってしまった。
バッチで大量のデータをQLDBに突っ込む機能、そもそもQLDBの用途に合ってない使い方だったんやろな(笑)というのが正直な感想である。
トランザクションのタイムアウト値とか変更可能なドキュメント数とかから察するに、ヘッダーと明細をもつようなデータ構造で少量のデータをオンライントランザクションで処理するような用途が想定されてんじゃないかなぁという気がしている。
QLDBの売りである改変履歴を取得する機能は一切使ってないけど、トレーサビリティが必要なデータを扱う場合には重要なんじゃないかな?
マネージドサービスで提供されてて改変不可で、料金も総データ量に課金らしいので、用途を間違わなければいいサービスだと思う。
また、上記の内容は一個人が試行錯誤してQLDBに対する処理を作成した結果なので、きっと公式様に確認したらもっとうまいやり方があるんじゃなかろうかと信じたい。
信じたいけど間違ったことはしてないんだろうなぁとも思ってる。\(^o^)/オワタ
↓興味がわいたらAWSの勉強しようぜ!
AWSにVPN接続するならYamahaのルーター!
コメント
コメントを投稿