수많은 QL(Query Language) 중에 나는 PromQL, 다시 말해서 프로메테우스를 이용하는 방법에 대해서 알아보려고 한다.
**참고로 프로메테우스의 수집된 것이 저장되는 곳은 Local이나 Remote이다. (알아서 마운트 하면 된다.)
프로메테우스에 대한 기본적인 설명은
이 글에서 설명하겠다.
[분류 전체보기] - Prometheus, 프로메테우스 개념
뭐 기본적으로는 이해했다.
그런데 왜... 많고 많은 데이터들중 PromQL을 신경써주어야 하느냐..?
라는 것이 문제다.
그래서 여기서 PromQL 에서 무엇이 성능을 느리게 하는지
Query에 따른 비용, 어떻게해야 최적화할 수 있는지 알아보려고 한다.
우선 PromQL의 성능에 영향을 주는 요소는 뭐가 있을까??
1. 뽑아내려는 데이터 수
당연히 뽑아내려는 수가 많으면 찾아야 하니까 느려지는 것이다.
예를 들어 몇백만 시계열 데이터를 뽑아내려면 RAM이 무지막지 하게 필요하고, CPU도 무지막지하게 필요할 것이다.
이건 너무 당연했다.
그러므로 검색할 때 정확한 필터링으로 필요한 것만 뽑아내는 것이 중요하다.
2. Cardinality
이것은 위의 글에 나와있는데 레이블을 저장한다고 생각하면 된다.
tsdb에 저장된 고유한 시계열의 수다.
다시 말해서 레이블의 중복도의 정도라고 생각하면 된다.
High Cardinality => 중복이 덜 됨 => 고유한 요소가 많음 => 구별할 것이 많음
Low Cardinality => 중복이 더 됨 => 고유한 요소가 적음 => 구별할 것이 없음
수집하는 메트릭은 같아도 다른 종류의 데이터로 취급하기 위해 레이블을 넣는다.
이것의 Cardinality가 커지면 성능이 급격하게 떨어진다.
??? 뭔데.. 고유한 요소가 많으면 빨리 필터링 되니까 좋은 것 아니야..?
왜 High Cardinality가 안 좋은건데??
예를 들면 HTTP Method에 따라 메트릭을 구분했다고 해보자..?
GET, POST만 쓴다면 Cardinality는 2다.
PUT까지 쓴다면 Cardinality는 3이 된다.
하지만 이렇게 Cardinality를 계산하는 것은 1차원적이다.
우리는 HTTP Method 뿐만 아니라
여러가지 HTTP Path, 여러가지 장비들, 개발 환경들 여러가지가 쓰여진다는 것을 알고 있다.
게다가 히스토그램을 사용하는 경우 기본적으로 12의 Cardinality를 갖게 된다.
결국 Cardinality가 높아진다.
게다가 이것은 곱의 형식으로 커진다. 각각의 조합이 뽑히는 것이다.
예를 들어 HTTP 메서드 2개, HTTP path 7개, 5개의 시스템을 다루는 히스토그램이 있다면
(프로메테우스는 일반적으로 하나의 환경, 데이터 센터만 모니터링 한다.)
2 * 7 * 5 * 12 => 840 가지나 된다.
Path와 Method가 1개씩만 더 늘어나고 새로운 엔드포인트가 생기면
3 * 8* 6 * 12 => 1728 이다.
3 종류에 대해서 1가지씩 늘어났지만 결과적으로 840 => 1728.. 2배 이상이 되어버렸다.
솔직히 Cardinality에 대해선 나도 더 리서치가 필요하다고 생각한다.
이 글을 보고 더 자세히 이해할 수 있도록 해보자
https://www.robustperception.io/cardinality-is-key/
3. Active한 시계열 데이터
프로메테우스는 최근에 수집한 메트릭들을 RAM에 가지고 있다.
그렇기 때문에 최근의 데이터를 Select할 때는 RAM에서 뒤진다.
즉, RAM의 용량이 클수록 빨리 찾아진다.
여기서 Active 시계열은 곧 Chrun rate를 통해서 Cardinality와 밀접한 관련이 있다.
다시 말해서 프로메테우스는 RAM 사용량도 중요하다.
3. Churn rate
위에서 활성화된 시계열 데이터는 새로운 샘플링을 받는 것을 멈췄을 때, 비활성화가 된다.
다시 말해서 샘플링을 새롭게 시작하면 새로운 시계열 데이터가 활성화 상태가 되고
이전의 데이터는 비활성화가 된다는 말이다.
churn rate는 비활성화와 활성화의 관계를 말한다.
예를 들자면
pod_name이란 레이블이 있다고 하자.
하지만 파드의 이름은 뒤에 식별자가 붙기 때문에 쿠버네티스가 배포할 때마다 달라질 수 있다.
이전에 시계열 데이터가 새로운 시계열 데이터로 대체된다.
그 이전의 데이터가 새로운 데이터로 교체되는 비율에 대해서 churn rate라고 할 수 있다.
딱 봐도 Chrun rate가 높다는 것은 cardinality가 높다는 것과 같다.
(같은 것들이 아니라 새로운 것들이 생겨서 중복도가 낮아진다)
역시 성능이 낮아진다. 또한 OOM 에러가 나올 수도 있다.
프로메테우스에서 특정한 메트릭을 노출하는데
(prometheus_tsdb_head_series_created_total)
얘를 이용해서 churn rate를 알아볼 수 있다.
rate(prometheus_tsdb_head_series_created_total[5m])
프로메테우스 버전 v2.10에서는
scrape_series_added라는 메트릭이 있다.
이러한 쿼리를 쓴다면
sum(sum_over_time(scrape_series_added[5m])) by (job)
이것 또한 source에 대한 churn rate를 알 수 있다.
다시 말하자면 High Churn rate라는 것은 새로운 시계열 데이터가 생성되고 있다는 것을 의미한다.
이 역시 전체적으로 축적되는 데이터가 많아짐을 의미한다.
Active 시계열데이터의 수는 Sliding time range 에선 일정하게 유지된다.
=> 범위를 지정하면 그렇다는 이야기다.
시계열 데이터는 시간 범위동안 새 데이터 포인트를 수신할 때 활성으로 간주한다.
3. Ingestion rate
Ingestion 이란 초당 tstb에 들어가는 데이터의 양이다.
프로메테우스는 주기적으로 target에 대한 수집(scrape)를 진행한다.
각각의 타겟마다 메트릭을 노출시키고 수집된 메트릭은 각각의 시계열과 더해진다.
예를 들자면
http://demo.robustperception.io:9090/metrics
에서 964메트릭을 노출한다고 해보자.
어떻게 수집해볼까? 아래처럼 수집가능하다.
curl -s http://demo.robustperception.io:9090/metrics | grep -vc '#' 964
Ingestion rate는 어떤 식으로 계산되느냐??
scrape_samples_scaraped 메트릭을 이용해서 계산된다.
예를 들면
sum_over_time(scrape_samples_scraped[5m]) / 300
이것이 계산 방법과 같다. (300은 초로 나누는 것이다.)
꼭 저 메트릭을 이용해야만 하는 것은 아니고 다른 메트릭을 이용해도 된다.
- ingestion_rate = targets_count * metrics_per_target / scrape_interval
- ingestion_rate = active_time_series / scrape_interval
4. Scrape interval
역시 수집 주기도 중요하다.
Prometheus는 target에 대해서 주기적으로 수집하게 되는데
Default 값은 1분이다.
하지만 Override를 통해서 값을 바꿀 수 있다.
global->scrape_interval (Prometheus config 옵션에서 바꿀 수 있다.)
다만 target 마다 interval을 바꾸는 것은 추천하지 않는다고 한다.(https://www.robustperception.io/keep-it-simple-scrape_interval-id/)
당연히 수집주기가 짧아질수록 Higher Ingestion이다.
그렇게 되면 RAM을 더 많이 쓰게 된다.
5. Retention
프로메테우스는 stored data의 생명 주기를 정할 수 있는 flag를 제공한다.
--storage.tsdb.retention.time 을 쓰면 된다.
데이터가 수명이 다하면 삭제된다.
초기 값은 15일로 되어있으며 데이터는 전부 Disk에 저장되어 있으며 그것은 retention에 따라 결정된다.
예를 들어 retention이 높다는 것은 디스크에 데이터가 많다는 것을 의미한다.
프로메테우스에서 가장 수명을 낮게 지원하는 retention은 2시간이다.
그래서 2시간 밖에 디스크에 유지못한다면 Remote Storage를 쓰면 좋다.
즉, 로컬에 있는 모든 데이터들을 리모트 저장소에 복사해 넣는 것이다.
다시 말해서 retention 이 로컬에서는 적게 유지되어도 된다는 말이다.
리모트에서 어차피 복사되어 있으니까!!
Prometheus API로 충분히 remote storage에 대한 접근이 가능하다.
alert이다 recording 가이드 라인에 따라 retention을 정하도록 하는 것이 좋다.
6. Relabeling
프로메테우스는 재레이블링을 지원한다.
제레이블링이란 metric의 label을 조작하는 것이다.
예를 들면 target과 데이터에 대한 scrape를 필터링한다.
?? 필터링..? 걸러낸다는 것인가?
맞다. 꽤나 유용한 작업이다. 이런 작업들은 쿠버네티스, EC2, GCE 서비스 discovery에 많이 쓰이는 작업이다.
감이 안온다고..? Relabeling 이라는 말이 안어울린다고?? 말할 수 있다.
이것에 대해 더 쉽게 설명하기 위해선
내가 더 리서치를 해봐야 할 것 같다.
나중에 업데이트를 하겠다.
7. Remote Storage
프로메테우스는 기본적으로는 로컬 tsdb에 대해서 작동한다.
하지만 앞서 말했듯이 configuration에서 remote에도 데이터를 복사해 넣을 수 있다.
즉, 로컬 저장소의 Retention이 2시간 수명이더라도 나중에 Remote에서 찾을 수 있다는 말과 같다.
Remote Storage는 정말 유용한데 몇가지 측면을 보자
- 여러 프로메테우스의 인스턴스로부터 얻은 데이터들을 한 곳에 마운트시킬 수 있다.
=> 인스턴스는 여러가지나 한 번에 모아야할 데이터들의 경우 한 번에 모을 수 있다.
global query view라고 부른다.
- 장기적으로 저장될 필요가 있는 데이터는 Remote에 저장한다.
=> 그럼으로써 로컬은 낮은 Retention을 유지할 수 있고 로컬에서 디스크 사용량이 낮아질 수 있다.
-스케일링에 관한 이슈를 분리할 수 있다.
=> 자동으로 여러 노드로 스케일링 될 수 없는 경우를 해결한다.
특정한 원격 저장소 solution의 경우(VictoriaMetrics => 예를 든 것이다.) vertically 또는 Horizontally Scale을 지원한다.
Vertically는 하나에 대해서 더 좋은 하나를 만드는 것이고
Horizontally는 하나에 대해서 여러 개를 만드는 것으로 이해하면 편하다.
- K8s 환경에서 프로메테우스를 임시 볼륨과 함께 작업할 때 도움이 된다.
=> 임시 볼륨에서는 파드가 재시작될 경우 사라져버린다. 다만 Remote에 마운트 되어 있다면 파드가 재시작하더라도 데이터가 날아갈 일이 없다.
결과적으로 프로메테우스의 성능에 대한 이슈가 여러가지가 있는 것을 알아보았고
우리의 시스템에선 어떤 것을 고려해야 하는지 비교해보자.
PromQL은 강력한 도구이다.
다만 우리가 어떻게 저장했으며, 어떤 식으로 구성했고, 얼만큼의 데이터를 어떤 기준으로 가져올 지에 대해서 잘 생각해보아야 한다.
우리는 수많은 데이터에서 Insight를 발견해야 한다.
잘해서 멋진 대시보드로 모니터링 해보고, Alert도 해보자!
참고링크
https://valyala.medium.com/how-to-optimize-promql-and-metricsql-queries-85a1b75bf986
'DevOps' 카테고리의 다른 글
PlantUML, UML 직접 그리지 말고 코드로 그리자 (0) | 2022.11.12 |
---|---|
GSLB, 트래픽이 높을 때 로드밸런싱하기 (0) | 2022.11.12 |
CMake 튜토리얼 - 2 (2) | 2022.09.20 |
CMake 튜토리얼 - 1 (0) | 2022.09.16 |
Github, Github Action 을 이용하여 CI 구성하기 (0) | 2022.09.16 |