728x90
반응형

Prometheus (프로메테우스란)?

지표들을 시계열 데이터로 수집하고 측정하는 오픈 소스 모니터링 툴킷을 말한다.

여기서 지표라는 것은 예를 들어 웹 서버같은 경우 "요청수", "지연시간" 등이 될 수 있겠고 데이터 베이스 서버같은 경우에는 "커넥션 수", "쿼리 수" 등을 말할 수 있다.

이런 지표들을 통하여 서비스 부하, 통계등을 측정하는데 유용할 수 있다.

 

 

 

특징

  • 측정항목 이름과 키/값 쌍으로 식별되는 다차원 데이터 모델
  • 유연한 쿼리 언어인 PromQL 지원
  • 분산 서버에 의존하지 않고 단일 서버 노드에 자율적
  • 시계열 수집은  HTTP를 통한 풀 모델을 통해 발생
  • 푸쉬 시계열은 중간 게이트웨이를 지원
  • 다양한 그래프 및 대시보드 지원

 

언제 적합하고 적합하지 않은가?

프로메테우스는 빠르게 수집하고 모니터링 할 수 있는 시스템에 적합하나 100% 정확성이 필요한 시스템에는 다른 도구와 사용하는 것이 좋다.

 

프로메테우스 동작 방식이 일정 주기를 간격으로 수집하기 때문에 간격 내에 갑작스럽게 발생하는 변동성이나 이벤트를 놓칠 수 있으며 100% 캡쳐하기 어려울 수 있다. 또한 분산 시스템에서는 네트워크나 다운타임으로 데이터 손실이 발생할 수 있다. 그렇기때문에 모든 데이터를 수집하는 것이 아니고 일정 간격으로  샘플링 된 데이터를 수집하기때문에 근사치를 활용하는 방식으로 가는 것이 좋다.

 

구성요소

Prometheus 생태계는 여러 구성 요소로 구성되며 그 중 다수는 선택 사항이다.

  • 시계열 데이터를 스크랩하고 저장하는 기본 Prometheus 서버
  • 애플리케이션 코드 계측을 위한 클라이언트 라이브러리
  • 단기 작업 지원을 위한 푸시 게이트웨이
  • HAProxy, StatsD, Graphite 등과 같은 서비스를 위한 특수 목적 수출업체
  • 경고를 처리하는 경고 관리자
  • 다양한 지원 도구

 

아키텍처

 

중간 푸쉬 게이트웨이를 통하여 측정항목을 스크랩한다. 스크랩을 통하여 모든 샘플을 로컬에 저장하고 이 데이터에 대한 규칙을 실행하여 기존 데이터에서 새로운 집계 및 기록하거나 경고를 생성한다. Grafana 또는 기타 API 소비자를 사용하여 수집된 데이터를 시각화할 수 있다.

여기서 TSDB란  "Time Series Database"의 약자로, 프로메테우스에서 사용되는 데이터베이스 형태를 나타낸다.

 

RDB vs Prometheus

로그를 RDB에 기록하여 측정하는 것과 Prometheus를 사용하여 측정하는 것이 무엇이 다른가? 에 대한 의문점이 들 수 있다.

  • RDB는 정형화된 데이터를 저장하는 용도지만 Prometheus는 모니터링에 최적화된 시스템으로 설계되었다.
  • Prometheus는 데이터 기반의 경고 시스템을 내장하고 있어 문제 발생 시 신속한 대응이 가능하다. 
  • 시스템의 상태 및 성능을 실시간으로 파악하는 데 강점이 있다.

 

📘 설치 개요

Docker를 사용하여 Prometheus 서버를 구동하고 호스트에서는 FastAPI를 사용하여 웹 서버를 실행한다.
백엔드 개발에 중점을 둔 것으로 로그 출력과 Prometheus의 스크랩 동작을 확인하는 것을 목표로 한다.

 

Github에 풀소스를 업로드하였으니 여기에서 다운받아 설치해보면된다. 

https://github.com/yscho03/sample-fastapi-with-prometheus

 

yscho03/sample-fastapi-with-prometheus

FastAPI에서 Prometheus 사용하기 샘플 코드. Contribute to yscho03/sample-fastapi-with-prometheus development by creating an account on GitHub.

github.com

 

💻 설치 방법

1. Docker로 Promethues 서버 설치

먼저 docker-compose.yml 파일을 작성해보자. 여기서 volumes 부분은 호스트에 있는 prometheus.yml 파일을 연결하도록 설정했고 호스트 네트워크와 연결하기 위해 extra_hosts를 사용하여 호스트 매핑을 설정했다.

version: '3'

services:
  prometheus:
    image: prom/prometheus
    extra_hosts:
      - "host.docker.internal:${HOST_IP}"    
    ports:
      - "9090:9090"
    volumes:
      - ./config/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    command: 
      - "--log.level=debug"
      - "--config.file=/etc/prometheus/prometheus.yml"

 

