Prodmethues Metrics.. 개발을 하시거나 Devops 업무를 해보셨던분들이라면 한번쯤 들어봤을 단어이다.
아래 그림은 Prometheus 에서 제공해주는 공식 이름이다. 로직을 가장 잘 표현해주는 그림인것 같아서 가지고 왔다.
Promethues가 뭔가요?
Prometheus는 오픈소스 모니터링 솔루션으로, 모니터링 분야에서 가장 가장 그리고 넓게 사용되는 시스템이다.
CPU, Mem, DB Connection, HTTP request count 등 모니터링이 필요한 부분을 Metrics으로 만들어서 모니터링한다.
구성은 Promethues Server + Metrics 정보를 노출한 Export Node로 구성된다.
- Server : 실제 Metrics을 수집하는 서버이고, 일반적으로 Prometheus를 뜻한다.
- Export Node : Metrics을 노출하고 있는 애플리케이션이다.
Prometheus가 대표적으로 아래 좋은점이 있다.
- Metrics을 Pull로 수집을 한다.
- 대부분의 모니터링 시스템은 Push 방식을 채택한다. 하지만 이는 부하가 많은 환경에서는 부적절하다.
- 어플리케이션에 무리가 없더록 Pull 방식으로 일정 주기(Default 15s)마다 Metrics을 수집한다.
- Prometheus 생태계가 잘 되어 있다. <- 가장 좋은 장점이라고 생각한다ㅎㅎ
- 오픈소스로 구성되어 있는 만큼, 커뮤니티와 생태계가 잘 되어 있다.
- 잘 사용하지 못하더라도, Example이 많고 K8s에서는 사용하기도 매우 편하다.
- 어플리케이션에서 Promethues Export만 하고, K8s Deployment Annotation만 추가하면 된다.
하지만, 다른 솔루션과 마찬가지로 장점만 있는것은 아니고 단점도 존재한다.
- Sacle-out이 안된다.
- 물론 Docs를 찾아보면 다수의 Host를 만들고, 연결-연결하는 구조로 억지로 사용은 가능하나 구조가 복잡하다.
- 최근에는 Tanos 등 다른 OpenSource 솔루션과 같이 사용하면 HA를 제공해주는것도 있다고 하나 원칙적으로는 어렵다.
- 이는 수집한 Metrics을 별도의 데이터베이스가 아니라 메모리 또는 Local Storage에 저장하기 때문이다.
- APM과 같이 모든 로그를 추적하여 상세한 상태를 확인하는것은 어렵다.
- Prometheus는 기본적으로 일정한 주기마다 Metrics을 수집한다. 그렇기에 추세를 확인하는 것은 가능하다.
- 하지만, 성능 이슈 또는 기타 다른 문제가 발생했을 때 Prometheus로만 원인 파악하기는 어렵다.
Promethues 어떻게 사용하나요?
Prometheus는 커뮤니티와 생태계가 잘 되어 있기 떄문에 사용하기 매우 편한 솔루션이다. SDK도 잘 되어있다.
Promethues Metrics Export 하는 방법
Prometheus에서는 수집하는 수집 Server 와 Metrics을 노출하는 Export 서버로 구성되어 있다.
그래서 애플리케이션에서 Prometheus를 Export 해줘야 한다. 그리게 Echo에서는 한줄만 쓰면 된다.
func InitRoute(server *echo.Echo) {
server.GET("/healthz", controllers.Healthcheck)
initv1(server, NewControllerFactory())
// Echo 에서 metrics 노출하기 위함
server.GET("/metrics", echo.WrapHandler(promhttp.Handler()))
}
바로 이해되는것처럼 /metrics 경로로 Prometheus를 Export 하겠다는 코드이다.
코드를 삽입하고 curl로 요청하면 기본적으로 Echo에서 Metrics을 Export 하고 있다.
Prometheus Metrics 타입 종류
내가 원하는 것은 특정 함수를 호출했을 때, 몇번 호출 됬는지 알고싶은것이다.
물론 Std log를 수집하고 확인하는 것도 방법이다. 하지만 Log에는 수집에 불필요한 정보가 많았다.
그리고 Std log는 신뢰할 수 없는 데이터라고 생각했기 때문에 Metrics으로 만들어서 모니터링 하고자 했다.
Promethues에서 지원해주는 Metrics은 크게 Counter / Gauge / Summary / Histogram 4가지가 있다.
- Counter : API 요청 또는 함수 발생 횟수를 추적하는게 사용되며 0부터 시작해서 오직 증가 값만 가능하다.
- Counter 타입에 Rate 함수를 적용하면 Gauge 타입으로 변환이 되면 일반적으로 _total 이름으로 끝나는 규칙이 있다.
- Gauge : 증가 또는 감소가 가능한 값을 측정하는데 사용된다. inc(), dec(), set() 이 가능하다.
- Counter가 회수에 초점이 맞춰졌다면, Gauge는 현재 값에 중심을 두고 관찰한다.
ex) API 연결중인 Connection counter, API 호출 시간 등..
- Counter가 회수에 초점이 맞춰졌다면, Gauge는 현재 값에 중심을 두고 관찰한다.
- Summary : BE의 지연시간이나 처리시간을 측정할 때 사용하며 연속된 값을 다룬다.
- Histogram : 연속적인 값의 분포를 측정할 때 사용한다.
- Summary와 유사하지만, 그룹을 나누고 해당 그룹 안의 데이터 집계를 하고 분포를 나타내는것이 차이점이다.
지금 필요한것은 특정 함수가 몇번 호출됬는지 관측 가능한 Metrics을 만드는것이다.
그리고 위 Metrics 4가지 속성을 참조해보면 Counter로 만드는것이 가장 적합하다.
Go에서 Counter Metrics 구현 방법
만약, Metric 이 사전에 다 정해져있다면 구현하기가 간단하다.
아래 처럼 할 필요가 없어 promethues.NewCouneter로 미리 만들고 필요에 따라 Inc() 하면 된다.
하지만 내가 필요한것은 Metrics 이름이 동적으로 변하는 값이다. 그렇기에 Metrics 존재 유/무를 먼저 검사해야 한다.
// 동적 Metrics 존재 여부를 확인하기 위한 Map을 만든다.
// map을 초기화하기 위해 make를 사용한다. 그렇기 않으면 null point 이슈가 발생할 수 있다.
var (
metricMap = make(map[string]bool)
metricMapCount = make(map[string]prometheus.Counter)
)
// Metrics이 존재하는지 확인한 다음에, 존재한다면 Inc() 하며,
// 존재하지 않는다면 Metrics를 만든 다음에 Inc() 한다.
func generateCounterMetrics(name string) error {
if exist := metricMap[name]; exist {
metricMapCount[name].Inc()
return nil
}
newMetrics := prometheus.NewCounter(
prometheus.CounterOpts{
Name: name,
},
)
if err := prometheus.Register(newMetrics); err != nil {
loggers.Loggers.Error("cloud not register metrics: %s", name)
return errors.New("cloud not register metrics")
}
metricMap[name] = true
metricMapCount[name] = newMetrics
metricMapCount[name].Inc()
return nil
}
Services Layer에서는 비즈니스 로직을 다 끝낸 다음에 위 generateMetrics를 호출하면 된다.
- 위에서 말한것과 같이 Metrics 이름이 동적이기 때문에 metricsName을 사전에 정의해줬다.
metricName := fmt.Sprintf("check_file_user_%s_total", name)
// ---
// 비즈니스 로직 실행 후 메트릭 증가
// ---
err := generateCounterMetrics(metricName)
if err != nil {
return err
}
Prometheus Metrics 지표 어떻게 확인하나요?
확인하는 방법은 매우 간단하다. 앞서 metrics export로 지정한 경로를 호출하면 된다.
그럼 아래처럼 내가 생성한 Metrics뿐 아니라 기본적으로 생성되는 Metrics 확인도 가능하다.
결론
위 코드는 동적으로 Metrics 이름이 다를 때 사용할 수 있는 코드이다. 필요에 따라 다르게 구현하면 된다.
최근 Go 기반의 배포시스템을 구현하면서, 배포 성공/실패에 대한 Metrics이 필요해서 알아보게됬다.
Metrics이 있으면 모니터링하기도 편하고, 필요에 따라서는 Slack 알람을 받아서 빠르게 대응할 수도 있다.
지금은 호출건수만 필요하기 때문에 Counter에 대해서만 진행했으나,
Gauge 등 다른 타입에 대한 Metrics에 대해서 알아보는것도 좋을것 같다.
끝!!
'개발 이모저모 > Golang' 카테고리의 다른 글
[go] doka, Sts Token Expire/Go routine 문제 해결 (1) | 2023.12.23 |
---|---|
[go] 내가 만든 kafka-connector to kinesis, 통칭 doka-connector (0) | 2023.12.21 |
[go] Golang 개발을 시작하자! (0) | 2023.11.26 |