GoogleCloudPlatform
gcp
Firebase
Firestore

Google FireStore を試したけどまだ早かった

More than 1 year has passed since last update.

はじめに

弊社の Game Server Services はゲームサーバのレンタル事業を行っています。
各クラウドプラットフォームのフルマネージドサービスのみを採用し、安定かつスケーラビリティのあるサービスを提供することを目指しています。
GS2 では Cloud DataStore もサービス開発の際に使用しています。
Cloud DataStore の後継サービスとして開発されているといわれている FireStore のβテストが始まったので早速評価を行いました。

所感

Firebase Realtime Database 風のインターフェースを Cloud DataStore の上にのせた。という感じです。
あくまで Firebase Realtime Database 風であり、互換性はありません。そのいくつかはスケーラビリティに問題があった箇所を仕様変更した。といえそうです。

というのも、料金体系が Cloud DataStore と全く同じで、これから解説する仕様から
Firebase Realtime Database のバックエンドは Cloud DataStore と推定できるからです。

Firebase Realtime Database と比較して劣化している点

ノード削除

Realtime Database ではノードを削除する際に中間ノードを削除すると、再帰的に子ノードを削除してくれていました。
しかし、FireStore では子ノードがある状態で中間ノードを削除しようとしてもエラー応答するようになりました。

当然ですが、子ノードが大量にある場合削除にかかる時間は一定ではなく、また料金体系としてこのようなコストのかかる巨大なリクエストに対して、それに見合う料金請求が出来ていなかったのが Firebase Realtime Database でした。
FireStore では、子ノードを1つずつ削除する必要があるため(batchリクエストは出来ます)削除1リクエストごとに課金も出来ますし、処理時間も Realtime Database と比較して予測可能な状態になっています。

しかし、利用者サイドの立場から見れば使いにくくなった点といえそうです。

子ノードの取得

Realtime Database は秒間スループットをどの程度保証するか明示されていませんでした。
実際に、GS2のサービスでの採用を検討しましたが、性能が安定せず、スケーラビリティもあまり良くなかったという経緯があり採用を見送っています。

一方で、 FireStore には保証される秒間スループットが制限という形で公開されました。
書き込みスループットの制限は ドキュメントあたりの書き込みが秒間1回。コレクションへの追記が秒間500回となっています。
書き込みが秒間1回。というのはいかにも Cloud DataStore といった感じです。
コレクションへの追記は秒間500回と多めになっているのは、コレクションは Cloud DataStore におけるエンティティグループに属していない。という状態でしょう。

これを裏付けるように、現在の FireStore は各ノードのもつコレクション(サブコレクション)を取得する手段がありません。

users/1/profile
users/1/image
users/1/items/1
users/1/items/2

このようなリソースがある状態において、

users/1 以下のドキュメント一覧を取得しても profileimage しか取得できません。
items はどうやっても取得できません。
profileimage を削除すると users/1 を削除できるようになりますが items 以下のリソースが残ります。

Cloud DataStore におけるテーブル構成は以下のようなものになっていると推測します。

Indexes

path
Key('Indexes', 'users/1')

Documents

key name age url
Key(Key('Indexes', 'users/1'), 'Documents', 'profile') "taro" 19
Key(Key('Indexes', 'users/1'), 'Documents', 'image') http://example.com/icon.jpeg

users/1/items

key name count
Key('users/1/items', '1') やくそう 5
Key('users/1/items', '2') ひのきのぼう 1

Collection に属するエンティティが単独のテーブルになっているのは、エンティティグループに含めてしまうと Collection への追記も秒間1回に制限されてしまうためです。
その代償として、特定のノードに属するサブコレクションの一覧を取得する手段が無くなっているのだと推測します。

この仕様により、再帰的に全ての子ノードを削除するのが非常に困難です。
コレクションを作成する際には、メタ情報を作成してどんなコレクションが存在するのかを管理するなど、それなりの努力が必要となるでしょう。

Cloud DataStore と比較して劣化している点

安定性

現在はβ期間中だからだと信じたいのですが、現在の FireStore は全然安定していません。

gRPCエラー

API呼び出しが数パーセントの確率で失敗します。
失敗する理由の多くは Internal Error のgRPCエラーであり、詳細は不明です。

一貫性のある読み込み

FireStore は一貫性のある読み込みができません。
DataStore では見たこと無い症状としてはデータを削除後にデータの一覧を取得すると、削除したデータが含まれた結果が一定期間返ってきます。
これがキャッシュなのか、結果整合によるものなのかは定かではありませんが、Cloud DataStore と比較して一貫性のある読み込みが期待できません。

注意するべき点

Cloud DataStore が使用不能になる

FireStore を有効にすると、GCP の Cloud DataStore が利用できなくなります。
FireStore のバックエンドが Cloud DataStore であるということを裏付ける最大の要因はここですが、一度設定してしまうと後戻り出来ませんので、注意する必要があります。

ネームスペースが使用できない

Cloud DataStore にはネームスペースという機能がありましたが、FireStore ではデータベースという名前で同機能が利用できそうなSDKになっています。
しかし、現状の FireStore のマネージメントコンソールにはデータベースを切り替える手段がありません。
また、SDKもデータベースを指定すると様々なAPIでエラーが発生し、実質使用できない状態でした。