Writing a Time Series Database from Scratch-Part1

0から時系列データベースを書く — Part1

gavin.zhou
Orangesys
9 min readJul 24, 2019

--

TSDB(時系列データベース)についての素晴らしい記事がありましたので、ぜひみなさんにご紹介したいと思います。長い記事ですので6回に分けて掲載していきます。第一回目はPrometheusの現在のアプローチなどについての内容です。

私は監視という業務に携わっています。特にPrometheus、カスタム時系列データベースを含む監視システム、またそれとKubernetesとの統合に関しての仕事をしています。

多くの点においてKubernetesはPrometheusの中に設計されたものを全て含んでいます。Kubernetesのおかげで、継続的なデプロイメント、自動スケーリング、その他の非常にダイナミックな環境の機能へのアクセスが容易になります。他の多くの概念的な決定の中においても、クエリ言語と運用モデルの利用で、Prometheusをそのような環境に特に適したものになります。 それでも、監視対象のワークロードが大幅にダイナミックになった場合、監視システム自体にも新たな負担がかかるようになります。 これを念頭に置いて、 Prometheusが既にうまく解決している問題を増加させるのではなく、特にダイナミックな、または一時的なサービスの環境でそのパフォーマンスを向上させることを目指しています。

Prometheusのストレージレイヤーはものすごく性能が高く、驚くほど少量のディスクの容量しか使わずに、単一のサーバーで毎秒最大100万サンプルを数百万の時系列として取り込むことができます。 現在のストレージはうまく機能していますが、私は、既存のソリューションの欠点を修正し、次の規模のオーダーを処理できるように装備された、新しく設計されたストレージサブシステムを提案します。

Problems, Problems, Problem Space

まず、私たちが達成しようとしていることと、それが引き起こす主な問題の概要を説明します。 それぞれについて、Prometheusの現在のアプローチ、それがうまくいくこと、そして新しい設計のおいて取り組むべき問題について見ていきましょう。

Time series data

データポイントを経時的に収集するシステムが存在します。

identifier -> (t0, v0), (t1, v1), (t2, v2), (t3, v3), ....

各データポイントはタイムスタンプと値のタプルです。 監視の目的のおいては、タイムスタンプは整数で、値は任意の数です。 64bit浮動小数点数は優れたカウンターの表示だけでなく、ゲージの値であることが判明したので、我々はそれで行きます。 厳密に単調増加するタイムスタンプを持つ一連のデータポイントは、識別子によってアドレスされる一連のものです。 私たちの識別子は、ラベルディメンションのディクショナリを含むメトリクス名です。ラベルディメンションは、単一のメトリックの測定空間を分割します。 各メトリック名と特定のラベルセットはそれぞれ独自の時系列のもので、その時系列は関連したバリューストリームを持っています。

これは、メトリックのカウントリクエストの一部である典型的な一連の識別子です。

requests_total{path="/status", method="GET", instance=”10.0.0.1:80”}requests_total{path="/status", method="POST", instance=”10.0.0.3:80”}requests_total{path="/", method="GET", instance=”10.0.0.2:80”}

それでは、この表示を今すぐシンプルにしましょう。メトリック名は別のラベルディメンションとして扱うことができます。私たちの場合には — __name__ となります。 クエリレベルでは、これは 特別に扱われるかもしれませんが、後でお話するように、それが保存する方法に関係することはありません。

{__name__="requests_total", path="/status", method="GET", instance=”10.0.0.1:80”}{__name__="requests_total", path="/status", method="POST", instance=”10.0.0.3:80”}{__name__="requests_total", path="/", method="GET", instance=”10.0.0.2:80”}

時系列データをクエリするときは、ラベルで系列を選択して実行します。 最も単純な場合 、{__name__=”requests_total”} が、requests_total メトリックに属するすべての系列を選択します。 選択したすべての系列について、指定した時間枠内のデータポイントを検索します。

