LabHub
学习 学习路径 课程

Grafana — 仪表盘是一个问题

同样的 0.42,有人读成 420 毫秒,有人读成 0.42 毫秒

在 LabHub 中继续学习

한국어 원문으로 표시합니다.

목표

진짜 Grafana 에 패널을 올려 단위 식별자를 직접 넣고, 쿼리가 내는 값의 크기와 단위가 맞는지 질의로 확인하고, 축의 범위와 로그 축을 손으로 만진 뒤, 운영에서 걷어 온 대시보드의 단위·축 결함 넷을 고쳐 제출합니다.

왜 중요한가

대시보드의 숫자는 쿼리가 옳아도 화면에서 틀릴 수 있다. Grafana 의 단위는 표시 규칙이지 변환 규칙이 아니라서, 초로 나오는 값에 밀리초 단위를 붙이면 값은 그대로인 채 이름만 천 배 작아진다. 비율도 0..1 과 0..100 이 서로 다른 단위이고, 바이트도 1024 로 줄이는 쪽과 1000 으로 줄이는 쪽이 다른 단위다. 화면에 보이는 이름과 JSON 에 들어가는 식별자가 다르다는 것까지 알아야 이 일을 파일로 남길 수 있다. 축은 그다음 자리다 - 바닥을 0 으로 고정하지 않으면 두 배도 안 되는 변동이 절벽처럼 보이고, 천장을 박아 두면 사고가 통째로 잘린다. 이 실습의 목적은 단위 이름을 외우는 것이 아니라, 패널 하나를 보고 '이 숫자는 무엇으로 읽히는가' 를 물을 수 있게 되는 것이다.

