BigTable/BigQueryの弱点をカバーする
長所を生かすには、もっともその特徴が活かせる場所に配置することが大事です。それでは短所はどうでしょうか。一つのアプローチとしては、短所をカバーする他のデータベースと組み合わせることです。例えば、BigTableの場合、分散型の列指向データベースになるため、クエリは主にシャードキーに制限されます。そこで、フルサイズのデータはBigTable側に持ちながら、クエリの自由度が高いMongoDBに揮発性のIndexのみを持たせて、取得時には必要な分だけBigTableから取得する方法などが考えられます。
また、BigQueryの場合、スケーラビリティを最大限確保しながらSQLによる比較的複雑なクエリがかけるのは大きな魅力です。反面アプリケーションで直接利用するには、レイテンシが物足りないケースがあります。その場合、Redisなどを利用してバックグラウンドで事前更新するキャッシュ層を用意すると良いでしょう。
KARTEでは実際この2つのテクニックを利用した全体設計を行なっています。それでは解析サービスにおける重要な2つの仕事で説明した2つの仕事に沿ってデータベースの構成について説明します。
Batch AggregationでのDB構成
一つ目の仕事は、生データを保存し、管理画面(またはレポートメールなど)から、Aggregation結果を取得するものです。KARTEではざっくり次のような構成を取っています。
データを収集するプロセス(track)は、負荷コントロールのために一度Cloud Pub/Subに書き込み、後続に渡します。次に書き込みプロセス(writer)がCloud Pub/Subからデータを定期的に取得しBigQueryに書き込みます。この時、BigQueryにはStreaming insertの機能があるので、それを使います。こうすることでニアリアルタイムにクエリをかけることができます。
非構造化データ(JSON)をKarteでは扱うため、Streaming Insertではtext(JSON)に全てのデータを格納します。反面BigQueryはカラムナストレージであり、構造化(カラム切り出し)することで劇的にクエリのパフォーマンスを改善することができます。そのため、バッチで必要なカラムをJSONから切り出してMaterialized Viewを作成すると効果的です。
管理画面プロセス(admin)からは直接BigQueryを利用しますが、間にRedisをキャッシュ層として利用します。(必須ではありませんが)プログラム上は透過的にアクセスできるようにしておき、Cacheプロセスは同じハッシュ(クエリから計算されるもの)を持つ結果が無ければBigQueryに直接クエリを実行します。また定期的(10分ごと/日時など)にバックエンドでBigQueryでクエリを実行し、結果を最新のものとします。
これが可能なのは、バッチでのAggregationの多くがリアルタイム性を要求されないためです。もちろん利用用途によって、またはクエリの多様性によって直接BigQueryを利用するしか方法がないケースはあります。その場合は、クエリの複雑さやデータサイズによりますが、数十秒から数分の待ち時間を吸収できるようなUI設計が必要になってくると考えられます。