차원별 동적 임계값 예제

차원별 동적 임계값 예제 (Example of dynamic thresholds per dimension)

Grafana Alerting에서 각 알림 규칙은 조건 표현식(condition expression)을 하나만 지원해요. 대부분의 알림은 latency > 3serror_rate > 5% 같은 고정 수치 임계값을 쓰니 충분하지만, 알림 구성이 커지면 서로 다른 대상이 서로 다른 임계값을 요구할 수 있어요. 이 예제는 규칙을 중복하지 않고 같은 조건을 유지하면서 대상마다 다른 임계값을 할당하는 방법을 다차원 알림과 Math 표현식으로 보여줘요.

출처: 문서

본문

예제 개요

여러 API 서비스의 지연 시간을 모니터링한다고 해요. 처음에는 95번째 백분위 지연 시간(p95_api_latency)이 3초를 초과하면 알림이 오도록 단일 정적 임계값을 씁니다:

p95_api_latency > 3

하지만 일부 서비스는 더 엄격한 임계값이 필요해요. 예를 들어 결제 API는 1.5초 아래를 유지해야 하고, 백그라운드 작업은 최대 5초까지 견딜 수 있어요. 서비스별 임계값이 이렇게 달라져요:

  • p95_api_latency{service="checkout-api"} : 1.5s 아래 유지
  • p95_api_latency{service="auth-api"} : 역시 엄격, 1.5s
  • p95_api_latency{service="catalog-api"} : 덜 중요, 3s
  • p95_api_latency{service="async-tasks"} : 백그라운드 작업, 최대 5s

서비스마다 규칙을 하나씩 만드는 건 관리가 어려우니 피하고 싶어요. Grafana Alerting에서는 이런 비슷한 컴포넌트 여러 개를 모니터링하는 하나의 알림 규칙을 정의할 수 있어요 — 이를 다차원 알림이라 해요. 하지만 Grafana는 규칙당 조건을 하나만 지원해요:

One alert rule
├─ One condition ( e.g., $A > 3)
│  └─ Applies to all returned series in $A
│     ├─ {service="checkout-api"}
│     ├─ {service="auth-api"}
│     ├─ {service="catalog-api"}
│     └─ {service="async-tasks"}

서비스별 임계값을 평가하려면 반환된 각 시리즈에 대해 서로 다른 임계값이 필요해요.

Math 표현식으로 동적 임계값 만들기

두 개의 쿼리에 Math 표현식을 적용해 동적 알림 조건을 만들 수 있어요.

  • $A : 쿼리 결과(예: p95_api_latency)
  • $B : 서비스별 임계값(CSV 데이터나 다른 쿼리에서)
  • $A > $B : 알림 조건을 정의하는 Math 표현식

Grafana는 시리즈별로 Math 표현식을 평가해요. $A$B의 시리즈를 공유 라벨을 기준으로 조인한 뒤 표현식을 적용해요. 산술 연산 예제:

  • $A{host="web01"} 30, {host="web02"} 20 반환
  • $B{host="web01"} 10, {host="web02"} 0 반환
  • $A + $B{host="web01"} 40, {host="web02"} 20 반환

실제로는 임계값 입력을 알림 쿼리가 반환하는 라벨 집합과 정렬해야 해요. 다음 표는 앞선 예제에서 서비스별 임계값이 어떻게 평가되는지 보여줘요:

$A: p95 지연 쿼리 $B: 임계값 $C: $A>$B 상태
{service="checkout-api"} 3 {service="checkout-api"} 1.5 {service="checkout-api"} 1 Firing
{service="auth-api"} 1 {service="auth-api"} 1.5 {service="auth-api"} 0 Normal
{service="catalog-api"} 2 {service="catalog-api"} 3 {service="catalog-api"} 0 Normal
{service="sync-work"} 3 {service="sync-work"} 5 {service="sync-work"} 0 Normal

