Grafana — 대시보드는 질문이다 · 대시보드의 비용 · 이론
대시보드 하나를 여는 값은 얼마인가
한 줄 요약
대시보드 하나를 여는 값은 "패널 수" 가 아니라 질의 수 곱하기 새로고침 주기이고, 그 값을 아무도 세어 보지 않는다.
왜 이게 필요했나
모니터링이 느려졌다는 신고는 대개 "쿼리 하나가 무겁다" 로 시작해서 "대시보드가 너무 많다" 로 끝난다. 그런데 둘 사이에 아무도 세어 보지 않은 숫자가 하나 있다 — 대시보드 하나를 한 번 여는 데 질의가 몇 번 날아가는가.
세는 법은 어렵지 않다. 패널마다 쿼리가 하나 이상 붙어 있으니 그 쿼리를 모두 더하고, 화면 위쪽의 변수 중 목록을 서버에 물어보는 것이 있으면 그만큼 더한다. 패널 여덟에 쿼리 열, 변수 질의 둘이면 한 번 여는 데 열두 번이다. 여기에 자동 새로고침이 곱해진다. 10초 주기면 1분에 예순 번, 한 시간에 삼천육백 번이다. 벽걸이 화면 하나가 하루에 팔만 번을 던지고, 그 화면을 아무도 보고 있지 않은 밤에도 똑같이 던진다.
더 나쁜 것은 이 비용이 화면에 전혀 드러나지 않는다는 점이다. 패널을 하나 더 붙이는 일은 클릭 세 번이고, 비용은 다른 팀의 Prometheus 에서 발생한다. 그래서 대시보드는 언제나 무거워지는 쪽으로만 자란다.
어떻게 동작하나
비용은 세 겹으로 쌓인다.
| 겹 | 무엇을 세나 | 어디서 읽나 |
| --- | --- | --- |
| 질의 횟수 | 열 때 몇 번, 1분에 몇 번 | 대시보드 JSON 의 패널·쿼리·변수·refresh |
| 계열 수 | 쿼리 하나가 몇 줄을 돌려주나 | 쿼리를 실제로 던져 결과 줄을 센다 |
| 점 개수 | 계열 하나에 점이 몇 개 오나 | 시간 범위 나누기 해상도 |
첫째 겹은 JSON 만 보면 센다. 대시보드 JSON 모델에는 panels 배열과 각 패널의 targets, 그리고 자동 새로고침 주기인 refresh 가 그대로 적혀 있다([대시보드 JSON 모델 문서](https://grafana.com/docs/grafana/latest/visualizations/dashboards/build-dashboards/view-dashboard-json-model/)). 변수는 templating.list 에 있고, 그중 서버에 목록을 물어보는 것은 type 이 query 인 것들이다.
둘째 겹은 던져 봐야 안다. sum by (handler) (...) 는 계열 넷을 돌려주지만 집계를 빼고 rate(http_request_duration_seconds_bucket{...}[5m]) 을 그대로 그리면 핸들러 넷 곱하기 버킷 열둘, 마흔여덟 줄이 온다. 같은 패널 한 칸에 마흔여덟 개의 선이 그려지는데, 그 화면에서 읽어 낼 수 있는 것은 아무것도 없다. 계열 수는 브라우저가 그려야 할 점의 개수를 정하고, 그래서 화면이 느려지는 진짜 이유가 된다.
셋째 겹은 시간 범위와 해상도다. 구간 질의는 start·end·step 을 받아 그 사이를 step 간격으로 잘라 돌려준다([Prometheus 질의 API 문서](https://prometheus.io/docs/prometheus/latest/querying/api/)). 두 시간을 15초 간격으로 보면 계열 하나에 481개, 300초 간격이면 25개다. 같은 질문인데 스무 배가 차이 난다. 6시간짜리 화면에서 15초 해상도가 필요한 일은 거의 없다.
줄이는 방법 중 가장 값싼 것은 이미 아는 답을 미리 계산해 두는 것이다. 마흔여덟 개의 버킷 계열에서 매번 분위수를 계산하는 대신, Prometheus 가 정해진 주기마다 그 계산을 한 번 하고 결과를 새 시계열로 남기게 한다. 레코딩 룰이다. 대시보드는 그 새 시계열을 그냥 읽기만 하면 된다. 이름은 관례가 정해져 있다 — 수준:지표:연산 꼴로 적는다([레코딩 룰 관례](https://prometheus.io/docs/practices/rules/)).
현장에서 만나는 모습
데이터 플랫폼 팀의 Prometheus 가 오후마다 느려졌다. 범인은 사람이 여는 대시보드가 아니라 회의실 벽에 띄워 둔 화면 두 개였다. 둘 다 새로고침이 5초였고 쿼리가 각각 열네 개였다. 아무도 보지 않는 시간에도 1분에 삼백서른여섯 번이 날아가고 있었다. 새로고침을 1분으로 바꾸고 안 쓰는 변수 셋을 지운 것만으로 그 부하가 스물여덟 분의 일이 됐다. 패널은 하나도 지우지 않았다.
또 하나 흔한 것은 아무도 쓰지 않는 변수다. 화면 위쪽의 드롭다운은 한번 만들어 두면 지우는 사람이 없는데, 대시보드를 열 때마다 목록을 채우려고 질의가 날아간다. 그 변수를 어느 패널도 참조하지 않아도 마찬가지다.
이 환경에서 판정할 수 있는 것과 없는 것
비용을 밀리초로 재는 일은 이 파드에서 의미가 없다. CPU 두 개를 학습자 프로세스와 채점기가 나눠 쓰고, 같은 맥에서 다른 컨테이너가 함께 돌기 때문에 같은 쿼리도 잴 때마다 다른 시간이 나온다. 그래서 여기서는 개수로만 판정한다 — 대시보드 JSON 에서 다시 센 패널·쿼리·변수 수, 실제로 던져 나온 계열 수, 구간 질의가 돌려준 점 개수. 레코딩 룰은 Prometheus 에 실제로 반영해 값이 원래 쿼리와 맞는지 본다. 화면이 실제로 얼마나 빨리 뜨는지는 결국 브라우저에서 눈으로 봐야 한다.
다음 실습에서 할 것
예산을 넘긴 대시보드 하나를 받아 값을 매긴다. JSON 에서 패널·쿼리·변수 질의를 세어 "한 번 열 때의 질의 수" 를 내고, 각 쿼리를 실제로 던져 계열 수를 재어 가장 무거운 패널을 찾는다. 시간 범위와 해상도를 바꿔 가며 돌아오는 점 개수를 재고, 새로고침 주기를 곱해 분당 질의 수를 낸다. 무거운 분위수 계산은 레코딩 룰로 옮겨 같은 값을 더 싸게 얻고, 예산을 파일로 적은 뒤 그 예산을 검사하는 스크립트를 만들어, 줄인 대시보드가 그 검사를 통과하는 것까지 확인한다.