그 다음은 프로메테우스 설정 파일 ./config/prometheus/prometheus.yml 을 작성하자.

전체 디폴트는 15초로 설정하였고 sample이라는 job_name으로 수집주기는 기본 5초로 설정하였다. 이를 통하여 프로메테우스 서버는 호스트 웹 서버의 8000 포트를 5초 간격으로 요청할 것이다.

global:
  scrape_interval: 15s
  evaluation_interval: 15s 

scrape_configs:
  - job_name: 'sample'
    scrape_interval: 5s
    static_configs:
      - targets: ['host.docker.internal:8000']

 

이제 docker-compose 실행하여 container를 생성해보자.

$ export HOST_IP=$(echo `hostname -I | awk '{print $1}'`)
$ docker-compose up -d

2. FastAPI 환경 설치

FastAPI 웹 서버를 만들어보자. 필요한 패키지를 설치한다.

$ pip install fastapi uvicorn[standard]
$ pip install prometheus-fastapi-instrumentator

 

main.py에 다음과 같이 코딩을 한다.

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
from prometheus_fastapi_instrumentator import Instrumentator

app = FastAPI()

def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    openapi_schema = get_openapi(
        title="Sample API",
        version="1.0.0",
        description="Sample API",
        routes=app.routes,
    )
    app.openapi_schema = openapi_schema
    return app.openapi_schema


app.openapi = custom_openapi

instrumentator = Instrumentator().instrument(app)
instrumentator.expose(app, include_in_schema=False)

@app.get("/api/v1/health", description="API status check", tags=["Common"])
def check_health():
    return {
        "status": "OK"
    }

 

주목할 부분은 기본 측정항목으로 앱을 계측하고 측정항목을 노출하는 부분이다.

실제로 동작하는 소스를 열어보면 FastAPI의 middleware 레이어에 등록하여 요청수, 응답수등을 컨트롤하여 전처리와 후처리를 하는 부분을 볼 수 있다.

instrumentator = Instrumentator().instrument(app)
instrumentator.expose(app, include_in_schema=False)

3. FastAPI 웹 서버 기동

자 그럼 이제 웹 서버를 기동시켜보자.

기본은 8000포트이고 변경시는 config/prometheus/prometheus.yml 안의 port도 수정하셔야 합니다.
$ uvicorn main:app --host=0.0.0.0 --port=8000

4. FastAPI /metrics 확인

브라우저 또는 curl를 호출하여 http://localhost:8000/metrics 을 정상적으로 출력하고 있는지 확인한다.

...
http_requests_total{handler="/api/v1/health",method="GET",status="2xx"} 1.0
http_request_duration_seconds_bucket{handler="/api/v1/health",le="0.1",method="GET"} 1.0
...

 

 

✅ 동작 확인

Promethues 로그 확인

ts=2024-02-04T00:28:41.267Z caller=main.go:1282 level=info msg="Completed loading of configuration file" filename=/etc/prometheus/prometheus.yml totalDuration=43.533308ms db_storage=1.44µs remote_storage=1.888µs web_handler=504ns query_engine=1µs scrape=25.986125ms scrape_sd=200.677µs notify=1.567µs notify_sd=4.126µs rules=1.575µs tracing=16.302µs
ts=2024-02-04T00:28:41.267Z caller=main.go:1024 level=info msg="Server is ready to receive web requests."
ts=2024-02-04T00:28:41.268Z caller=manager.go:212 level=debug component="discovery manager scrape" msg="Discoverer channel closed" provider=static/0
ts=2024-02-04T00:28:41.268Z caller=manager.go:146 level=info component="rule manager" msg="Starting rule manager..."

FastAPI 로그 출력 확인

설정된 스크랩 주기 시간에 맞추어 다음과 같이 /metrics를 호출하여 스크랩을 시작한다.

INFO:     Started server process [1514]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO:     172.18.0.2:39004 - "GET /metrics HTTP/1.1" 200 OK
INFO:     172.18.0.2:39004 - "GET /metrics HTTP/1.1" 200 OK

 

❌ 오류

FastAPI 로그 출력 확인

Promethues 서버에서 host의 로그를 스크랩하지 못하는 경우이다.

$ docker logs -f <container-id>

ts=2024-02-04T00:28:51.143Z caller=scrape.go:1274 level=debug component="scrape manager" scrape_pool=sample target=http://host.docker.internal:8000/metrics msg="Scrape failed" err="Get \"http://host.docker.internal:8000/metrics\": dial tcp 20.100.0.101:8000: connect: connection refused"

 

다음과 같은 경우에는 docker 컨테이너 안의 /etc/hosts를 확인하여 host 도메인 설정이 잘 되어 있는지 확인한다. host.docker.internal 부분 확인하면 된다.

$ docker exec -it <container-id> sh  
/prometheus $ cat /etc/hosts

/prometheus $ cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
<HOST_IP>	host.docker.internal 
172.18.0.2	ca56b8cb6211
728x90
반응형