이 예제에서 $Ap95_api_latency 쿼리에서, $B$A의 각 시리즈에 대한 임계값으로 수동 정의돼요. 알림 조건은 라벨 일치로 시리즈를 조인하는 Math 관계 연산자(>, <, >=, <=, ==, !=)로 $A>$B를 비교하고, 조건이 참인 곳에서 발화 상태를 설정해요.

Math 표현식은 $A의 각 시리즈가 $B의 시리즈 정확히 하나와 일치할 수 있을 때 작동해요. 한 쿼리의 시리즈가 다른 쿼리의 어떤 시리즈와도 일치하지 않으면 결과에서 제외되고 경고 메시지가 표시돼요:

Caution 1 items dropped from union(s) : ["$A > $B": ($B: {service=payment-api})]

양 시리즈의 라벨이 동일할 필요는 없어요. 라벨이 다른 쪽의 부분집합이면 조인할 수 있어요. 예를 들어 $A{host="web01", job="event"} 30을, $B{host="web01"} 10을 반환하면 $A + $B{host="web01", job="event"} 40을 반환해요.

TestData로 시도해 보기

TestData 데이터 소스로 이 예제를 재현할 수 있어요:

  • Connections 메뉴로 TestData 데이터 소스를 추가해요.
  • Alerting → Alert rules로 이동해 알림 규칙을 만들어요.
  • 각 서비스의 지연 시간을 반환하는 쿼리($A)를 시뮬레이션해요. TestData에서 Scenario: Random Walk, Alias: latency, Labels: service=api-$seriesIndex, Series count: 4, Start value: 1, Min: 1, Max: 4로 설정해요. ($seriesIndex로 api-0, api-1 식의 고유 service 라벨을 부여해요.)
  • 정적 데이터로 서비스별 임계값을 정의해요. 새 쿼리($B)를 추가하고 TestData를 선택한 뒤 Scenario에서 CSV Content를 선택해 이 CSV를 붙여넣어요:
service,value
api-0,1.5
api-1,1.5
api-2,3
api-3,5

service 열은 $A의 라벨과 일치해야 해요. value 열은 알림 비교에 쓰는 수치 값이에요.

  • 새 Reduce 표현식($C)을 추가해요. Type: Reduce, Input: A, Function: Mean, Name: C. 각 서비스의 평균 지연 시간을 계산해요.
  • Math 표현식을 추가해요. Type: Math, Expression: $C > $B, 이 표현식을 알림 조건으로 설정해요. 어떤 서비스든 평균 지연 시간($C)이 $B의 임계값을 초과하면 발화해요.

다른 사용 사례

이 예제는 다차원 알림과 Math 표현식으로 시리즈별 서로 다른 임계값을 가진 단일 알림 규칙을 만드는 법을 보여줬어요. 이 접근법은 서로 다른 안정성 목표를 가진 비슷한 컴포넌트를 모니터링할 때 잘 확장돼요. 두 쿼리의 시리즈를 정렬하면 규칙 중복 없이 라벨 집합당 하나의 값인 동적 임계값을 적용할 수 있어요. 이 예제는 임계값 정의에 정적 CSV를 쓰지만, 같은 기법은 다른 시나리오에서도 적용 가능해요:

  • 쿼리나 레코딩 규칙의 동적 임계값: 실시간 쿼리나 커스텀 레코딩 규칙에서 임계값을 가져와요.
  • 여러 조건 결합: 지연 시간, 오류율, 트래픽 양 같은 여러 조건을 결합해 더 고급 임계값 로직을 만들 수 있어요.

예를 들어 트래픽에 따라 조정되는 지연 임계값을 설정하는 PromQL 표현식을 정의할 수 있어요 — 높은 부하 기간에 더 높은 응답 시간을 허용하는 방식이에요:

(
  // Fires when p95 latency > 2s during usual traffic (≤ 1000 req/s)
  service:latency:p95 > 2 and service:request_rate:rate1m <= 1000
)
or
(
  // Fires when p95 latency > 4s during high traffic (> 1000 req/s)
  service:latency:p95 > 4 and service:request_rate:rate1m > 1000
)

더 알아보기 (Learn more)