TT Lab
はじめる
学ぶ 学習パス コース

Grafana — ダッシュボードは問いだ

同じ 0.42 が、420ミリ秒にも 0.42ミリ秒にも読まれていた

TT Labで続きを見る

目標

本物のGrafanaにパネルをアップロードして単位の識別子を自分で入れ、クエリが出す値の大きさと単位が合っているかを問い合わせで確認し、軸の範囲とログ軸を手で触ったあと、本番から取り出してきたダッシュボードの単位・軸の欠陥4つを直して提出します。

なぜ重要なのか

ダッシュボードの数字は、クエリが正しくても、画面では間違うことがあります。Grafanaの単位は表示ルールであって変換ルールではないので、秒で出る値にミリ秒の単位を付けると、値はそのままで、名前だけが1,000倍小さくなります。割合も、0..1と0..100は互いに異なる単位であり、バイトも、1024で縮めるものと1000で縮めるものは異なる単位です。画面に表示される名前とJSONに入る識別子が違うことまで知って初めて、この作業をファイルとして残せます。軸はその次の話です。下限を0に固定しないと、2倍にも満たない変動が崖のように見え、天井を設定しておくと、事故がまるごと切れてしまいます。このラボの目的は、単位の名前を覚えることではなく、パネルを1つ見て「この数字は何として読まれるか」を問えるようになることです。

