Prometheus가 메트릭을 모아두면 Grafana는 그 위에 시각화·탐색·Alerting(정해 둔 조건을 넘으면 알림을 보내는 기능) UI를 얹는다. 하지만 Grafana는 데이터를 저장하지 않고, PromQL 쿼리를 그대로 실행해 결과를 보여줄 뿐이다. 이 글은 실무 대화를 통해 정리한 Grafana의 역할과 구체적인 대시보드 구성법을 담는다.
토론 요약
- Grafana는 조회·시각화·Alerting UI를 제공한다. 데이터 저장은 Prometheus가 담당하고, Grafana는 읽기만 한다.
- Prometheus를 데이터소스로 등록하면, Grafana에서 작성한 모든 PromQL이 Prometheus에 실시간으로 실행된다.
- 대시보드를 열 때마다 저장된 쿼리가 다시 실행되어 최신 데이터를 표시한다. 쿼리 결과를 저장하는 것이 아니라, 어떤 쿼리를 실행할지만 저장한다.
- 패널별 PromQL 쿼리가 가장 중요하다. 올바른 쿼리 없이는 올바른 대시보드를 만들 수 없다.
Grafana의 역할: 데이터소스 → 쿼리 → 시각화
1) Prometheus 데이터소스 등록
Grafana는 이미 설치되어 떠 있다고(프로그램이 실행 중이라고) 전제한다(설치 자체는 이 글의 범위 밖이다). 떠 있는 Grafana는 웹 브라우저로 접속해 쓰는 화면 도구라서, 설치할 때 정한 주소를 열고 그때 정한 계정으로 로그인하면 왼쪽 메뉴에 톱니바퀴 모양의 Settings 아이콘이 보인다. 거기서부터 아래 순서를 따라간다.
- Grafana → Settings(톱니바퀴) → Data sources → Add data source
- Type: Prometheus
- URL: Prometheus 서버 주소(예: http://prometheus:9090).
prometheus는 Prometheus가 돌고 있는 컴퓨터의 이름이고,9090은 그 컴퓨터에서 Prometheus에 닿는 포트 번호다 - Save & test — 저장하면서 Grafana가 그 주소로 Prometheus가 열어 둔 쿼리 창구(API)에 실제로 쿼리를 한 번 보내 본다. 성공하면
Successfully queried the Prometheus API.라는 문구가 뜬다(Grafana 공식 문서). 이 문구가 안 뜨면 URL부터 다시 본다 - 이 단계부터 Grafana가 Prometheus의 PromQL을 실행할 준비가 완료된다.
2) 쿼리 → 패널 → 대시보드 흐름
새 대시보드 → Add visualization
→ 데이터소스(Prometheus) 선택
→ PromQL 작성
→ 시각화 옵션 설정(차트타입, 색상, 단위 등)
→ 패널 저장
→ 대시보드에 추가
→ 대시보드 저장
먼저 둘의 관계를 잡고 가야 순서가 읽힌다. 패널은 그래프 한 칸이고, 대시보드는 그 칸들을 한 화면에 모아 둔 판이다. 그래서 순서가 이렇게 된다.
새 대시보드 → Add visualization: 빈 판을 만들고, 그 위에 칸(패널) 하나를 새로 연다데이터소스 선택 → PromQL 작성: 이 칸이 어디(Prometheus)에 무엇(쿼리)을 물을지 정한다시각화 옵션 설정: 받아 온 숫자를 선 그래프로 그릴지, 숫자 하나로 보일지, 단위는 무엇인지 정한다패널 저장 → 대시보드에 추가: 다 만든 칸을 판 위에 붙인다대시보드 저장: 판 전체(어떤 칸이 어디에 있고 각 칸이 무슨 쿼리를 쓰는지)를 저장한다. 패널 저장은 칸 하나의 설정을 확정하는 것이고, 대시보드 저장까지 해야 다음에 열었을 때 그 판이 그대로 남는다
대시보드를 열면 그 안의 패널마다 저장된 쿼리가 Prometheus에 실행되어 최신 데이터를 가져온다.
실무 예제: 경매 데이터 수집 백엔드 대시보드 구성
경매 데이터를 주기적으로 수집하는 백엔드라면, 일반적인 HTTP 메트릭 외에 배치/수집 작업 상태도 봐야 한다.
기본 패널 구성
- HTTP/API 메트릭: RPS(초당 처리한 요청 수, Requests Per Second), p95 응답시간(전체 요청 중 95%가 이 시간 안에 끝났다고 할 수 있는 값), 에러율(5xx — 서버 쪽 잘못으로 실패한 요청의 비율), 인스턴스 가용성
- 배치 작업 메트릭: 마지막 실행 시간, 완료 여부, 처리 건수, 실패 건수
- 데이터 수집 메트릭: 수집 시간, 시간당 처리 건수, 외부 API 호출 성공/실패율
- 저장소 메트릭: DB 인서트 성공/실패, 처리량
- JVM/리소스: 메모리, GC, 스레드, CPU
이 목록 중 이 글에서 쿼리까지 정한 것은 아래 패턴에 있는 HTTP · JVM 힙 · 스크레이프 상태뿐이다. 배치 · 수집 · 저장소 · GC 패널의 쿼리는 이 글에서 정하지 않았다.
자주 쓰는 PromQL 패턴
아래 쿼리의 http_server_requests_seconds_* 메트릭은 내가 만든 것이 아니라 Spring Boot Actuator가 이 서버가 받은 HTTP 요청마다 처리 시간을 세어 내보내는 것이다(자세한 풀이는 PromQL 실전 글의 Spring Boot Actuator 절). job은 Prometheus가 숫자를 가져올 때 자동으로 붙이는 서비스 이름표이고, 이 백엔드의 job 이름은 farm-predict-kamis-dev다.
쿼리 안의 $job은 아래 「템플릿 변수」 절에서 만드는 드롭다운 값이 들어갈 자리다. 변수를 아직 만들지 않았다면 $job 자리에 farm-predict-kamis-dev를 그대로 적는다.
- RPS:
sum by (instance) (rate(http_server_requests_seconds_count{job="$job"}[$__rate_interval])) - p95 응답시간:
histogram_quantile(0.95, sum by (le) (rate(http_server_requests_seconds_bucket{job="$job"}[$__rate_interval]))) - 에러율:
sum(rate(http_server_requests_seconds_count{job="$job",status=~"5.."}[$__rate_interval])) / sum(rate(http_server_requests_seconds_count{job="$job"}[$__rate_interval])) - JVM 힙:
jvm_memory_used_bytes{job="$job",area="heap"} - 스크레이프 상태:
up{job="$job"}
한 줄씩 보면 이렇다.
http_server_requests_seconds_count는 서버가 시작된 뒤 지금까지 받은 요청 수를 계속 더해 가는 숫자다. 줄어들지 않고 늘기만 한다{job="$job"}처럼 중괄호 안에 적는 것은 라벨 조건이다. 여러 서비스의 숫자 중에서 job 라벨이 그 값과 같은 것만 골라낸다[$__rate_interval]은 「최근 얼마 동안」을 볼지 정하는 구간이다. 이 값은 내가 적지 않고 Grafana가 그래프가 보여 주는 기간(최근 1시간인지 하루인지)과 스크레이프 간격을 보고 정해 넣는데, 적어도 스크레이프 간격의 4배가 된다(Grafana 공식 문서)rate(...)는 그 구간 동안 늘어난 양을 초당 평균으로 바꾼 값이고,sum by (instance) (...)는 그 값을 인스턴스별로 더해 합친 것이다 — 그래서 RPS 쿼리는 인스턴스마다 초당 몇 번 요청이 왔는지를 보여준다http_server_requests_seconds_bucket은 요청을 응답 시간 구간(버킷)으로 나눠 센 숫자다. 구간의 경계는le(“less than or equal”, ~이하) 라벨에 담기고,le="0.3"은 「0.3초 이하로 끝난 요청 수」다.sum by (le)는 인스턴스가 여럿이어도 같은 구간끼리 더해 하나의 분포로 만든다histogram_quantile(0.95, ...)는 그 분포에서 전체 요청의 95%가 이 시간 안에 끝났다고 할 수 있는 경계값, 즉 p95를 계산해 낸다status=~"5.."의=~는 「같다」가 아니라 정규식에 맞는지 본다..은 아무 글자 하나라서"5.."는 500부터 599까지의 상태 코드에 맞는다- 에러율 쿼리는 상태 코드가 5xx인 요청의 초당 횟수를 전체 요청의 초당 횟수로 나눈 것이다. 여기서는
sum뒤에by가 없어서 인스턴스를 가리지 않고 전부 하나로 더한다 — 서비스 전체의 에러율 하나가 나온다. 결과는 백분율이 아니라 0에서 1 사이의 비율이고,0.05가 5%다 jvm_memory_used_bytes{..., area="heap"}는 애플리케이션이 지금 쓰고 있는 JVM 힙 메모리량을 그대로 보여준다. 이 숫자도 Actuator가 내보낸다 — Spring Boot는 메모리 · GC · 스레드 같은 JVM 메트릭을 자동으로 켠다(Spring Boot 공식 문서)up{job="$job"}은 앱이 아니라 Prometheus가 스크레이프할 때마다 스스로 만드는 숫자다. Prometheus가 그 서비스를 정상적으로 스크레이프하고 있으면 1을, 못 하고 있으면 0을 내보낸다
패널별 시각화 설정
- RPS, p95, 에러율, GC: Time series (시계열 그래프)
- 에러율: 임계값(예: 5%) 표시로 한눈에 이상 여부 판단. 패널 편집 화면의 Thresholds 항목에서 값(에러율은 비율이라
0.05)을 넣고, Show thresholds에서 선으로 보이게 고른다(Grafana 공식 문서) - JVM 힙: Time series + 단위 설정(Bytes)
- 인스턴스 수: Stat (숫자 표시) -
count(up{job="$job"} == 1).== 1은up값이 1인 것(살아 있는 인스턴스)만 남기고 나머지를 버리며,count(...)는 남은 것이 몇 개인지 센다
템플릿 변수로 재사용성 높이기
템플릿 변수를 쓰면 동일한 대시보드를 여러 서비스/환경(개발용 · 운영용처럼 따로 띄운 같은 서비스)에 재사용할 수 있다.
변수 정의
- Dashboard settings → Variables → Add variable
- Name:
job - Type: Query
- Data source: Prometheus
- Query:
label_values(http_server_requests_seconds_count, job) - Multi-select 활성화하면 여러 서비스 동시 비교 가능
label_values(http_server_requests_seconds_count, job)는 http_server_requests_seconds_count라는 메트릭에 실제로 붙어 있는 job 라벨값을 전부 모아 목록으로 돌려준다. 이 목록이 그대로 변수의 선택지가 되어, 드롭다운에 서비스 이름들이 나타난다.
쿼리에서 변수 사용
rate(http_server_requests_seconds_count{job=~"$job"}[$__rate_interval])
dropdown에서 job을 선택하면 쿼리가 실행되기 전에 $job 자리에 고른 값이 들어가서, 그 서비스의 숫자만 걸러진다.
여기서는 앞 절의 =가 아니라 =~를 썼다. Multi-select로 여러 개를 고르면 Grafana가 고른 값들을 a|b처럼 |로 이어서 넣는데, 이건 「a 또는 b」라는 정규식이라 =로는 맞는 것이 없다(Grafana 공식 문서). 그래서 Multi-select를 켰다면 앞 절의 쿼리들도 job="$job"을 job=~"$job"으로 바꿔 쓴다.
Explore로 쿼리 실험 후 패널에 옮기기
- 좌측 메뉴 → Explore
- 데이터소스: Prometheus 선택
- PromQL 작성 후 라벨/윈도/집계를 실험하며 조정한다 — 라벨은
{job="..."}처럼 어떤 대상만 걸러 볼지, 윈도는[5m]처럼 최근 몇 분의 데이터를 볼지, 집계는sum·avg같은 함수로 여러 값을 어떻게 하나로 합칠지를 뜻한다 - 원하는 시계열이 나오면 “Add to dashboard” → 새 패널로 저장
- 이후 패널을 대시보드에서 편집해 공통 변수나 시각화 옵션 추가
Alerting 간단 구성
Grafana Alerting으로 임계값 기반 알림을 만들 수 있다.
알림 룰 생성
- 좌측 메뉴 → Alerts & IRM(알림 관련 메뉴를 모아 둔 이름이다) → Alert rules → + New alert rule (지금 Grafana 공식 문서 기준이다. 버전에 따라 메뉴 이름이 조금 다르다)
- PromQL 쿼리 입력 (예:
sum(rate(http_server_requests_seconds_count{job="farm-predict-kamis-dev",status=~"5.."}[5m])) / sum(rate(http_server_requests_seconds_count{job="farm-predict-kamis-dev"}[5m]))) - 조건 설정 (예: > 0.05, 지속시간 2m) — 에러율이 0.05(5%)를 넘는 상태가 2분 동안 계속되어야 알림이 나간다. 잠깐 튀었다 내려가면 알림을 보내지 않는다(Grafana는 이 지속시간을 pending period라고 부른다)
- 알림 받을 곳 선택 (Slack, Email, Webhook 등). 지금 Grafana 화면에서는 이것을 Contact point라고 부른다
- 저장
2번 쿼리는 대시보드 쿼리와 달리 $job 대신 job 이름을 그대로 적었다. 알림 룰에는 드롭다운이 없어서 대시보드 변수를 쓸 수 없다(Amazon Managed Grafana 문서에 「Grafana does not support alert queries with template variables」로 적혀 있다. Amazon이 Grafana를 대신 띄워 운영해 주는 서비스의 문서인데, Grafana를 만든 쪽 문서에서는 이 문장을 찾지 못해서 이것을 근거로 댔다). 구간도 같은 이유로 $__rate_interval 대신 [5m]을 적었다 — $__rate_interval이 알림 룰에서 동작하는지는 확인하지 않았다.
역할 분담
- Grafana Alerting: 조건 평가 및 알림 발송
- Alertmanager (선택): 알림 라우팅, 사일런스, 집계(비슷한 알림 여러 개를 한 통으로 묶어 보내기) — 알림 종류마다 받는 곳을 나누거나 묶어 보내야 할 때 쓴다. 이때는 Grafana가 판단한 알림을 Alertmanager에 넘기고, 받는 곳으로 보내는 일은 Alertmanager가 맡는다. Alertmanager를 데이터소스로 등록하고 Alerting 설정에서 그쪽으로 보내기를 켜면 된다(Grafana 공식 문서)
흐름 한눈에 보기
Prometheus는 모은 숫자를 자기 안의 TSDB에 쌓는다. Grafana는 패널의 PromQL을 HTTP 요청에 실어 Prometheus에 보내고 결과만 받아 온다. 이때 쓰는 HTTP 메서드는 데이터소스 설정의 HTTP method에서 고르고 기본값은 POST다(Grafana 공식 문서) — 쿼리가 길어도 주소에 다 싣지 않고 본문에 실어 보낼 수 있어서다. 알림 룰도 대시보드를 거치지 않고 자기 쿼리를 같은 데이터소스로 보낸다.
아래 그림의 화살표는 요청 방향이 아니라 데이터가 흘러가는 방향이다. 테이블은 결과를 표로 보여 주는 시각화다.
결론/팁
- 쿼리가 핵심: 올바른 PromQL 없이는 올바른 대시보드를 만들 수 없다.
- 실시간 실행: 대시보드를 열 때마다 쿼리가 Prometheus에 실행되므로, 항상 최신 데이터를 본다.
- Explore 활용: 쿼리를 완성한 뒤 대시보드에 옮기는 것이 효율적이다.
- 변수로 재사용: 동일한 대시보드 구조를 여러 서비스에 맞춰 쓸 수 있다.
- 언어 설정: Preferences → Language에서 한국어를 선택할 수 있지만, 번역이 부분적일 수 있다.
자신만의 철학을 만들어가는 중입니다.
댓글남기기