Prometheus와 Grafana로 마이크로서비스 모니터링하기

Navendu Pottekkat

Navendu Pottekkat

June 8, 2023

Ecosystem

마이크로서비스 시스템을 견고하게 만들기 위해서는 지속적인 모니터링이 중요합니다. 적절한 모니터링 없이는 마이크로서비스가 빠르게 과부하 상태에 이르러 오류와 성능 저하를 초래할 수 있습니다.

지속적인 모니터링을 통해 개발자는 서비스에 문제가 발생하자마자 이를 감지하고 심각한 손상을 방지하기 위한 조치를 취할 수 있습니다. 또한 서비스의 성능에 대한 통찰력을 제공하여 정보에 기반한 결정을 내릴 수 있게 합니다.

이 글에서는 PrometheusGrafana라는 두 가지 인기 있는 도구를 사용하여 마이크로서비스 애플리케이션에 모니터링을 설정하는 방법을 소개합니다.

이 튜토리얼의 소스 코드와 Docker Compose 파일은 pottekkat/monitoring-101에서 확인할 수 있습니다.

Prometheus 기본 사항

Prometheus는 오픈소스 모니터링 및 알림 도구입니다. 이 도구는 HTTP 요청을 보내 마이크로서비스로부터 메트릭(측정값)을 "풀링"하고, 그 결과를 시계열 데이터베이스에 저장합니다.

Prometheus가 제공하는 클라이언트 라이브러리를 사용하여 서비스를 계측할 수 있습니다. 이를 통해 서비스에서 사용자 정의 메트릭을 생성하고 수집할 수 있습니다.

Prometheus는 또한 Prometheus 형식이 아닌 메트릭을 풀링할 수 있게 해주는 익스포터를 제공합니다. 익스포터는 중간자 역할을 하여 내보낸 데이터를 Prometheus가 읽을 수 있는 형식으로 변환합니다.

1-prometheus-architecture.png

Prometheus는 수집된 데이터를 작업하기 위한 강력한 쿼리 언어인 PromQL을 제공합니다. PromQL을 사용하여 복잡한 쿼리를 생성하여 데이터를 필터링, 집계 및 원하는 형식으로 변환할 수 있습니다.

메트릭을 풀링하는 것 외에도, Prometheus는 설정된 임계값이 초과될 때 알림을 트리거할 수 있습니다. 알림 메커니즘은 매우 구성 가능하며, Slack이나 이메일과 같은 곳으로 알림을 보낼 수 있습니다.

Prometheus는 수집된 메트릭을 쉽게 시각화할 수 있는 GUI를 제공합니다. 또한 Grafana와 같은 고급 시각화 도구와 통합됩니다.

prometheus-dashboard.png

메트릭 유형

Prometheus는 네 가지 핵심 메트릭 유형을 제공합니다:

  1. Counter: 단일 단조 증가 카운터를 나타냅니다. 값은 증가하거나 재시작 시 0으로 재설정될 수 있습니다. 이를 사용하여 처리된 요청 수와 같은 메트릭을 나타낼 수 있습니다.
  2. Gauge: 증가하거나 감소할 수 있는 숫자 값을 나타냅니다. 메모리 사용량이나 초당 요청 수와 같은 값을 나타내는 데 사용할 수 있습니다.
  3. Histogram: 데이터를 구성 가능한 버킷으로 샘플링합니다. 요청 지속 시간이나 응답 크기와 같은 값을 나타내는 데 사용합니다.
  4. Summary: 히스토그램과 유사하며, 슬라이딩 시간 창 동안 구성 가능한 값을 계산합니다.

이 메트릭 유형과 사용 방법에 대해 더 자세히 알아보려면 공식 문서를 참조하세요.

샘플 애플리케이션

우리의 샘플 애플리케이션은 API 게이트웨이, Go 애플리케이션, 그리고 Python 애플리케이션으로 구성됩니다.

2-sample-app-flowchart.png

이 애플리케이션은 제공한 <name>과 선택한 언어로 "Hello <name>!"을 반환합니다. Apache APISIX는 서비스로 트래픽을 전달하는 API 게이트웨이 역할을 합니다.

아래 다이어그램은 시스템이 어떻게 작동하는지 보여줍니다.

3-sample-app-sequence.png

  1. 사용자가 애플리케이션의 진입점인 APISIX에 GET 요청을 보냅니다.
  2. APISIX는 요청을 Go 서비스로 전달합니다.
  3. Go 서비스는 지정된 언어로 "Hello"를 얻기 위해 Python 서비스에 GET 요청을 보냅니다.
  4. Python 서비스는 "Hello"의 필요한 번역을 응답합니다.
  5. Go 서비스는 쿼리에서 제공된 이름을 사용하여 필요한 응답을 생성하고 APISIX로 보냅니다.
  6. APISIX는 응답을 사용자에게 다시 전달합니다.