ステップ

  1. lab-start-grafanaでGrafanaを起動し、/root/gfd-units/dash.jsonにuidがgfd-unitsのダッシュボードを作って、Grafanaにアップロードしてください。パネルは1つで、idは1、タイプはtimeseries、タイトルはp99 응답 시간 (단위 없음 - 비교용)(韓国語のタイトルは「p99応答時間(単位なし、比較用)」という意味です)、クエリはhistogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{job="shop-api"}[6h])))です。このパネルには単位を書かないでください(あとのステップでもそのままにします。比較用です)。そして/root/gfd-units/01-readings.tsvに、ヘッダー行なしで3行、各行はタブで区切った2列<가정한 단위 식별자> <그 가정대로면 실제로 몇 초인가>を書いてください(プレースホルダーは順に、仮定した単位の識別子と、その仮定どおりなら実際には何秒かです)。仮定する単位は順にs(秒)・ms(ミリ秒)・m(分)で、秒に換算した値は小数第6位まで書きます。
  2. 同じダッシュボードにパネルを3つ追加してください。idが2のパネルは、タイトルがp99 응답 시간(韓国語のタイトルは「p99応答時間」という意味です)、クエリがhistogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{job="shop-api"}[6h])))です。idが3のパネルは、タイトルが5xx 비율(韓国語のタイトルは「5xx割合」という意味です)、クエリがsum(rate(http_requests_total{job="shop-api",status=~"5.."}[1h])) / sum(rate(http_requests_total{job="shop-api"}[1h]))です。idが4のパネルは、タイトルが남은 디스크(韓国語のタイトルは「残りのディスク」という意味です)、クエリがnode_filesystem_avail_bytes{job="node",mountpoint="/data"}です。3つともタイプはtimeseriesで、各パネルのfieldConfig.defaults.unitに、その値に合うGrafanaの単位識別子を書きます。レイテンシは秒、割合は0と1のあいだ、ディスクはバイトで出ます。バイトは、1024で縮めるほう(IEC)を使ってください。そして/root/gfd-units/02-units.tsvに、ヘッダー行なしで3行、各行はタブで区切った3列<패널 id> <단위 식별자> <이 단위를 고른 이유 15자 이상>を書いてください(プレースホルダーは順に、パネルのid、単位の識別子、この単位を選んだ理由(15文字以上)です)。
  3. 同じダッシュボードに、idが5のtimeseriesパネルを追加してください。タイトルはp99 응답 시간 (ms)(韓国語のタイトルは「p99応答時間(ms)」という意味です)で、同じp99をミリ秒の数値で出すクエリを使い、単位識別子はミリ秒のほうを使います。そして/root/gfd-units/03-scale.tsvに、ヘッダー行なしで2行、各行はタブで区切った2列<단위 식별자> <그 패널의 쿼리가 실제로 내는 값>を書いてください(プレースホルダーは順に、単位の識別子と、そのパネルのクエリが実際に出す値です)。1行目はステップ2の秒のパネル、2行目は今回のパネルで、値は小数第6位まで書きます。
  4. 同じダッシュボードに、idが6のtimeseriesパネルを追加してください。タイトルは초당 요청 수(韓国語のタイトルは「秒あたりのリクエスト数」という意味です)、クエリはsum(rate(http_requests_total{job="shop-api"}[5m]))、単位識別子はスループットのカテゴリのrequests/sec (rps)で、fieldConfig.defaults.minを0に固定します。逆に、ステップ2で作ったidが2のパネルには、maxを入れないでください(入れていたら削除します)。そして/root/gfd-units/04-axis.tsvに、ヘッダー行なしで3行、各行はタブで区切った2列で、rps_min・rps_max・swing_pctをこの順に書いてください。前の2つは、直近12時間にこのクエリが出した最も小さい値と最も大きい値(小数第3位)、swing_pctは(最大値引く最小値)割る最大値掛ける100です(小数第2位)。
  5. 同じダッシュボードに、idが7のtimeseriesパネルを追加してください。タイトルは지연과 오류 비율(韓国語のタイトルは「レイテンシとエラー率」という意味です)、クエリは2つです。refIdがAのhistogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{job="shop-api"}[6h])))(凡例名はp99)と、refIdがBのsum(rate(http_requests_total{job="shop-api",status=~"5.."}[1h])) / sum(rate(http_requests_total{job="shop-api"}[1h]))(凡例名は5xx)です。パネル全体の単位は秒にしておき、fieldConfig.overridesに、名前が5xxの系列だけを選んで、単位を0..1の割合に、custom.axisPlacementをrightに指定してください。そして/root/gfd-units/05-override.tsvに、ヘッダー行なしで2行、各行はタブで区切った3列<범례 이름> <그 계열에 적용되는 단위 식별자> <축 위치>を書いてください(プレースホルダーは順に、凡例名、その系列に適用される単位識別子、軸の位置です)。軸の位置はleftまたはrightです。
  6. 同じダッシュボードに、idが8のtimeseriesパネルを追加してください。タイトルは핸들러별 초당 요청 수(韓国語のタイトルは「ハンドラー別の秒あたりのリクエスト数」という意味です)、クエリはsum by (handler) (rate(http_requests_total{job="shop-api"}[1h]))、単位はスループットのカテゴリのrequests/sec (rps)で、fieldConfig.defaults.custom.scaleDistributionを{"type": "log", "log": 10}に指定します。このパネルでは、最小値を0に固定しないでください。そして/root/gfd-units/06-log.txtに4行を書いてください。top=<가장 큰 핸들러의 값>、bottom=<가장 작은 핸들러의 값>(どちらも小数第3位)、ratio=<top 나누기 bottom, 소수 두 자리>、loss=<로그 축으로 바꾸면서 잃는 것, 40자 이상>です(プレースホルダーは順に、最も大きいハンドラーの値、最も小さいハンドラーの値、topをbottomで割った値(小数第2位)、ログ軸に変えることで失うもの(40文字以上)です)。
  7. 同じダッシュボードにパネルを2つ追加してください。idが9のパネルは、タイトルが디스크가 줄어드는 속도(韓国語のタイトルは「ディスクが減る速さ」という意味です)、クエリが- deriv(node_filesystem_avail_bytes{job="node",mountpoint="/data"}[1h])、単位は1024で縮めるほうの秒あたりバイトです。idが10のパネルは、タイトルが디스크가 바닥날 때까지(韓国語のタイトルは「ディスクが底をつくまで」という意味です)で、クエリは残りバイトを減る速さで割ったもの、単位は秒です。2つともタイプはtimeseriesです。そして/root/gfd-units/07-derived.tsvに、ヘッダー行なしで3行、各行はタブで区切った2列<단위 식별자> <그 쿼리가 내는 값>を書いてください(プレースホルダーは順に、単位の識別子と、そのクエリが出す値です)。順に、残りバイト、減る速さ、残り時間で、値は小数第3位まで書きます。
  8. /opt/lab/gfd/gfd-units/broken.jsonは、本番から取り出してきたダッシュボードです(uidはgfd-units-fix)。4つのパネルすべてに、単位か軸の欠陥があります。クエリはそのままでも変えてもかまいませんが、画面に出る値と単位が互いに合っている必要があります。直したダッシュボードを、uidgfd-units-fixでGrafanaにアップロードしてください。パネル4(秒あたりのリクエスト数)の軸は、最小値を0に固定し、天井は外します。そして/root/gfd-units/08-report.tsvに、ヘッダー行なしで4行、各行はタブで区切った3列<패널 id> <결함 코드> <무엇이 틀렸었나, 20자 이상이고 숫자를 하나 이상 포함>を書いてください(プレースホルダーは順に、パネルのid、欠陥コード、何が間違っていたか(20文字以上で、数字を1つ以上含める)です)。欠陥コードはscale(値の大きさと単位がずれている)・category(単位のカテゴリが違う)・axis(軸のせいで切れている)の3つのうち1つで、行はパネルidの順です。

