この記事では、人気のあるオープンソースの時系列データベースエンジンの時系列データの保存と計算能力を分析しています。
周 肇峰著
KairosDBInfluxDB
KairosDBはもともとOpenTSDBのバージョン1.xからフォークされたブランチで、OpenTSDBのコードをベースにした二次開発を実装して新しい機能要件を満たすことを目的としていました。その改良点の一つは、プラガブルなストレージエンジンをサポートすることです。例えば、H2のサポートは、OpenTSDBのようにHBaseと強く結合されるのではなく、ローカルでの開発とテストを容易にします。以前のバージョンでは、HBase が主要なストレージエンジンでもありました。しかし、その後のストレージの最適化で、HBaseは徐々にCassandraに取って代わられ、Cassandraをベースに開発された最初の時系列データベースとなりました。最新バージョンでは、Cassandraに固有の属性でありながらHBaseでは利用できない属性がストレージ最適化のために利用されているため、HBaseはサポートされなくなっています。
全体的なアーキテクチャはOpenTSDBと似ており、どちらも成熟したデータベースを最下層のストレージエンジンとして利用しています。メインロジックはストレージエンジン層の上にある薄いロジック層のみです。このロジック層のデプロイメントアーキテクチャは、水平方向に簡単にスケールできるステートレスなコンポーネントです。
機能的な違いとしては、OpenTSDB 1.x上で二次開発を行い、OpenTSDBの機能を最適化したり、OpenTSDBにはない機能を開発したりしています。ここでは、主な機能的な違いについて説明します。
1、プラグイン可能なストレージエンジン:OpenTSDBの初期バージョンはHBaseと強く結合しています。究極のパフォーマンスを追求するために、非同期のHBase Client(現在は独立したオープンソースプロジェクトとして出力されている:AsyncHBase)までもが開発されました。その結果、コード全体が非同期駆動モードで書かれているため、コードの複雑さが増して可読性が低下するだけでなく、複数のストレージエンジンをサポートすることの難しさも増しています。KairosDBでは、ストレージ層のAPIインターフェースを厳密に定義しています。全体的なロジックとストレージ層の結合が少ないため、複数のストレージエンジンのスケーリングが容易になります。最新版のOpenTSDBではCassandraやBigTableにも対応していますが、全体のアーキテクチャとしてはプラガブルなストレージエンジンをサポートするアーキテクチャとは言えません。
2、様々なデータ型の値とカスタム型のサポート: OpenTSDBは数値のみをサポートしていますが、KairosDBは数値型や文字列型、カスタム数値型の値をサポートしています。いくつかのシナリオでは、メトリック値は単純な値ではありません。例えば、この時点でのTopNをカウントしたい場合、対応するメトリック値は文字列値のセットになるかもしれません。スケーラブルな型は、将来的に新しい要件を満たすことを容易にします。1つ目と2つ目の違いは、OpenTSDBをベースにしたKairosDBの最初の大きな改良点は、OpenTSDBの機能モデルとコードアーキテクチャをより柔軟にすることであることを示しています。
3、自動ロールアップのサポート:現在、ほとんどのTSDBは事前集約と自動ロールアップをサポートする方向に進んでいます。OpenTSDBは、この機能をサポートしていない数少ないTSDBの一つです。最新版のOpenTSDBでは、多精度データの格納すらサポートされていない。しかし、KairosDBでサポートされている自動ロールアップ機能の実装方法はまだ比較的原始的なものであり、以下のセクションで詳しく説明します。
4、ストレージのモデルが異なる: TSDBの場合、ストレージは「コアの中のコア」です。OpenTSDBのストレージモデルでは、クエリとストレージを最適化するためにUID圧縮最適化が適用されます。KairosDBの場合は、Cassandraのワイドテーブルを活用した別の考え方が採用されています。これは、HBaseがCassandraに置き換わった最大の理由でもあります。これについては、以下のセクションで詳しく説明します。
ストレージモデル
設計上の主な特徴は、UIDエンコーディングを使用していることです。これによりストレージスペースを大幅に節約することができ、UIDエンコーディングの固定バイト数属性に基づいてHBaseフィルタを使用することで、多くのクエリが最適化されています。しかし、UIDエンコーディングには多くの欠陥もあります。まず、メトリック/タグキー/タグ値とUIDのマッピングテーブルを維持する必要があります。すべてのデータポイントの書き込みと読み出しは、マッピングテーブルを介して変換される必要があります。マッピングテーブルは通常、TSDまたはクライアントにキャッシュされ、追加のメモリ消費を増加させます。第二に、UIDエンコーディングのため、UIDが使用するバイト数に応じてメトリック/タグキー/タグ値の数に上限があり、UIDの割り当てで競合が発生する可能性があり、書き込みに影響を与えます。
本質的に、OpenTSDBのストレージモデルで採用されているUIDエンコーディング最適化は、主に2つの問題を解決します。
1、ストレージスペースを最適化します。UIDエンコーディングは、行キーの繰り返し保存に起因するストレージスペースの冗長化の問題を解決します。
2、クエリの最適化 UIDでエンコードされたタグキーとタグ値の固定バイト長属性に基づいて、HBase FuzzyRowFilterを使用して特定のシナリオでクエリの最適化を行います。
この2つの問題を解決するために、KairosDBではUIDエンコードを必要としない別の方法を採用しており、これらの問題は回避されています。まず、KairosDBのストレージモデルを見てみましょう。主に以下の3つのテーブルで構成されています。
1、DataPoints:すべてのオリジナルのデータポイントを格納します。また、各データポイントは、メトリック、タグ、タイムスタンプ、値で構成されています。このテーブルのデータ行のタイムスパンは3週間です。つまり、3週間以内のすべてのデータポイントが同じ行に格納されるのに対し、OpenTSDB内の行のタイムスパンは1時間しかありません。RowKeyの構成はOpenTSDBと同様です。構造は<metric><timestamp><tagk1><tagv1><tagk2><tagv2>...<tagkn><tagvn>
です。違いは、メトリック、タグキー、タグ値のすべてがUIDの代わりに元の値を格納していることです。
2、RowKeyIndex:このテーブルは、すべてのメトリックに対応する DataPoints テーブル内のすべての行キーのマッピングを格納します。つまり、同じメトリックに書き込まれたすべての行キーが同じ行に格納され、時間順にソートされます。このテーブルは主にクエリに使用されます。タグキーやタグ値でフィルタリングを行う場合は、まずこのテーブルから、クエリ対象期間内の対象となるすべての行キーをフィルタリングしてから、DataPointsテーブル内のデータをクエリします。
3、StringIndex(文字列インデックス):このテーブルは3行のデータを含み、各行にはそれぞれすべてのメトリクス、タグキー、およびタグ値が格納されます。
KairosDBのストレージモデルは、Cassandraのワイドテーブルを活用しています。HBaseの最下層ファイル格納形式では、各列はキー値に対応しており、キーはその行のrowkeyとなります。そのため、HBaseの行の各列には、同じ行キーが繰り返し格納されます。これが、UIDエンコードがストレージ容量を大幅に節約できる主な理由であり、UIDエンコード後のストレージ容量をさらにコンパクトにするために、コンパクションポリシー(行内のすべての列を1つの列にマージする)を採用できる理由でもあります。Cassandraの最下層のファイル格納形式は、HBaseのそれとは異なります。Cassandraの行の各列にはrowkeyが繰り返し格納されないため、UIDエンコードは必要ありません。Cassandraのストレージ容量を減らすための最適化策の1つは、行数を減らすことで、1行あたり1時間分のデータではなく、3週間分のデータを保存することです。この2つのソリューションの理由については、「Hbase File Format」と「Cassandra File Format」を参照してください。
Cassandraのワイドテーブルを使用すると、UIDエンコードを使用しなくても、UIDエンコードを使用したOpenTSDBよりもストレージ容量はそれほど悪くありません。公式には以下のように説明されています。
1つは、文字列にIDを使用しないことです。文字列データ(メトリック名とタグ)は、行キーと適切なインデックスに書き込まれます。Cassandraの行は非常に広いので、データベースに書き込まれるキーの数ははるかに少なくなります。idを使用してもスペースはあまり節約されません。また、idを使用しないことで、クラスタ全体で何らかのロックを使用する必要がなくなります。
前述したように、Cassandraはより広い行を持っています。OpenTSDB HBaseのデフォルトの行サイズは1時間です。Cassandraでは3週間に設定されています。
採用されているクエリの最適化方法もOpenTSDBとは異なります。KairosDB内でのクエリの全体の流れは以下の通りです。
1、クエリ条件に基づいて、すべてのDataPointsテーブルの行キーを検索します。
1、カスタムプラグインがあれば、プラグインからすべての行キーを取得することができます。(プラグインを使用することで、行キーのインデックスを作成するために、外部のインデックス作成システムをスケールして使用することができます。例えば、ElasticSearchを使用するなど)
2、カスタムプラグインがない場合は、RowKeyIndexテーブルのすべての行キーを、メトリックと時間の範囲に基づいて検索することができます。(列名の範囲(metric+startTime, metric+endTime)に基づいてクエリ範囲を絞り込むことができます)
2、行キーに基づいてDataPointsテーブルからすべてのデータを検索します。
データテーブルを直接スキャンして行キーをフィルタリングします。OpenTSDBに比べて、KairosDBはインデックステーブルを利用してスキャンするデータ量を絶対的に減らすことができます。メトリックの下にタグキーとタグ値の組み合わせが限定されている場合には、クエリ効率が大幅に向上します。また、KairosDBはQueryPluginメソッドを提供しており、行キーをインデックスするために外部コンポーネントをスケールして使用することができます。例えば、ElasticSearchや他のインデックスシステムを利用することができますが、これは結局のところ、インデックスを作成することが最良のクエリソリューションであるためです。これがKairosDBに対するHeroicの最大の改善点でもあります。
自動ロールアップ
KairosDBの公式ドキュメントには、自動ロールアップの設定方法についてのセクションがあります。しかし、ディスカッショングループでは、自動ロールアップの記述は以下のようになっています。
まず第一に、Kairosはインジェストではアグリゲーションを行いません。インジェストはパフォーマンスのためにストレージに直接送られます。
Kairosのアグリゲーションは、クエリの実行後に行われます。ロールアップとは、クエリを実行して結果を新しいメトリックとして保存することです。現在、ロールアップはすべてKairosノードごとに設定されています。将来的にはこれを変更する予定です。
現在、Kairosは他のKairosノードと状態を共有していません。ノード上の状態はほとんどありません(ロールアップ以外は)。
一貫性に関しては、どれだけのデータを必要とするか、どれだけ重要なデータを必要とするかはあなた次第です。
まとめると、KairosDBが提供する自動ロールアップソリューションは、まだ比較的簡単に実装できます。これは設定可能なスタンドアロンコンポーネントで、スケジュールされた時間に起動し、書き込まれたデータを読み出し、集計後に再度データを書き込むことができます。確かに非常に原始的で、可用性やパフォーマンスは低いです。
しかし、何もないよりはマシです。自動ロールアップ対応はすべてのTSDBでトレンドとなっており、機能差を拡大してコアコンピテンシーを向上させる重要な機能でもあります。
BlueFlood
前回はCassandra上に構築された最初のTSDBであるKairosDBを中心に分析しましたので、引き続きCassandra上に構築された他のTSDBを分析していきたいと思います。
BlueFloodもCassandra上に構築されたTSDBです。このPPTを見る限りでは、全体のアーキテクチャには主に以下の3つのコアコンポーネントがあることがわかります。
-
インジェストモジュール:データの書き込み処理を行う。
-
ロールアップモジュール:自動事前集計や精度の低下を行う。
-
クエリモジュール:データの問い合わせ処理を行う。
KairosDBと比較すると、そのデータモデルは主に以下の点で他のTSDBとは若干異なります。 -
テナント次元が導入されている:サービス指向のTSDBを構築する場合、テナントディメンションは必須です。
-
タグがサポートされていない:これはかなり意外です。ほとんどのTSDBは基本的にタグをモデルに欠かせないものとして使用していますが、BlueFloodはモデル上でタグをサポートしていません。これは、タグクエリの最適化がどのように決定されていないため、トレードオフになっているのかもしれません。この場合、BlueFloodは単にタグをサポートしていないだけです。いずれにしても、将来的にタグをスケーリングするための完全な互換性があります。BlueFloodは現在、メトリックインデックスを構築するためにElasticSearchを使用しています。将来的にはタグインデックスを構築するソリューションもElasticSearchをベースにすべきだと思います。この計画が完全にサポートされるまでタグは導入されません。
BlueFloodモデルの欠陥のため、タグクエリの最適化を考慮する必要はありません。その代わりに、自動ロールアップなどの他の機能の最適化にすべての努力が費やされています。自動ロールアップのサポートという点では、KairosDBやOpenTSDBよりもはるかに優れています。自動ロールアップ機能は以下の通りです。
- 固定インターバルのみサポート:5分、20分、60分、4時間、1日。
- 分散ロールアップサービス:ロールアップタスクを分散してスケジューリングし、オフラインのバッチスキャンでロールアップデータを取得することができます。
2014年の導入PPTから、今後の計画についていくつかの機能ポイントが見えてきました。
- ElasticSearchのインデクサとディスカバリー:現在はこの機能が実装されていますが、対応しているのはメトリックインデックスのみです。今後タグが導入された後は、タグインデックスにも利用される可能性があります。
- ロールアップのためのクラウドファイルエクスポート:この方法は、オフライン計算のためにより最適化されています。ロールアップから大量の履歴データを読んでも、オンラインサービスには影響しません。
- ロールアップ用の Apache Kafka エクスポート:この方法はオフライン計算よりも高度です。ロールアップはStreamComputeで行うことができ、リアルタイム性が高くなります。
まとめると、タグのサポートを必要とせず、ロールアップの需要が強いのであれば、KairosDBよりもBlueFloodの方が良いでしょう。逆にKairosDBを選ぶべきです。
Heroic
3番目に紹介するCassandraベースのTSDBはHeroicで、DB-Enginesでは19位にランクインしています。BlueFloodやKairosDBには遅れをとっていますが、その設計と実装は最高だと思います。その成り立ちについては、こちらの記事やこちらのPPTで、どちらも貴重な経験と教訓を紹介しています。
SpotifyはHeroicの開発を決める前に、OpenTSDB、InfluxDB、KairosDBなどのTSDBで旧来の監視システムの最下層を置き換えるためにKairosDBを選びました。しかし、KairosDBでのクエリの問題がすぐに明らかになりました。最大の問題は、KairosDBにはメトリクスやタグに関するインデックスがないため、メトリクスやタグの重要度が一定のレベルに達すると、クエリが非常に遅くなってしまうことでした。そこでSpotifyがHeroicを開発する最大の動機は、KairosDBのクエリ問題を解決することでした。クエリエンジンを最適化するためのインデックスとしてElasticSearchを利用するソリューションを採用し、データの書き出しやデータテーブルのソリューションはKairosDBと完全に一致しています。
その特徴を簡単にまとめると以下のようになります。
1、metric2.0の仕様に完全準拠した完全なデータモデル。
2、データ格納モデルはKairosDBと一致しており、クエリエンジンの最適化にはElasticSearchを採用している。(これはKairosDB、OpenTSDB、BlueFloodなど、InfluxDB以外の他のTSDBの最大の既存問題であり、コアコンピタンスの一つである)
3、自動ロールアップ機能に対応していないのが欠点の一つ。
完全なデータモデルをサポートするTSDBが必要で、効率的なインデックスクエリを取得したいのであれば、Heroicがおすすめです。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