Prometheus를 구성하여 메트릭 수집하기

우리는 애플리케이션의 모든 서비스에서 메트릭을 계측하고 내보내어 Prometheus에서 수집할 것입니다. API 게이트웨이인 Apache APISIX부터 시작하겠습니다.

APISIX에서 메트릭 내보내기

Apache APISIX는 오픈소스 클라우드 네이티브 API 게이트웨이입니다.

APISIX에 대해 알 필요는 없으며, 제공된 Docker Compose 파일을 사용하여 모든 것을 설정할 수 있습니다. APISIX에 대해 더 알아보려면 api7.ai/apisix를 방문하세요.

APISIX는 Prometheus 형식으로 메트릭을 쉽게 내보낼 수 있는 prometheus 플러그인을 제공합니다. APISIX 구성 파일에서 이 플러그인을 구성할 수 있습니다:

apisix:
  enable_admin: false # APISIX를 독립 모드로 실행
  config_center: yaml # etcd 대신 YAML 파일을 사용하여 구성 저장
plugin_attr:
  prometheus:
    export_uri: /prometheus/metrics # prometheus 플러그인을 활성화하고 메트릭을 이 URI로 내보냄
    enable_export_server: false # 기본 데이터 플레인 포트에서 메트릭 내보내기

이제 모든 Route에서 플러그인을 활성화하기 위해 글로벌 규칙으로 만들 수 있습니다:

