Ubuntu14.04パート2でPrometheusをクエリする方法
Prometheusの共同作成者であるJuliusVolzの記事
序章
Prometheusは、オープンソースの監視システムおよび時系列データベースです。 Ubuntu 14.04 Part 1 でPrometheusをクエリする方法では、合成メトリックをPrometheusサーバーに公開する3つのデモサービスインスタンスを設定しました。 次に、これらのメトリックを使用して、Prometheusクエリ言語を使用して時系列を選択およびフィルタリングする方法、ディメンションを集計する方法、およびレートとデリバティブを計算する方法を学習しました。
このチュートリアルの第2部では、第1部からのセットアップに基づいて構築し、より高度なクエリ手法とパターンを学習します。 このチュートリアルを終えると、値ベースのフィルタリング、セット操作、ヒストグラムなどを適用する方法がわかります。
前提条件
このチュートリアルは、 Ubuntu 14.04 Part1でPrometheusをクエリする方法で概説されているセットアップに基づいています。 少なくとも、そのチュートリアルのステップ1とステップ2に従って、Prometheusサーバーと3つの監視対象デモサービスインスタンスをセットアップする必要があります。 ただし、最初の部分で説明したクエリ言語の手法にも基づいているため、完全に実行することをお勧めします。
ステップ1—値によるフィルタリングとしきい値の使用
このセクションでは、値に基づいて返された時系列をフィルタリングする方法を学習します。
値ベースのフィルタリングの最も一般的な使用法は、単純な数値アラートしきい値です。 たとえば、過去15分間の平均で、500
ステータス要求の合計レートが1秒あたり0.2よりも高いHTTPパスを検索したい場合があります。 これを行うには、すべての500
ステータス要求率を照会し、式の最後に> 0.2
フィルター演算子を追加するだけです。
rate(demo_api_request_duration_seconds_count{status="500",job="demo"}[15m]) > 0.2
Console ビューでは、結果は次のようになります。
ただし、バイナリ演算と同様に、Prometheusは単一のスカラー数によるフィルタリングをサポートするだけではありません。 別の時系列セットに基づいて、ある時系列セットをフィルタリングすることもできます。 この場合も、要素はラベルセットによって照合され、一致する要素間にフィルター演算子が適用されます。 フィルタを通過する右側の要素およびと一致する左側の要素のみが出力の一部になります。 on(<labels>)
、group_left(<labels>)
、group_right(<labels>)
句は、ここでは算術演算子と同じように機能します。
たとえば、500
-ステータスレートは、job
、instance
、method
、およびpath
の任意の組み合わせに対して選択できます。 200
-ステータスレートは500
-ステータスレートの少なくとも50倍ではありません。
rate(demo_api_request_duration_seconds_count{status="500",job="demo"}[5m]) * 50 > on(job, instance, method, path) rate(demo_api_request_duration_seconds_count{status="200",job="demo"}[5m])
これは次のようになります。
Prometheusは、>
の他に、通常の>=
、<=
、<
、!=
、および==
比較演算子もサポートしています。フィルタリングで使用します。
これで、単一の数値に基づいて、またはラベルが一致する別の時系列値のセットに基づいて、時系列のセットをフィルタリングする方法がわかりました。
ステップ2—集合演算子を使用する
このセクションでは、Prometheusのセット演算子を使用して、時系列のセットを相互に関連付ける方法を学習します。
多くの場合、別のセットに基づいて時系列の1つのセットをフィルタリングする必要があります。 このために、Prometheusはand
セット演算子を提供します。 オペレーターの左側にあるすべてのシリーズについて、同じラベルの右側にあるシリーズを見つけようとします。 一致するものが見つかった場合、左側の系列が出力の一部になります。 右側に一致する系列が存在しない場合、その系列は出力から省略されます。
たとえば、90パーセンタイルのレイテンシが50ms(0.05s)を超えるHTTPエンドポイントを選択したい場合がありますが、1秒あたり複数のリクエストを受信するディメンションの組み合わせに対してのみです。 ここでは、パーセンタイルの計算にhistogram_quantile()
関数を使用します。 次のセクションで、この機能が正確に機能することを説明します。 今のところ、重要なのは、各サブディメンションの90パーセンタイルレイテンシを計算することだけです。 結果として生じる不良レイテンシをフィルタリングし、1秒あたり複数のリクエストを受信するレイテンシのみを保持するために、次のクエリを実行できます。
histogram_quantile(0.9, rate(demo_api_request_duration_seconds_bucket{job="demo"}[5m])) > 0.05 and rate(demo_api_request_duration_seconds_count{job="demo"}[5m]) > 1
共通部分を取得する代わりに、2セットの時系列からユニオンを構築したい場合があります。 Prometheusは、このためのor
セット演算子を提供します。 これにより、操作の左側のシリーズと、左側に一致するラベルセットがない右側のシリーズが作成されます。 たとえば、10未満または30を超えるすべてのリクエストレートを一覧表示するには、次のクエリを実行します。
rate(demo_api_request_duration_seconds_count{job="demo"}[5m]) < 10 or rate(demo_api_request_duration_seconds_count{job="demo"}[5m]) > 30
結果はグラフで次のようになります。
ご覧のとおり、グラフで値フィルターとセット操作を使用すると、グラフに沿った任意のタイムステップでフィルターと一致するかどうかに応じて、同じグラフ内で時系列が表示および非表示になる可能性があります。 一般に、この種のフィルターロジックの使用は、アラートルールにのみ推奨されます。
これで、ラベル付けされた時系列から交差点と和集合を構築する方法がわかりました。
ステップ3—ヒストグラムの操作
このセクションでは、ヒストグラムメトリックを解釈する方法と、それらから分位数(パーセンタイルの一般化された形式)を計算する方法を学習します。
Prometheusは、サービスが一連の値の分布を記録できるようにするヒストグラムメトリックをサポートしています。 ヒストグラムは通常、リクエストのレイテンシや応答サイズなどの測定値を追跡しますが、基本的に、何らかの分布に従って大きさが変動する値を追跡できます。 Prometheusは、クライアント側の sample データをヒストグラム化します。つまり、構成可能な数を使用して観測値をカウントします(例: レイテンシー)バケットを作成し、それらのバケットを個別の時系列として公開します。
内部的には、ヒストグラムは時系列のグループとして実装され、それぞれが特定のバケットのカウントを表します(例: 「10ms未満のリクエスト」、「25ms未満のリクエスト」、「50ms未満のリクエスト」など)。 バケットカウンターは累積的です。つまり、値が大きいバケットには、値の小さいすべてのバケットのカウントが含まれます。 ヒストグラムの一部である各時系列で、対応するバケットは特別なle
(以下)ラベルで示されます。 これにより、すでに追跡している既存のディメンションに追加のディメンションが追加されます。
たとえば、デモサービスは、APIリクエスト期間の分布を追跡するヒストグラムdemo_api_request_duration_seconds_bucket
をエクスポートします。 このヒストグラムは、追跡されたサブディメンションごとに26個のバケットをエクスポートするため、このメトリックには多くの時系列があります。 まず、1つのインスタンスから、1つのタイプのリクエストのみの生のヒストグラムを見てみましょう。
demo_api_request_duration_seconds_bucket{instance="localhost:8080",method="POST",path="/api/bar",status="200",job="demo"}
le
ラベルで識別される、それぞれが1つの観測バケットを表す26のシリーズが表示されます。
ヒストグラムは、「リクエストの完了までに100ミリ秒以上かかるものはいくつありますか?」などの質問に答えるのに役立ちます。 (ヒストグラムに100msの境界を持つバケットが構成されている場合)。 一方、「クエリが99 % o f完了するまでのレイテンシはどれくらいですか?」などの関連する質問に答えたいと思うことがよくあります。 ヒストグラムバケットが十分にきめ細かい場合は、histogram_quantile()
関数を使用してこれを計算できます。 この関数は、入力としてヒストグラムメトリック(le
バケットラベルを持つシリーズのグループ)を想定し、対応する分位数を出力します。 0パーセンタイルから100パーセンタイルの範囲のパーセンタイルとは対照的に、histogram_quantile()
関数が入力として期待するターゲット分位数の仕様は0
から1
の範囲です(したがって、 90パーセンタイルは、0.9
の分位数に対応します。
たとえば、次のように、すべてのディメンションについて、すべての時間で90パーセンタイルのAPIレイテンシを計算することができます。
# BAD! histogram_quantile(0.9, demo_api_request_duration_seconds_bucket{job="demo"})
これはあまり有用でも信頼性もありません。 バケットカウンターは、個々のサービスインスタンスが再起動されるとリセットされます。通常、メトリックの全時間ではなく、レイテンシが「現在」(たとえば、過去5分間で測定)を確認する必要があります。 これを実現するには、基になるヒストグラムバケットカウンターにrate()
関数を適用します。この関数は、カウンターリセットを処理し、指定された時間枠での各バケットの増加率のみを考慮します。
次のように、過去5分間の90パーセンタイルAPIレイテンシを計算します。
# GOOD! histogram_quantile(0.9, rate(demo_api_request_duration_seconds_bucket{job="demo"}[5m]))
これははるかに優れており、次のようになります。
ただし、これは、すべてのサブディメンション(job
、instance
、path
、method
、および[ X126X] )。 繰り返しになりますが、これらのすべてのディメンションに関心があるわけではなく、それらの一部を集約したい場合があります。 幸い、Prometheusのsum
集計演算子は、histogram_quantile()
関数と組み合わせて構成できるため、クエリ時にディメンションを集計できます。
次のクエリは90パーセンタイルのレイテンシを計算しますが、結果をjob
、instance
、path
のディメンションでのみ分割します。
histogram_quantile( 0.9, sum without(status, method) ( rate(demo_api_request_duration_seconds_bucket{job="demo"}[5m]) ) )
注:histogram_quantile()
機能を適用する前に、すべての集計でle
バケットラベルを常に保持してください。 これにより、バケットのグループを操作し、それらから分位数を計算できるようになります。
グラフは次のようになります。
ヒストグラムから分位数を計算すると、常にある程度の統計誤差が発生します。 このエラーは、バケットサイズ、観測値の分布、および計算するターゲット分位数によって異なります。 これについて詳しくは、Prometheusのドキュメントの分位数推定のエラーをお読みください。
これで、ヒストグラムメトリックを解釈する方法と、さまざまな時間範囲でヒストグラムメトリックから分位数を計算する方法を理解し、その場でいくつかのディメンションを集計することもできます。
ステップ4—タイムスタンプメトリックの操作
このセクションでは、タイムスタンプを含むメトリックを使用する方法を学習します。
Prometheusエコシステムのコンポーネントは、タイムスタンプを頻繁に公開します。 たとえば、これは、バッチジョブが正常に完了した最後の時間、構成ファイルが正常に再ロードされた最後の時間、またはマシンが起動されたときの場合があります。 慣例により、時間は1970年1月1日UTCからの秒単位のUnixタイムスタンプとして表されます。
たとえば、デモサービスは、シミュレートされたバッチジョブが最後に成功した時間を公開します。
demo_batch_last_success_timestamp_seconds{job="demo"}
このバッチジョブは、1分に1回実行されるようにシミュレートされていますが、すべての試行で25% ofで失敗します。 失敗した場合、demo_batch_last_success_timestamp_seconds
メトリックは、別の実行が成功するまで最後の値を保持します。
生のタイムスタンプをグラフ化すると、次のようになります。
ご覧のとおり、通常、生のタイムスタンプ値はそれ自体ではあまり役に立ちません。 代わりに、タイムスタンプ値の古さを知りたいことがよくあります。 一般的なパターンは、time()
関数によって提供されるように、現在の時刻からメトリックのタイムスタンプを減算することです。
time() - demo_batch_last_success_timestamp_seconds{job="demo"}
これにより、最後に成功したバッチジョブの実行からの時間が秒単位で生成されます。
この年齢を秒から時間に変換したい場合は、結果を3600
で割ることができます。
(time() - demo_batch_last_success_timestamp_seconds{job="demo"}) / 3600
このような式は、グラフ化とアラートの両方に役立ちます。 上記のようにタイムスタンプの経過時間を視覚化すると、線が直線的に増加し、バッチジョブが正常に完了すると0
に定期的にリセットされる鋸歯状のグラフが表示されます。 鋸歯状のスパイクが大きくなりすぎる場合、これはバッチジョブが長期間完了していないことを示します。 >
しきい値フィルターを式に追加し、結果の時系列でアラートを出すことによって、これについてアラートを出すこともできます(ただし、このチュートリアルではアラートルールについては説明しません)。
過去1.5分間にバッチジョブが完了しなかったインスタンスを単純に一覧表示するには、次のクエリを実行できます。
time() - demo_batch_last_success_timestamp_seconds{job="demo"} > 1.5 * 60
これで、生のタイムスタンプメトリックを相対的な年齢に変換する方法がわかりました。これは、グラフ化とアラートの両方に役立ちます。
ステップ5— topk/bottomk関数の並べ替えと使用
このステップでは、クエリ出力を並べ替える方法、または一連のシリーズの最大値または最小値のみを選択する方法を学習します。
表形式のConsoleビューでは、出力系列を値で並べ替えると便利なことがよくあります。 これは、sort()
(昇順)およびsort_desc()
(降順)関数を使用して実現できます。 たとえば、パスごとのリクエストレートを値で並べ替えて表示するには、次のクエリを実行できます。
sort_desc(sum by(path) (rate(demo_api_request_duration_seconds_count{job="demo"}[5m])))
ソートされた出力は次のようになります。
または、すべてのシリーズを表示することすら興味がなく、K個の最大または最小のシリーズのみを表示することもできます。 このために、Prometheusはtopk()
およびbottomk()
機能を提供します。 それらはそれぞれ、K値(選択するシリーズの数)と、フィルタリングする必要のある時系列のセットを返す任意の式を取ります。 たとえば、パスとメソッドごとの上位3つのリクエスト率のみを表示するには、次のクエリを実行できます。
topk(3, sum by(path, method) (rate(demo_api_request_duration_seconds_count{job="demo"}[5m])))
並べ替えはコンソールビューではのみが役立ちますが、グラフではtopk()
とbottomk()
も役立つ場合があります。 出力には、グラフの時間範囲全体で平均された上位または下位のK系列が表示されないことに注意してください。代わりに、出力は、グラフに沿ったすべての解像度ステップについて、上位または下位のK系列を再計算します。 したがって、上部または下部のKシリーズは実際にはグラフの範囲全体で変化する可能性があり、グラフには合計でKシリーズより多くが表示される場合があります。
ここで、K個の最大または最小のシリーズを並べ替える方法または選択する方法を学びました。
ステップ6—スクレイプされたインスタンスの状態を検査する
このステップでは、インスタンスのスクレイプヘルスを経時的に検査する方法を学習します。
このセクションをさらに面白くするために、3つのバックグラウンドデモサービスインスタンスの最初のインスタンス(ポート8080でリッスンしているインスタンス)を終了しましょう。
pkill -f -- -listen-address=:8080
Prometheusはターゲットをスクレイプするたびに、メトリクス名up
と、スクレイプされたインスタンスのjob
およびinstance
ラベルの合成サンプルを保存します。 スクレイプが成功した場合、サンプルの値は1
に設定されます。 スクレイプが失敗した場合は0
に設定されます。 したがって、現在「アップ」または「ダウン」しているインスタンスを簡単に照会できます。
up{job="demo"}
これで、1つのインスタンスがダウンとして表示されます。
のみのダウンインスタンスを表示するには、値0
でフィルタリングできます。
up{job="demo"} == 0
これで、終了したインスタンスのみが表示されます。
または、ダウンインスタンスの総数を取得するには:
count by(job) (up{job="demo"} == 0)
これにより、1
の数が表示されます。
これらの種類のクエリは、基本的なスクレイプヘルスアラートに役立ちます。
注:ダウンインスタンスがない場合、このクエリは、カウントが0
の単一の出力系列ではなく、空の結果を返します。 これは、count()
が、入力として次元時系列のセットを期待し、by
またはwithout
句に従って出力系列をグループ化できる集約演算子であるためです。 すべての出力グループは、既存の入力系列にのみ基づくことができます。入力系列がまったくない場合、出力は生成されません。
これで、インスタンスのヘルス状態を照会する方法がわかりました。
結論
このチュートリアルでは、 Ubuntu 14.04 Part 1 でPrometheusをクエリする方法の進捗状況に基づいて構築し、より高度なクエリ手法とパターンについて説明しました。 値に基づいて系列をフィルタリングする方法、ヒストグラムから分位数を計算する方法、タイムスタンプベースのメトリックを処理する方法などを学びました。
これらのチュートリアルでは、考えられるすべてのクエリのユースケースを網羅することはできませんが、Prometheusを使用して実際のクエリ、ダッシュボード、アラートを作成するときに、クエリの例が役立つことを願っています。 Prometheusのクエリ言語の詳細については、Prometheusクエリ言語のドキュメントを参照してください。