SardineはGoogle Cloud Datastoreを使って、調査用UIの一部を支えています。Datastoreは、柔軟なインターフェースを備えた、非常にスケーラブルなマネージドNoSQLデータベースです。Datastoreは私たちのインフラにとって非常に重要であるため、常にその最適化を図っています。
スケールするにつれて、Datastoreのコストも大幅に増加していることに気づきました。そこで、Datastoreに関連するコストの種類と、今後のインフラのスケーリングを見据えてこれらのコストをどのように最適化できるかについて、より深く掘り下げることにしました。
Googleには、現在Datastoreの次世代版として位置づけられているFirestoreという製品もあります。私たちが始めた当時、ネイティブのFirestoreはまだGA(一般提供)されていませんでした。現在はDatastore互換モードのFirestoreを使用しています。
Datastoreの料金体系を理解する
この調査における最初のステップは、Datastoreの料金体系を理解することでした。Datastoreは以下に対して課金します。
- 読み取りリクエスト
- 書き込みリクエスト
- 削除リクエスト
- ストレージ
チームの分析の結果、Sardineのコストの大部分は、大量のデータ(とインデックス)を保持していることに起因するデータストレージからのものだと判明しました。
Datastoreのインデックスの仕組みを理解する
ストレージ(とインデックス)が注力すべき領域だったため、datastoreのインデックスシステムを理解したいと考えました。それがdatastoreのコスト最適化に役立つはずだったからです。
組み込みインデックス
Datastoreは(MongoDBに似た)柔軟なドキュメントストアであり、デフォルトではすべてのカラムがインデックス化されます。つまり、注意しないと多くのフィールドがインデックス化されてしまい、コストが跳ね上がることになります。
複合インデックス
複数のフィルターを使ったクエリをサポートするには、複合インデックスを追加する必要があります。Datastoreは並べ替えにもインデックスを必要とするため、次のようなクエリをサポートするには、(customer_id, timestamp)の複合インデックスが必要になります。
インデックスは順序付けされているため、timestamp DESC ソートをサポートするには、別のインデックスが必要になります。
インデックスの使用状況を分析する
Google Cloudは、インデックスの使用状況を把握するためのさまざまなメタデータを提供しています。正確な使用状況データを得るには、組み込みインデックスと複合インデックスの両方の使用状況を確認する必要があります。
組み込みインデックス
組み込みインデックスの使用状況を分析するために、チームは次のクエリを実行しました。
このクエリは、各組み込みインデックスに関する以下のような統計情報を明らかにします。
- インデックスサイズ
- 最終使用日時
- 最終更新日時
セッションごとにリストフィールドを誤ってインデックス化しており、それが多くの容量を消費していたことが分かりました。しかも、それらのインデックスは使われてすらいませんでした。
複合インデックス
複合インデックスを分析するために、次のクエリを実行しました。
このクエリは、各組み込みインデックスに関する以下のような統計情報を明らかにします。
- インデックスサイズ
- 最終使用日時
- 最終更新日時
インデックスを削除する
コストのかかるインデックスを特定できたので、チームはそれらを削除するプロセスを開始できます。複合インデックスについては、terraformで管理しているため簡単に削除できます。組み込みインデックスはオブジェクトごとに存在するため、より複雑です。
dataflowジョブがdatastoreにデータを書き込む際、次のようなコードがあります。
このコードにはインデックスについての記述は一切ありません。しかし、この例ではscoreフィールドはインデックス化されています。デフォルトではすべてのフィールドがインデックス化されるためです。
混乱を避けるため、私たちはbuildIndexedValueとbuildUnindexedValueというラッパー関数を作成し、コードが次のようにより明示的になるようにしました。
さらに、既存の数十億件のレコードからフィールドのインデックスを解除する必要がありました。私たちの知る限り、これを行う簡単な方法はありません。そこで、データを読み込み、更新したexcludeFromIndexフラグを付けて書き戻すpythonスクリプトを作成しました。
まとめ
Datastoreのコストは、不要なインデックスによって気づかないうちに増加していくことがよくあります。以下を実践することで、目に見えるコスト削減が可能です。
- インデックスの統計情報を監査する(
__Stat_Kind_BuiltinIndex__、__Stat_Kind_CompositeIndex__)。 - 使われていないインデックスを削除する。
- クエリで使用しないフィールドを明示的に
excludeFromIndexes=true.
このアプローチについてのご意見をぜひお聞かせください。ご自身のデータストレージソリューションも見直して、コスト削減と最適化の余地がないか確認してみてください!
クラウド利用の最適化にワクワクする方は、ぜひこちらからご応募ください!