参考

単位を書いていないパネルをアップロードし、同じ数字を3通りに読んでみる

lab-start-grafanaでGrafanaを起動し、/root/gfd-units/dash.jsonにuidがgfd-unitsのダッシュボードを作って、Grafanaにアップロードしてください。パネルは1つで、idは1、タイプはtimeseries、タイトルはp99 응답 시간 (단위 없음 - 비교용)(韓国語のタイトルは「p99応答時間(単位なし、比較用)」という意味です)、クエリはhistogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{job="shop-api"}[6h])))です。このパネルには単位を書かないでください(あとのステップでもそのままにします。比較用です)。そして/root/gfd-units/01-readings.tsvに、ヘッダー行なしで3行、各行はタブで区切った2列<가정한 단위 식별자> <그 가정대로면 실제로 몇 초인가>を書いてください(プレースホルダーは順に、仮定した単位の識別子と、その仮定どおりなら実際には何秒かです)。仮定する単位は順にs(秒)・ms(ミリ秒)・m(分)で、秒に換算した値は小数第6位まで書きます。

ダッシュボードは、Webプレビュー(3000番ポート)で作ってもAPIでアップロードしてもかまいません。APIはcurl -s -XPOST -H 'Content-Type: application/json' -d @파일 http://127.0.0.1:3000/api/dashboards/dbで、送る本体は{"dashboard": {...}, "overwrite": true}の形です(プレースホルダーはファイル名です)。パネルのdatasourceを空にしておくと、既定のデータソース(Prometheus)を使います。換算は掛け算1回です。分だと仮定するなら、その数字の分数なので、60を掛けます。

単位識別子を実際に入れる

同じダッシュボードにパネルを3つ追加してください。idが2のパネルは、タイトルがp99 응답 시간(韓国語のタイトルは「p99応答時間」という意味です)、クエリがhistogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{job="shop-api"}[6h])))です。idが3のパネルは、タイトルが5xx 비율(韓国語のタイトルは「5xx割合」という意味です)、クエリがsum(rate(http_requests_total{job="shop-api",status=~"5.."}[1h])) / sum(rate(http_requests_total{job="shop-api"}[1h]))です。idが4のパネルは、タイトルが남은 디스크(韓国語のタイトルは「残りのディスク」という意味です)、クエリがnode_filesystem_avail_bytes{job="node",mountpoint="/data"}です。3つともタイプはtimeseriesで、各パネルのfieldConfig.defaults.unitに、その値に合うGrafanaの単位識別子を書きます。レイテンシは秒、割合は0と1のあいだ、ディスクはバイトで出ます。バイトは、1024で縮めるほう(IEC)を使ってください。そして/root/gfd-units/02-units.tsvに、ヘッダー行なしで3行、各行はタブで区切った3列<패널 id> <단위 식별자> <이 단위를 고른 이유 15자 이상>を書いてください(プレースホルダーは順に、パネルのid、単位の識別子、この単位を選んだ理由(15文字以上)です)。

画面に表示される名前と、JSONに入る識別子は違います。/opt/lab/gfd/gfd-units/unit-picker.mdに、このPodのGrafanaからそのまま取り出した表があります。割合は、0と1のあいだか0と100のあいだかで分かれ、バイトは、1024で縮めるほうと1000で縮めるほうが、互いに異なる識別子です。値の大きさが気になるなら、promq "<쿼리>"でまず投げてみてください(プレースホルダーはクエリです)。

単位は値を変えない: ミリ秒で表示するには何を掛けるか