より複雑なクエリでは、一度に一連の複数のラベルのセレクタを選択することを望み、通常のものよりもより複雑な条件を表示します。 例えば、否定(method!=”GET”)や一致する正規表現(method=~”PUT|POST”)などです。

これは主に保存されたデータとそのリコール方法を定義します。

Vertical and Horizontal

簡略図では、すべてのデータポイントを2次元平面上に配置できます。 横軸は時間を表し、縦軸は系列の識別子スペースを表します。

Prometheusは、一連の時系列に対して現在の値を定期的にスクラップすることによってデータポイントを検索します。 このようなバッチを検索する元のエンティティはターゲットと呼ばれています。 それによって、各ターゲットからのサンプルが独立して取り込まれるので、書き込みパターンは完全に垂直で同時実効性が高いのです。

スケールをある程度測定するには:単一のPrometheusインスタンスが数万のターゲットからデータポイントを収集することです。それは、それぞれ数百から数千の異なる時系列をエクスポーズします。

1秒あたり何百万ものデータポイントを収集する規模において、書き込みをバッチ処理することは妥協できないパフォーマンス要件です。 ディスク上に点在する単一のデータポイントを書き込むのは、非常に遅くなります。したがって、我々はもっと大きなデータの塊を順番に書きたいと思っています。

これはディスクを回転させるためには当然のことです。なぜなら彼らの頭は常に物理的に異なるセクションに移動しなければならないからです。 SSDは高速ランダム書き込みで知られています。実際には個々のバイトを変更することはできませんが、4KiBかもしくはそれ以上のページに書き込むことはできます。つまり、16バイトのサンプルを書き込むことは、4KiBのページ全体を書き込むことと同じということです。この動作は、 write amplificationライトアンプリフィケーション:WA)として知られています。これは、あなたのSSDを磨耗させます。つまり、遅くなるだけではなく、文字通り数日から数週間でハードウェアを破壊するのです。

この問題についてより詳しく知りたい方は、 “SSDのためのコーディング” シリーズを御一読されることをおすすめします。

主な問題を考えてみましょう。シーケンシャル書き込みとバッチ書き込みは、ディスクとSSDの両方を回転させるのに理想的な書き込みパターンです。こだわるべき簡単な規則です。

クエリパターンは、パターンの書き込みと絶対的に区別されます。 単一シリーズの単一データポイント、1万シリーズの単一データポイント、単一シリーズの週のデータポイント、1万シリーズの週のデータポイントなどをクエリすることができます。したがって、2次元平面では、クエリは完全に垂直、もしくは水平でもありませんが、2つの長方形の組み合わせになっています。

Recording rules は既知のクエリ問題を軽減することはできますが、ad-hocクエリの一般的な解決策ではありませんし、やはりかなり上手く実行しなければいけないでしょう。

我々はバッチで書きたいということは分かっています。しかし我々が取得する唯一のバッチはシリーズ全体的なデータポイントの垂直のセットです。 ある期間にわたって一連のデータポイントをクエリする場合、個々のポイントがどこにあるのかを特定するのが難しいだけでなく、ディスク上の多数のランダムな場所から読み取る必要があります。 1クエリあたり何百万ものサンプルに触れると、最速のSSDでも遅くなります。 読み取りは要求された6バイトのサンプルよりも多くのデータを私たちのディスクから取得します。 SSDは全ページをロードし、HDDは少なくともセクター全体を読み取ります。 どちらにしても、貴重な読み取りスループットを無駄にしています。

したがって、同じシリーズのサンプルは順番に格納されるのが理想的で、そうすれば、できるだけ少ない読み取りでそれらをスキャンすることができます。さらに、このシーケンスがすべてのデータポイントへのアクセスを開始する場所を知るだけで済みます。

収集されたデータをディスクに書き込むための理想的なパターンと、クエリを処理するために非常に効率的なレイアウトとの間には明らかに圧迫感があります。 それはTSDBが解決しなければならない基本的な問題です。

Orangesys.ioでは、kuberneteの運用、DevOps、監視のお手伝いをさせていただいています。ぜひ私たちにおまかせください。

--

--