단계

  1. lab-start-grafana 로 Grafana 를 띄우고, /root/gfd-units/dash.json 에 uid 가 gfd-units 인 대시보드를 만들어 Grafana 에 올리세요. 패널은 하나이고 id1, 타입은 timeseries, 제목은 p99 응답 시간 (단위 없음 - 비교용), 쿼리는 histogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{job="shop-api"}[6h]))) 입니다. 이 패널에는 단위를 적지 마세요(뒤 단계에서도 그대로 둡니다 - 비교용입니다). 그리고 /root/gfd-units/01-readings.tsv 에 머리글 없이 세 줄, 각 줄은 탭으로 나눈 두 칸 <가정한 단위 식별자> <그 가정대로면 실제로 몇 초인가> 를 적으세요. 가정할 단위는 순서대로 s(초)·ms(밀리초)·m(분) 이고, 초로 환산한 값은 소수 여섯 자리까지 적습니다.
  2. 같은 대시보드에 패널 셋을 더하세요. id 2 는 제목 p99 응답 시간, 쿼리 histogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{job="shop-api"}[6h]))), id 3 은 제목 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"} 입니다. 셋 다 타입은 timeseries 이고, 각 패널의 fieldConfig.defaults.unit그 값에 맞는 Grafana 단위 식별자를 적습니다. 지연은 초 단위로, 비율은 0 과 1 사이로, 디스크는 바이트로 나옵니다. 바이트는 1024 로 줄이는 쪽(IEC)을 쓰세요. 그리고 /root/gfd-units/02-units.tsv 에 머리글 없이 세 줄, 각 줄은 탭으로 나눈 세 칸 <패널 id> <단위 식별자> <이 단위를 고른 이유 15자 이상> 을 적으세요.
  3. 같은 대시보드에 id5 인 timeseries 패널을 더하세요. 제목은 p99 응답 시간 (ms) 이고, 같은 p99 를 밀리초 숫자로 내는 쿼리를 쓰고 단위 식별자는 밀리초 쪽을 씁니다. 그리고 /root/gfd-units/03-scale.tsv 에 머리글 없이 두 줄, 각 줄은 탭으로 나눈 두 칸 <단위 식별자> <그 패널의 쿼리가 실제로 내는 값> 을 적으세요. 첫 줄은 2단계의 초 패널, 둘째 줄은 이번 패널이고, 값은 소수 여섯 자리까지 적습니다.
  4. 같은 대시보드에 id6 인 timeseries 패널을 더하세요. 제목은 초당 요청 수, 쿼리는 sum(rate(http_requests_total{job="shop-api"}[5m])), 단위 식별자는 처리량 갈래의 requests/sec (rps) 이고, fieldConfig.defaults.min0 으로 고정합니다. 반대로 2단계에서 만든 id 2 패널에는 max넣지 마세요(넣었다면 지웁니다). 그리고 /root/gfd-units/04-axis.tsv 에 머리글 없이 세 줄, 각 줄은 탭으로 나눈 두 칸으로 rps_min·rps_max·swing_pct 를 차례로 적으세요. 앞의 둘은 최근 12시간 동안 이 쿼리가 낸 가장 작은 값과 가장 큰 값(소수 세 자리), swing_pct 는 (최댓값 빼기 최솟값) 나누기 최댓값 곱하기 100 입니다(소수 두 자리).
  5. 같은 대시보드에 id7 인 timeseries 패널을 더하세요. 제목은 지연과 오류 비율, 쿼리는 둘입니다 - refIdAhistogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{job="shop-api"}[6h]))) (범례 이름 p99)와 refIdBsum(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.axisPlacementright 로 지정하세요. 그리고 /root/gfd-units/05-override.tsv 에 머리글 없이 두 줄, 각 줄은 탭으로 나눈 세 칸 <범례 이름> <그 계열에 적용되는 단위 식별자> <축 위치> 를 적으세요. 축 위치는 left 또는 right 입니다.
  6. 같은 대시보드에 id8 인 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 에 네 줄을 적으세요 - top=<가장 큰 핸들러의 값>, bottom=<가장 작은 핸들러의 값>(둘 다 소수 세 자리), ratio=<top 나누기 bottom, 소수 두 자리>, loss=<로그 축으로 바꾸면서 잃는 것, 40자 이상>.
  7. 같은 대시보드에 패널 둘을 더하세요. id 9 는 제목 디스크가 줄어드는 속도, 쿼리 - deriv(node_filesystem_avail_bytes{job="node",mountpoint="/data"}[1h]), 단위는 1024 로 줄이는 쪽의 초당 바이트입니다. id 10 은 제목 디스크가 바닥날 때까지, 쿼리는 남은 바이트를 줄어드는 속도로 나눈 것이고 단위는 초입니다. 둘 다 타입은 timeseries 입니다. 그리고 /root/gfd-units/07-derived.tsv 에 머리글 없이 세 줄, 각 줄은 탭으로 나눈 두 칸 <단위 식별자> <그 쿼리가 내는 값> 을 적으세요. 차례로 남은 바이트, 줄어드는 속도, 남은 시간이고 값은 소수 세 자리까지 적습니다.
  8. /opt/lab/gfd/gfd-units/broken.json 은 운영에서 걷어 온 대시보드입니다(uid gfd-units-fix). 패널 넷 모두 단위나 축에 결함이 있습니다. 쿼리는 그대로 두어도 되고 바꿔도 되지만, 화면에 나오는 값과 단위가 서로 맞아야 합니다. 고친 대시보드를 uid gfd-units-fix 로 Grafana 에 올리세요. 4번 패널(초당 요청 수)의 축은 최솟값을 0 으로 고정하고 천장은 걷어 냅니다. 그리고 /root/gfd-units/08-report.tsv 에 머리글 없이 네 줄, 각 줄은 탭으로 나눈 세 칸 <패널 id> <결함 코드> <무엇이 틀렸었나, 20자 이상이고 숫자를 하나 이상 포함> 을 적으세요. 결함 코드는 scale(값의 크기와 단위가 어긋남)·category(단위 갈래가 틀림)·axis(축 때문에 잘림) 셋 중 하나이고, 줄은 패널 id 순서입니다.

참고

단위를 적지 않은 패널을 올리고, 같은 숫자를 세 가지로 읽어 본다

lab-start-grafana 로 Grafana 를 띄우고, /root/gfd-units/dash.json 에 uid 가 gfd-units 인 대시보드를 만들어 Grafana 에 올리세요. 패널은 하나이고 id1, 타입은 timeseries, 제목은 p99 응답 시간 (단위 없음 - 비교용), 쿼리는 histogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{job="shop-api"}[6h]))) 입니다. 이 패널에는 단위를 적지 마세요(뒤 단계에서도 그대로 둡니다 - 비교용입니다). 그리고 /root/gfd-units/01-readings.tsv 에 머리글 없이 세 줄, 각 줄은 탭으로 나눈 두 칸 <가정한 단위 식별자> <그 가정대로면 실제로 몇 초인가> 를 적으세요. 가정할 단위는 순서대로 s(초)·ms(밀리초)·m(분) 이고, 초로 환산한 값은 소수 여섯 자리까지 적습니다.

대시보드는 웹 미리보기(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)를 씁니다. 환산은 곱셈 한 번입니다 - 분이라고 가정하면 그 숫자만큼의 분이므로 60을 곱합니다.

단위 식별자를 실제로 넣는다