routes:
  # /hello/* 요청을 go-app으로 전달
  - uri: /hello/*
    upstream:
      type: roundrobin
      nodes:
        "go-app:8080": 1
    plugins:
      # 요청을 go-app으로 전달하기 전에 "/hello" 접두사 제거
      proxy-rewrite:
        regex_uri:
          - "/hello/(.*)"
          - "/$1"
  # 지정된 URI로 Prometheus 메트릭 내보내기
  - uri: /prometheus/metrics
    plugins:
      public-api:
# 모든 Route에서 Prometheus 플러그인을 글로벌로 활성화
global_rules:
  - id: 1
    plugins:
      prometheus:
        prefer_name: true
#END

이렇게 하면 Apache APISIX에서 /prometheus/metrics 엔드포인트로 메트릭이 내보내집니다.

사용 가능한 메트릭에 대해 더 알아보려면 문서를 참조하세요.

Go 서비스에서 메트릭 계측 및 내보내기

Prometheus는 Go 애플리케이션을 계측하기 위한 공식 Go 클라이언트 라이브러리를 제공합니다.

기본적으로 Prometheus는 기본 Go 메트릭을 노출합니다. 또한 애플리케이션별 사용자 정의 메트릭을 생성할 수도 있습니다.

우리 서비스에서는 기본 메트릭을 노출하고 요청 수를 추적하기 위한 사용자 정의 카운터 메트릭을 생성할 것입니다:

package main

import (
  "encoding/json"
  "fmt"
  "io/ioutil"
  "log"
  "net/http"
  "os"

  // Prometheus 패키지
  "github.com/prometheus/client_golang/prometheus"
  "github.com/prometheus/client_golang/prometheus/promauto"
  "github.com/prometheus/client_golang/prometheus/promhttp"
)

// Response는 python-app에서 얻은 메시지를 저장
type Response struct {
  Message string `json:"message"`
}

// 기본 언어와 이름
var (
  lang = "en"
  name = "John"
)

// 새로운 사용자 정의 Prometheus 카운터 메트릭 생성
var pingCounter = promauto.NewCounter(
  prometheus.CounterOpts{
    Name: "go_app_request_count",
    Help: "go-app이 처리한 요청 수",
  },
)

// HelloHandler는 go-app에 대한 요청을 처리
func HelloHandler(w http.ResponseWriter, r *http.Request) {
  lang = r.URL.String()
  name = r.URL.Query()["name"][0]
  
  fmt.Println("Request for", lang, "with name", name)
  pingCounter.Inc()
  
  pUrl := os.Getenv("PYTHON_APP_URL")
  if len(pUrl) == 0 {
    pUrl = "localhost"
  }

  // python-app을 호출하여 번역을 얻음
  resp, err := http.Get("http://" + pUrl + ":8000" + lang)
  if err != nil {
    log.Fatalln(err)
  }

  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    log.Fatalln(err)
  }

  resp.Body.Close()

  var m Response
  json.Unmarshal(body, &m)

  // 지정된 언어로 "Hello name!" 응답 전송
  fmt.Fprintf(w, "%s %s!", m.Message, name)
}

func main() {
  // Prometheus 메트릭 노출
  http.Handle("/metrics", promhttp.Handler())
  http.HandleFunc("/", HelloHandler)
  
  http.ListenAndServe(":8080", nil)
}

이렇게 하면 /metrics 엔드포인트로 메트릭이 노출됩니다. Go 클라이언트 라이브러리에 대해 더 알아보려면 GitHub 저장소를 참조하세요.

Python 서비스에서 메트릭 계측 및 내보내기

Prometheus는 또한 공식 Python 클라이언트 라이브러리를 제공합니다. 특정 사용 사례에 맞게 조정된 타사 라이브러리도 있습니다.

우리 서비스는 FastAPI를 사용하며, prometheus_fastapi_instrumentator 라이브러리를 사용하여 계측할 것입니다:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from prometheus_fastapi_instrumentator import Instrumentator

app = FastAPI()

hello = {"en": "Hello", "fr": "Bonjour", "es": "Hola", "ml": "ഹലോ"}

# 기본 Python 메트릭을 /metrics 엔드포인트로 노출
Instrumentator().instrument(app).expose(app)

@app.get("/{lang}")
async def get_hello(lang):
    return {"message": hello[lang]}

사용자 정의 메트릭 생성에 대해 더 알아보려면 문서를 참조하세요.

Prometheus 구성

이제 Prometheus에서 이러한 메트릭을 스크랩하고 수집할 수 있습니다.

각 서비스에서 메트릭을 수집하도록 Prometheus를 구성할 수 있습니다. 기본적으로 Prometheus는 /metrics 경로에서 메트릭을 확인합니다:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]
  
  - job_name: "go-app"
    static_configs:
      - targets: ["go-app:8080"]

  - job_name: "python-app"
    static_configs:
      - targets: ["python-app:8000"]

  - job_name: "apisix"
    static_configs:
      - targets: ["apisix:9080"]
    metrics_path: "/prometheus/metrics"

이제 Prometheus 대시보드(기본 포트 9090)를 열고 네비게이션 바에서 "Status"를 클릭한 후 "Targets"를 선택하면 서비스에서 스크랩된 메트릭의 상태를 확인할 수 있습니다.

prometheus-target-status.png

Prometheus에서 메트릭 쿼리 및 시각화

이제 Prometheus 대시보드를 사용하여 쿼리와 복잡한 표현식을 실행할 수 있습니다.

prometheus-query.png

Prometheus 쿼리에 대해 더 알아보려면 공식 문서를 참조하세요.

Grafana를 사용하여 Prometheus 쿼리하기

Grafana는 Prometheus와 함께 작동하여 메트릭을 수집, 쿼리 및 시각화하기 위한 포괄적인 도구를 제공하는 오픈소스 데이터 시각화 플랫폼입니다.

Prometheus는 메트릭 수집과 쿼리에 능숙하지만 의미 있는 시각화를 생성하기 위한 도구가 부족합니다. Grafana는 수집된 메트릭을 시각화로 변환하여 이러한 한계를 극복합니다.

Grafana는 Prometheus 외에도 다양한 데이터 소스와 호환됩니다.

Grafana를 배포한 후 웹 UI(기본 포트 3000)를 열 수 있습니다.

먼저 Prometheus를 데이터 소스로 추가해야 합니다. 이를 위해 /datasources 또는 "Configuration"과 "Data sources"로 이동합니다. "Add data source"를 클릭하고 Prometheus를 선택합니다. Prometheus가 배포된 위치를 지정하고 연결을 저장하고 테스트합니다.

grafana-add-prometheus.png

사전 구축된 Grafana 대시보드 사용

Grafana는 사전 구축된 Grafana 대시보드를 포함한 공개 대시보드 저장소를 호스팅합니다. 이를 Grafana 인스턴스에서 사용하여 관련 메트릭을 빠르게 시각화할 수 있습니다.

우리는 Prometheus Go 클라이언트 라이브러리에서 발행한 프로세스 상태를 처리하고 시각화할 Go Processes 대시보드를 사용할 것입니다.

이 템플릿을 가져오려면 먼저 대시보드 저장소에서 ID(6671)를 복사합니다. Grafana UI에서 "Dashboards"로 이동하여 "Import"를 선택합니다. 복사한 ID를 붙여넣고 "Load"를 클릭합니다.

grafana-dashboard.png

다른 사전 구축된 대시보드를 탐색하거나 자신만의 대시보드를 생성할 수도 있습니다. 이에 대해 더 알아보려면 문서를 참조하세요.

다음 단계

이 튜토리얼은 여기까지입니다!

이 글은 서비스에 모니터링을 설정하는 방법에 대한 소개일 뿐이며, 아래 언급된 리소스에서 Prometheus와 Grafana에 대해 더 많이 배우기를 권장합니다:

이 튜토리얼의 전체 코드와 Docker Compose 파일은 pottekkat/monitoring-101에서 확인할 수 있습니다.

Tags: