IT・技術研修ならCTC教育サービス

サイト内検索 企業情報 サイトマップ

研修コース検索

コラム

グーグルのクラウドを支えるテクノロジー

CTC 教育サービス

 [IT研修]注目キーワード   Python  UiPath(RPA)  最新技術動向  Microsoft Azure  Docker  Kubernetes 

第155回 サーバーレスNoSQLデータベースサービス「Firestore」(パート3) (中井悦司) 2023年7月

はじめに

 前回に続いて、2023年に公開された論文「Firestore: The NoSQL Serverless Database for the Application Developer」に基づいて、Google Cloudで提供されるNoSQLデータベースサービス「Firestore」のアーキテクチャーを解説していきます。今回は、データの検索・書き込みの詳細を解説します。

検索処理の仕組み

 前回の記事で説明したように、Firestoreの検索処理は、すべてインデックスを用いて行われます。特に、ドキュメントに含まれるキー・バリューペアのそれぞれのキーについて、1次インデックスが自動的に用意されます。この際、特定のキーに対するインデックスには、固有のindex-idが割り当てられて、バリューの値から逆に、その値を持つドキュメントを逆引きする仕組みが用意されます。この部分の仕組みはとてもシンプルで、新たなキー・バリューペアが保存されるごとに、SpannerのIndexEntriesテーブルに、(index-id, value, name) のタプルをキーとするレコードが保存されます。valueとnameは、それぞれバリューとドキュメント名をバイト値にエンコードしたものです。FirestoreのドキュメントとSpannerのIndexEntriesテーブルの対応関係は、図1のようなイメージになります。

fig01

図1 FirestoreのドキュメントとSpannerのIndexEntriesテーブルの関係

 Spannerは、テーブルのキーに対して、値の範囲を指定したレンジスキャンが高速に行えるので、これにより、特定のindex-idに対応するキーについて、指定範囲のバリューを持つドキュメントが容易に特定されます。この例から分かるように、Firestoreの検索処理において、Spanner自身の高度な検索処理(複雑なSQLによるクエリー)が行われるわけでありません。しかしながら、バックエンドのデータストアとしてSpannerを使うことにより、Firestoreの強い整合性を持ったトランザクションをSpannerのトランザクションとして実行する、あるいは、リアルタイムクエリーで使用する特定時刻のスナップショットをSpannerのスナップショット機能で実現するなど、Firestoreの実装をシンプルにできるというメリットがあります。そして何よりも、Firestoreのスケーラビリティと耐障害性は、Spannerのスケーラビリティと耐障害性に支えられることになります。

トランザクションによる書き込み処理の流れ

 Firestoreのトランザクションを伴う書き込み処理について、冒頭の論文では、次のような具体例が紹介されています。ここでは、「レストラン・アプリケーション」の例を用いて、新しいドキュメント「restaurants/one/ratings/2」にキー・バリューペア (rating, 3) を追加すると同時に、既存のドキュメント「restaurant/one」のキー・バリューペア (avgRating, 3.5) を更新します。論文内では、分散トランザクションにまで踏み込んだ詳細な手続きが紹介されていますが、大雑把な流れをまとめると次のようになります。

  1. Spannerのread-writeトランザクションTを開始
  2. Entitiesテーブルからドキュメント「restaurants/one/ratings/2」と「restaurant/one」のレコードをexclusive lockを取得して読み出す(この段階で「restaurants/one/ratings/2」のレコードは存在しないことが分かる)
  3. トランザクションTにおいて、「restaurants/one/ratings/2」のレコードを追加すると共に、「restaurant/one」のレコードを更新する
  4. トランザクションTにおいて、IndexEntriesテーブルに「restaurants/one/ratings/2」と「restaurant/one」の新たなインデックスレコードを追加すると共に、「restaurant/one」の古いインデックスレコードを削除する
  5. トランザクションTをコミットする

 先に触れたように、Firestoreのトランザクション処理がSpannerのトランザクションによって支えらていることがよく分かります。

リアルタイムクエリーの仕組み

 リアルタイムクエリーに関連するコンポーネントは、図2のようになります。

fig02

図2 リアルタイムクエリーに関連するコンポーネント(論文より抜粋)

 クライアントがリアルタイムクエリーを発行すると、それを受け取ったフロントエンドは、初回の検索結果をバックエンドから取得して、クライアントに返却すると同時に、Query Matcherに対して、クエリーに含まれるドキュメントの更新情報の取得をサブスクライブします。複数あるQuery Matcherは、それぞれに担当するドキュメント名のレンジが決まっています。クライアントとフロントエンドは、その後もコネクションを確立した状態を保ち、ドキュメントの更新に応じて、新しいタイムスタンプの情報がクライアントに送られます。
 バックエンドによるドキュメントの更新情報は、メモリー上のChangeLogに記録されていくようになっており、ChangeLogに記録された情報は、該当のドキュメントを担当するQery Matcherに通知が送られた後、さらにサブスクライブしているフロントエンドにその情報が伝達されます。一般にはクエリーには複数のドキュメントが含まれており、フロントエンドは、それぞれのドキュメントの更新情報を取りまとめて、特定の時刻における整合性を持った結果を新たな検索結果としてクライアントに送ります。

次回予告

 2023年に公開された論文「Firestore: The NoSQL Serverless Database for the Application Developer]」に基づいて、Google Cloudで提供されるNoSQLデータベースサービス「Firestore」におけるデータの検索・書き込みの詳細を解説しました。次回は、Firestoreの性能に関するベンチマークデータを紹介します。

Disclaimer:この記事は個人的なものです。ここで述べられていることは私の個人的な意見に基づくものであり、私の雇用者には関係はありません。

 


 

 [IT研修]注目キーワード   Python  UiPath(RPA)  最新技術動向  Microsoft Azure  Docker  Kubernetes