같은 대시보드에 패널 셋을 더하세요. id 2 는 제목 p99 응답 시간, 쿼리 histogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{job="shop-api"}[6h]))), id 3 은 제목 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"} 입니다. 셋 다 타입은 timeseries 이고, 각 패널의 fieldConfig.defaults.unit그 값에 맞는 Grafana 단위 식별자를 적습니다. 지연은 초 단위로, 비율은 0 과 1 사이로, 디스크는 바이트로 나옵니다. 바이트는 1024 로 줄이는 쪽(IEC)을 쓰세요. 그리고 /root/gfd-units/02-units.tsv 에 머리글 없이 세 줄, 각 줄은 탭으로 나눈 세 칸 <패널 id> <단위 식별자> <이 단위를 고른 이유 15자 이상> 을 적으세요.

화면에 보이는 이름과 JSON 에 들어가는 식별자는 다릅니다. /opt/lab/gfd/gfd-units/unit-picker.md 에 이 파드의 Grafana 에서 그대로 뽑은 표가 있습니다. 비율은 0 과 1 사이인지 0 과 100 사이인지로 갈리고, 바이트는 1024 로 줄이는 쪽과 1000 으로 줄이는 쪽이 서로 다른 식별자입니다. 값의 크기가 궁금하면 promq "<쿼리>" 로 먼저 던져 보세요.

단위는 값을 바꾸지 않는다 - 밀리초로 보이려면 무엇을 곱해야 하나

같은 대시보드에 id5 인 timeseries 패널을 더하세요. 제목은 p99 응답 시간 (ms) 이고, 같은 p99 를 밀리초 숫자로 내는 쿼리를 쓰고 단위 식별자는 밀리초 쪽을 씁니다. 그리고 /root/gfd-units/03-scale.tsv 에 머리글 없이 두 줄, 각 줄은 탭으로 나눈 두 칸 <단위 식별자> <그 패널의 쿼리가 실제로 내는 값> 을 적으세요. 첫 줄은 2단계의 초 패널, 둘째 줄은 이번 패널이고, 값은 소수 여섯 자리까지 적습니다.

단위는 표시 규칙이지 변환 규칙이 아닙니다. 초로 나오는 값에 밀리초 단위만 붙이면 화면의 숫자는 그대로이고 이름만 바뀝니다 - 천 배 작게 읽히는 패널이 됩니다. 값을 밀리초로 만들려면 쿼리에서 곱해야 합니다. 두 값은 정확히 1000배 차이가 나야 합니다.

0 에서 시작해야 하는 축과, 천장을 씌우면 안 되는 축

같은 대시보드에 id6 인 timeseries 패널을 더하세요. 제목은 초당 요청 수, 쿼리는 sum(rate(http_requests_total{job="shop-api"}[5m])), 단위 식별자는 처리량 갈래의 requests/sec (rps) 이고, fieldConfig.defaults.min0 으로 고정합니다. 반대로 2단계에서 만든 id 2 패널에는 max넣지 마세요(넣었다면 지웁니다). 그리고 /root/gfd-units/04-axis.tsv 에 머리글 없이 세 줄, 각 줄은 탭으로 나눈 두 칸으로 rps_min·rps_max·swing_pct 를 차례로 적으세요. 앞의 둘은 최근 12시간 동안 이 쿼리가 낸 가장 작은 값과 가장 큰 값(소수 세 자리), swing_pct 는 (최댓값 빼기 최솟값) 나누기 최댓값 곱하기 100 입니다(소수 두 자리).

12시간 동안의 최솟값·최댓값은 부분 쿼리로 구합니다 - min_over_time((<쿼리>)[12h:5m]) 처럼 씁니다. 축을 자동으로 두면 y축이 최솟값에서 시작해, 두 배도 안 되는 변동이 화면 높이를 가득 채웁니다. 반대로 최댓값을 박아 두면 그 위에서 일어난 사고가 통째로 잘려 나갑니다 - 선을 덜 출렁이게 하고 싶다면 하드 최댓값 대신 Soft max 를 씁니다.

한 패널에 단위가 다른 둘을 올린다

