recording rule 이란

 

자주 필요한 표현식이나 계산 비용이 큰 표현식을 미리 계산해서, 그 결과를 별도 시계열 셋으로 저장해 둘 수 있는 기능이다. 

즉 성능과 재사용성을 높이기 위해서 사용할 수 있다.

 

예를 들어보자. 

 

원하는 시계열 데이터를 만들기 위해서 5개의 시계열 데이터가 들어가고, 하나의 프롬 쿼리당 1의 리소스가 든다고 가정해 보자.

 

-> 데이터를 요청할 때마다 5의 리소스가 들어가게 된다. 

 

반면에 recording rule을 사용하면, 처음에 5의 리소스가 들어가게 되고, 해당 값을 저장하는 시계열 데이터가 만들어진다. 

-> 데이터를 요청할 때마다 1의 리소스가 들어가게 된다.

 

여기서 프롬 쿼리가 복잡하다면 더 많은 차이가 나타나게 된다. 물론 별도의 시계열 데이터로 저장해서, 저장 공간이 더 필요하므로 남용해서는 안 된다.

 

recording rule 사용

 

먼저 recording rule을 명시하는 rule.yml을 작성해야 한다. java 애플리케이션을 기준으로 하므로 gc와 관련된 식을 작성해 보자.

 

최근 5분 동안 발생한 GC 이벤트의 평균 중단 시간을 계산하는 프롬 쿼리를 예로 들어보겠다.

 

groups:
  - name: java_gc_duration_seconds
    rules:
      - record: job:jvm_gc_duration_seconds:rate5m
        expr: rate(jvm_gc_pause_seconds_sum[5m]) / rate(jvm_gc_pause_seconds_count[5m])

 

name: 룰의 이름으로 유니크해야 한다. 

record: 집계한 시계열 데이터의 별칭으로 사용

expr: 프롬 쿼리

 

여기서 record에는 컨벤션이 존재한다.

 

level:metric:operations

 

level: 메트릭의 범위, 중요도를 의미함 (ex instance, job, service )

metric: 관찰하고 있는 대상을 의미함 (ex jvm_gc_pause_seconds_sum)

operation: 해당 메트릭의 적용된 연산의 종류 (ex rate5 m)

 

컨벤션을 지키면서, 룰을 추가해야 많아졌을 때 관리하기가 쉬우므로 웬만하면 따를 것을 추천한다.

 

prometheus.yaml config 값추가

rule_files:
  - "rules.yml"

 

이제 컨테이너를 실행해 보자. 

 

docker run \
-p 9090:9090 \
--name prometheus \
-d \
-v $(pwd)/web.yml:/etc/prometheus/web.yml \
-v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \
-v $(pwd)/rules.yml:/etc/prometheus/rules.yml \
prom/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--web.config.file=/etc/prometheus/web.yml

 

Rules 탭에서 정상적으로 조회되는 것을 볼 수 있다.

 

 

recording rule 권장하지 않는 경우

 

recording rule을 사용하면 별도의 시계열 데이터를 저장하므로, 저장해야 하는 데이터가 늘어나게 된다. 즉 저장 공간을 낭비하지 않기 위해서는 사용을 권장하지 않는 경우를 알아보자.

 

단순 쿼리

 

recording rule 같은 경우 복잡한 쿼리와 같이 한 번 조회하는데 많은 리소스가 들어갈 수 있는 것에 사용하는 게 적합하다. 하지만 단순한 쿼리의 경우 리소스 자체가 낮으므로, 오히려 별도의 시계열 데이터를 만듦으로써 저장 공간을 차지하는 것이 리소스를 더 많이 사용한다고 할 수 있다. 즉 단순한 쿼리에는 권장하지 않는다.

 

낮은 쿼리 빈도

 

recording rule 또한 인터벌을 지정할 수 있지만, 쿼리 빈도 자체가 낮을 경우 권장하지 않는다. 한 번 보고 다시 볼 데이터가 아닌 경우가 많기 때문에 저장 공간을 낭비할 필요가 없다.

 

동적 쿼리

 

사용자의 입력이나 특정 조건에 따라서 쿼리의 구성이 바뀌는 경우에는 권장하지 않는다. 즉 label을 가장 먼저 떠올릴 수 있다.

 

rate(jvm_gc_pause_seconds_sum {instance = "ab"}[5m]) / rate(jvm_gc_pause_seconds_count {instance = "ab"}[5m])

 

이 경우 instance 레이블이 ab인 것만 조회하게 되는데, 또 다른 별도의 레이블을 보고 싶으면 모두 일일이 추가해야 한다. 이 경우 오히려 recording rule로 생성하는 리소스가 더 많이 들어갈 수 있다.

 

따라서 recording rule단에서 레이블을 처리하는 것보다 집계를 한 상태에서 레이블로 필터링하는 것이 더 좋다.

 

예시로 

record: instance:jvm_gc_duration_seconds:rate5 m

expr: sum(rate(jvm_gc_pause_seconds_sum [5m])) by (instance) / sum(rate(jvm_gc_pause_seconds_count [5m])) by (instance)

 

by를 써서 집계한 후에 instance:jvm_gc_duration_seconds:rate5m{instance="ab"}로 하는 게 recording rule 내에서 동적 쿼리를 사용하지 않아 적합할 수 있다.