- 開始・終了日時を保存しておき、指定の日時に対応するデータを検索。
- 上限・下限の金額を保存しておき、指定の金額に対応するデータを検索。
- etc.
2024/08/26
Firestore/Datastoreで複数の範囲フィルタを使ってクエリが可能に
2023/01/13
データストアの選択
世の中には データを保存しておく製品にも、いろいろと選択肢が用意されています。GCPでも目的に応じて特徴の異なる複数のサービスが用意されています。その中でもBigQueryって特徴的で判りやすいと(個人的には)思っていたのですが、最近になってGCPにかかわりながらもBigQueryがどういうものなのかを未だに知らない人に遭遇しました。
ここでGCPのデータの保存目的に使えるサービスを比較しておきたいと思います。
一覧
名称 | 略称 | 概要 | スケーラブル | マネージド |
Firestore | (特になし) | NoSQL、ドキュメント指向データベース。 | 〇 | 〇 |
Cloud SQL | (特になし) | SQLのリレーショナルデータベース。 | △ | 〇 |
Cloud Spanner | Spanner | SQLのリレーショナルデータベース。 | 〇 | 〇 |
Cloud Bigtable | Bigtable | NoSQL・低レイテンシのデータベース。 | 〇 | 〇 |
Memorystore | Memstore | オンメモリで高速動作。 | 〇 | 〇 |
BigQuery | (特になし) | 検索に特化したデータウェアハウス。 | 〇 | 〇 |
Cloud Storage | GCS | 非構造化データ用のストレージ。 | 〇 | 〇 |
各サービスの特徴
Firestore
Cloud SQL
Cloud Spanner
Cloud Bigtable
Memorystore
2021/12/18
Firestoreのトランザクションのリトライがおかしい
公式ドキュメントの説明
「トランザクションとデータ競合」には以下の記載があります。
Firestore では、いずれかのオペレーションを遅延または失敗させることで、データ競合を解決します。データ競合が原因で失敗したトランザクションは、Firestore クライアント ライブラリによって自動的に再試行されます。一定回数の再試行が行われると、トランザクション オペレーションは失敗し、エラー メッセージが返されます。
つまりデータ競合によりトランザクションが失敗するのは、一定回数リトライしても競合を解決できなかった場合ということになります。
実際に起きた例外
ところが Java版のサーバクライアントライブラリを使用したアプリで、割とあっさりとこのエラーが発生しました。以下がその時のログに出ていた例外とそのメッセージ。
java.util.concurrent.ExecutionException: com.google.api.gax.rpc.AbortedException: io.grpc.StatusRuntimeException: ABORTED: Aborted due to cross-transaction contention. This occurs when multiple transactions attempt to access the same data, requiring Firestore to abort at least one in order to enforce serializability.
検証用にアプリを作って故意にデータ競合を起こしてみると、以下の例外が発生しました。別アプリなのでJavaライブラリのバージョンも違っていたかもしれません。
java.util.concurrent.ExecutionException : com.google.cloud.firestore.FirestoreException: Transaction was cancelled because of too many retries.
この例外のgetCause()メソッドで得られたThrowableは、以下。
com.google.cloud.firestore.FirestoreException : Transaction was cancelled because of too many retries.
ネットで検索してみるとStack Overflowにも同様の現象に遭遇した質問「Firestore retry transaction logic」が見つかります。状況は最初の方と同じです。この記事には回答がまったく付いていなくてさみしい限りです。
考察
例外が発生するときと、例外が起きずに正常動作する時とで実行時間にほとんど差がないことから、公式ドキュメントの説明と異なり、実際には以下の実装ではないかと考えられます。
- トランザクションはリトライしていない、あるいは
- リトライはしているがウェイトがないのでデータ競合が解決することなく規定回数を回ってしまう
Javaクライアントライブラリのソースを探して解析すれば何かわかるかもしれませんが、面倒ですしそんな時間もありません。
回避策
ベストな解決策は、Googleさんがこの問題を解決したバージョンのライブラリを公開してくれることです。
しかしそれを待っていられないなら、自分でウェイト付きリトライをトランザクションにかましてみればいいでしょう。私はこの方法で、上記の例外がほぼ発生しなくなっています。
最後に
公式ドキュメントにはリトライはクライアントライブラリが実行しているとの記載があります。今回発見した現象はJavaライブラリによるものですが、他の言語のライブラリは使ったことがないので未確認です。
本日、Javaライブラリをひととおり新しくしてみたら、上記の例外は発生しなくなっていました。どのあたりのバージョンからかは分かりませんが、修正されたようです。
2021/12/08
GCPのデモアプリ : vsReversi
GCPのデモとして、vsReversiを作ってみました。ネット対戦リバーシ(オセロ)です。
- 対戦相手を選択できる。
- 適当にマッチングして対戦もできる。
- 相手がいないときは対コンピュータ戦もできる。
- App Engine : Webサーバ
- Firestore : データベース
- Identity Platform (Firebase Authentication) : ユーザ認証
- Cloud Tasks : 対コンピュータ戦の思考ルーチン