同じダッシュボードに、idが5のtimeseriesパネルを追加してください。タイトルはp99 응답 시간 (ms)(韓国語のタイトルは「p99応答時間(ms)」という意味です)で、同じp99をミリ秒の数値で出すクエリを使い、単位識別子はミリ秒のほうを使います。そして/root/gfd-units/03-scale.tsvに、ヘッダー行なしで2行、各行はタブで区切った2列<단위 식별자> <그 패널의 쿼리가 실제로 내는 값>を書いてください(プレースホルダーは順に、単位の識別子と、そのパネルのクエリが実際に出す値です)。1行目はステップ2の秒のパネル、2行目は今回のパネルで、値は小数第6位まで書きます。

単位は表示ルールであって、変換ルールではありません。秒で出る値にミリ秒の単位だけを付けると、画面の数字はそのままで、名前だけが変わります。1,000倍小さく読まれるパネルになります。値をミリ秒にするには、クエリで掛ける必要があります。2つの値は、ちょうど1000倍の差になっていなければなりません。

0から始めるべき軸と、天井をかぶせてはいけない軸

同じダッシュボードに、idが6のtimeseriesパネルを追加してください。タイトルは초당 요청 수(韓国語のタイトルは「秒あたりのリクエスト数」という意味です)、クエリはsum(rate(http_requests_total{job="shop-api"}[5m]))、単位識別子はスループットのカテゴリのrequests/sec (rps)で、fieldConfig.defaults.minを0に固定します。逆に、ステップ2で作ったidが2のパネルには、maxを入れないでください(入れていたら削除します)。そして/root/gfd-units/04-axis.tsvに、ヘッダー行なしで3行、各行はタブで区切った2列で、rps_min・rps_max・swing_pctをこの順に書いてください。前の2つは、直近12時間にこのクエリが出した最も小さい値と最も大きい値(小数第3位)、swing_pctは(最大値引く最小値)割る最大値掛ける100です(小数第2位)。

12時間の最小値・最大値は、サブクエリで求めます。min_over_time((<쿼리>)[12h:5m])のように書きます(プレースホルダーはクエリです)。軸を自動のままにすると、y軸が最小値から始まり、2倍にも満たない変動が画面の高さいっぱいに広がります。逆に最大値を固定すると、その上で起きた事故がまるごと切れてしまいます。線の揺れを抑えたいなら、ハードな最大値の代わりにSoft maxを使います。

1つのパネルに、単位の異なる2つを載せる

同じダッシュボードに、idが7のtimeseriesパネルを追加してください。タイトルは지연과 오류 비율(韓国語のタイトルは「レイテンシとエラー率」という意味です)、クエリは2つです。refIdがAのhistogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{job="shop-api"}[6h])))(凡例名はp99)と、refIdがBのsum(rate(http_requests_total{job="shop-api",status=~"5.."}[1h])) / sum(rate(http_requests_total{job="shop-api"}[1h]))(凡例名は5xx)です。パネル全体の単位は秒にしておき、fieldConfig.overridesに、名前が5xxの系列だけを選んで、単位を0..1の割合に、custom.axisPlacementをrightに指定してください。そして/root/gfd-units/05-override.tsvに、ヘッダー行なしで2行、各行はタブで区切った3列<범례 이름> <그 계열에 적용되는 단위 식별자> <축 위치>を書いてください(プレースホルダーは順に、凡例名、その系列に適用される単位識別子、軸の位置です)。軸の位置はleftまたはrightです。

オーバーライドの1件は、{"matcher": {"id": "byName", "options": "<범례 이름>"}, "properties": [{"id": "unit", "value": "..."}, ...]}の形です(プレースホルダーは凡例名です)。凡例名は、ターゲットのlegendFormatで決めます。オーバーライドなしに重ねると、2つの系列が1つの軸を共有することになり、0.004の割合は、0.3のレイテンシの隣で、底に張り付いた直線になります。

ログ軸を使う場面と、そのとき失うもの

