LabHub
배우기 러닝패스 코스

Grafana Dashboards

The same 0.42 meant 420 milliseconds to half the room and 0.42 milliseconds to the rest

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 으로 사본을 뜨고 고쳐서 올리면 됩니다.