같은 대시보드에 id7 인 timeseries 패널을 더하세요. 제목은 지연과 오류 비율, 쿼리는 둘입니다 - refIdAhistogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{job="shop-api"}[6h]))) (범례 이름 p99)와 refIdBsum(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.axisPlacementright 로 지정하세요. 그리고 /root/gfd-units/05-override.tsv 에 머리글 없이 두 줄, 각 줄은 탭으로 나눈 세 칸 <범례 이름> <그 계열에 적용되는 단위 식별자> <축 위치> 를 적으세요. 축 위치는 left 또는 right 입니다.

오버라이드 한 칸은 {"matcher": {"id": "byName", "options": "<범례 이름>"}, "properties": [{"id": "unit", "value": "..."}, ...]} 모양입니다. 범례 이름은 타깃의 legendFormat 으로 정합니다. 오버라이드 없이 겹치면 두 계열이 한 축을 나눠 쓰게 되고, 0.004 짜리 비율은 0.3 짜리 지연 옆에서 바닥에 붙은 직선이 됩니다.

로그 축을 쓰는 자리와, 그때 잃는 것

같은 대시보드에 id8 인 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 에 네 줄을 적으세요 - top=<가장 큰 핸들러의 값>, bottom=<가장 작은 핸들러의 값>(둘 다 소수 세 자리), ratio=<top 나누기 bottom, 소수 두 자리>, loss=<로그 축으로 바꾸면서 잃는 것, 40자 이상>.

핸들러 넷의 값은 promq "sum by (handler) (rate(http_requests_total{job="shop-api"}[1h]))" 로 한 번에 볼 수 있고, 가장 큰 값과 가장 작은 값은 max(...)·min(...) 으로 감싸면 바로 나옵니다. 로그 축에서 0 은 그릴 수 없습니다 - 그래서 최솟값 0 고정과 로그 축은 같이 쓸 수 없습니다. 잃는 것을 적을 때는 '같은 세로 거리가 무엇을 뜻하게 되는가' 를 생각해 보세요.

응용 ① - 나눗셈의 결과에는 어떤 단위가 붙나

같은 대시보드에 패널 둘을 더하세요. id 9 는 제목 디스크가 줄어드는 속도, 쿼리 - deriv(node_filesystem_avail_bytes{job="node",mountpoint="/data"}[1h]), 단위는 1024 로 줄이는 쪽의 초당 바이트입니다. id 10 은 제목 디스크가 바닥날 때까지, 쿼리는 남은 바이트를 줄어드는 속도로 나눈 것이고 단위는 초입니다. 둘 다 타입은 timeseries 입니다. 그리고 /root/gfd-units/07-derived.tsv 에 머리글 없이 세 줄, 각 줄은 탭으로 나눈 두 칸 <단위 식별자> <그 쿼리가 내는 값> 을 적으세요. 차례로 남은 바이트, 줄어드는 속도, 남은 시간이고 값은 소수 세 자리까지 적습니다.

바이트를 초당 바이트로 나누면 초가 남습니다 - 단위는 쿼리의 산수를 따라갑니다. 줄어드는 속도는 deriv 로 구하고, 값이 음수로 나오므로 앞에 빼기를 붙여 양수로 만듭니다. 초당 바이트는 바이트와 다른 갈래의 단위입니다(Data 가 아니라 Data rate). 바이트 단위를 그대로 붙이면 화면이 '4 GiB' 라고 말하지만 실제 뜻은 '초당 4 GiB' 입니다.

응용 ② - 운영 대시보드의 단위·축 결함을 전부 고쳐 제출한다

/opt/lab/gfd/gfd-units/broken.json 은 운영에서 걷어 온 대시보드입니다(uid gfd-units-fix). 패널 넷 모두 단위나 축에 결함이 있습니다. 쿼리는 그대로 두어도 되고 바꿔도 되지만, 화면에 나오는 값과 단위가 서로 맞아야 합니다. 고친 대시보드를 uid gfd-units-fix 로 Grafana 에 올리세요. 4번 패널(초당 요청 수)의 축은 최솟값을 0 으로 고정하고 천장은 걷어 냅니다. 그리고 /root/gfd-units/08-report.tsv 에 머리글 없이 네 줄, 각 줄은 탭으로 나눈 세 칸 <패널 id> <결함 코드> <무엇이 틀렸었나, 20자 이상이고 숫자를 하나 이상 포함> 을 적으세요. 결함 코드는 scale(값의 크기와 단위가 어긋남)·category(단위 갈래가 틀림)·axis(축 때문에 잘림) 셋 중 하나이고, 줄은 패널 id 순서입니다.

1번은 초로 나오는 값에 밀리초가 붙어 있고, 2번은 0..1 비율에 0..100 백분율이 붙어 있습니다. 둘 다 고치는 방법이 두 가지입니다 - 단위를 값에 맞추거나, 값을 단위에 맞게 곱하거나. 어느 쪽이든 됩니다. 3번은 초당 바이트인데 바이트 단위가 붙어 있습니다(갈래가 다릅니다). 4번은 단위는 맞는데 축에 천장이 씌워져 실제 트래픽이 잘립니다 - 12시간 최댓값을 먼저 재 보세요. cp /opt/lab/gfd/gfd-units/broken.json /root/gfd-units/fixed.json 으로 사본을 뜨고 고쳐서 올리면 됩니다.