同じダッシュボードに、idが8のtimeseriesパネルを追加してください。タイトルは핸들러별 초당 요청 수(韓国語のタイトルは「ハンドラー別の秒あたりのリクエスト数」という意味です)、クエリはsum by (handler) (rate(http_requests_total{job="shop-api"}[1h]))、単位はスループットのカテゴリのrequests/sec (rps)で、fieldConfig.defaults.custom.scaleDistributionを{"type": "log", "log": 10}に指定します。このパネルでは、最小値を0に固定しないでください。そして/root/gfd-units/06-log.txtに4行を書いてください。top=<가장 큰 핸들러의 값>、bottom=<가장 작은 핸들러의 값>(どちらも小数第3位)、ratio=<top 나누기 bottom, 소수 두 자리>、loss=<로그 축으로 바꾸면서 잃는 것, 40자 이상>です(プレースホルダーは順に、最も大きいハンドラーの値、最も小さいハンドラーの値、topをbottomで割った値(小数第2位)、ログ軸に変えることで失うもの(40文字以上)です)。

4つのハンドラーの値は、promq "sum by (handler) (rate(http_requests_total{job="shop-api"}[1h]))"で一度に見られ、最も大きい値と最も小さい値は、max(...)・min(...)で包めばすぐに出ます。ログ軸では0を描けません。そのため、最小値0の固定とログ軸は、一緒には使えません。失うものを書くときは、「同じ縦の距離が何を意味するようになるのか」を考えてみてください。

応用①: 割り算の結果にはどんな単位が付くか

同じダッシュボードにパネルを2つ追加してください。idが9のパネルは、タイトルが디스크가 줄어드는 속도(韓国語のタイトルは「ディスクが減る速さ」という意味です)、クエリが- deriv(node_filesystem_avail_bytes{job="node",mountpoint="/data"}[1h])、単位は1024で縮めるほうの秒あたりバイトです。idが10のパネルは、タイトルが디스크가 바닥날 때까지(韓国語のタイトルは「ディスクが底をつくまで」という意味です)で、クエリは残りバイトを減る速さで割ったもの、単位は秒です。2つともタイプはtimeseriesです。そして/root/gfd-units/07-derived.tsvに、ヘッダー行なしで3行、各行はタブで区切った2列<단위 식별자> <그 쿼리가 내는 값>を書いてください(プレースホルダーは順に、単位の識別子と、そのクエリが出す値です)。順に、残りバイト、減る速さ、残り時間で、値は小数第3位まで書きます。

バイトを秒あたりバイトで割ると、秒が残ります。単位は、クエリの算術に従ってついてきます。減る速さはderivで求め、値が負で出るので、前にマイナスを付けて正にします。秒あたりバイトは、バイトとは別のカテゴリの単位です(Dataではなく、Data rateです)。バイトの単位をそのまま付けると、画面は「4 GiB」と言いますが、実際の意味は「毎秒4 GiB」です。

応用②: 本番ダッシュボードの単位・軸の欠陥をすべて直して提出する

/opt/lab/gfd/gfd-units/broken.jsonは、本番から取り出してきたダッシュボードです(uidはgfd-units-fix)。4つのパネルすべてに、単位か軸の欠陥があります。クエリはそのままでも変えてもかまいませんが、画面に出る値と単位が互いに合っている必要があります。直したダッシュボードを、uidgfd-units-fixでGrafanaにアップロードしてください。パネル4(秒あたりのリクエスト数)の軸は、最小値を0に固定し、天井は外します。そして/root/gfd-units/08-report.tsvに、ヘッダー行なしで4行、各行はタブで区切った3列<패널 id> <결함 코드> <무엇이 틀렸었나, 20자 이상이고 숫자를 하나 이상 포함>を書いてください(プレースホルダーは順に、パネルのid、欠陥コード、何が間違っていたか(20文字以上で、数字を1つ以上含める)です)。欠陥コードはscale(値の大きさと単位がずれている)・category(単位のカテゴリが違う)・axis(軸のせいで切れている)の3つのうち1つで、行はパネルidの順です。

パネル1は秒で出る値にミリ秒が付いており、パネル2は0..1の割合に0..100のパーセントが付いています。どちらも直し方が2通りあります。単位を値に合わせるか、値を単位に合うように掛けるかです。どちらでもかまいません。パネル3は秒あたりバイトなのにバイトの単位が付いています(カテゴリが違います)。パネル4は単位は合っているのに、軸に天井がかぶせられていて、実際のトラフィックが切れています。まず12時間の最大値を測ってみてください。cp /opt/lab/gfd/gfd-units/broken.json /root/gfd-units/fixed.jsonでコピーを作り、直してアップロードすればかまいません。