Alerts 동작 방식
이 페이지에서는 Wave Alerts 시스템의 아키텍처, 평가 파이프라인, 전송 메커니즘을 기술적으로 상세히 다룹니다.
아키텍처 개요
데이터 모델
Alert 채널
Alert 채널은 다음과 같은 스키마로 저장됩니다.
struct AlertChannel {
id: String, // UUID v7
name: String, // Human-readable name
alert_channel_type: AlertChannelType, // http | slack_webhook | slack_web_api
metadata_json: AlertChannelData, // Type-specific configuration
created_at: i64, // Unix timestamp
updated_at: i64, // Unix timestamp
deleted_at: Option<i64>, // Soft-delete timestamp
}AlertChannelData의 종류:
// HTTP Webhook
struct AlertChannelHttpData {
url: String,
method: Option<HttpMethod>, // POST | PATCH | PUT | DELETE
headers: Option<HashMap<String, String>>,
proxy: Option<String>,
}
// Slack Webhook
struct AlertChannelSlackWebhookData {
webhook_url: String,
proxy: Option<String>,
}
// Slack Web API
struct AlertChannelSlackWebApiData {
token: String, // Bot token (xoxb-)
channel: String, // Channel ID or name
proxy: Option<String>,
}Alert 규칙
Alert 규칙은 다음과 같은 스키마로 저장됩니다.
struct Alert {
id: String, // UUID v7
title: String, // Human-readable title
event_type: AlertEventType, // deployment_workload_metrics | etc
event_targets: EventTargets, // None | All | Specific
event_rule_expression: String, // JavaScript expression
event_rule_check_interval_min: i32, // Evaluation frequency
alert_messages_json: Vec<AlertMessage>,// Messages to send
created_at: i64, // Unix timestamp
updated_at: i64, // Unix timestamp
deleted_at: Option<i64>, // Soft-delete timestamp
}EventTargets의 종류:
enum EventTargets {
None, // Disabled
All {
resource_type: ResourceType // deployment
},
Specific(Vec<Resource>) // Targeted resources
}
struct Resource {
resource_type: ResourceType, // deployment
namespace: Option<String>, // None = all namespaces
name: Option<String>, // None = all names
}AlertMessage:
struct AlertMessage {
alert_channel_id: String, // Reference to AlertChannel.id
message: String, // Template with ${variable} syntax
}Alert 로그
Alert가 실행될 때마다 로그가 기록됩니다.
struct AlertLog {
id: String, // UUID v7
alert_log_group_id: String, // Groups logs from same evaluation
alert_channel_id: String, // Which channel was used
alert_id: String, // Which alert fired
alert_title: String, // Alert title (denormalized)
response_json: String, // HTTP response body
is_error: bool, // Success/failure flag
reason: String, // Error details
created_at: i64, // Unix timestamp
}로그 보관 기간: 30일 (설정 가능)
이벤트 유형과 스키마
1. Deployment 워크로드 메트릭
이벤트 유형: deployment_workload_metrics
설명: 특정 시간 구간 동안 수집한 CPU 및 메모리 사용률 집계 지표입니다.
사용 가능한 필드:
| 필드 | 타입 | 설명 | 사용 컨텍스트 |
|---|---|---|---|
evaluation_period_minutes | number | 메트릭을 수집한 기간 | 규칙 표현식 |
cpu_utilization_arr | number[] | CPU 사용률(%) 배열 | 규칙 표현식 |
memory_utilization_arr | number[] | 메모리 사용률(%) 배열 | 규칙 표현식 |
namespace | string | 리소스 namespace | 메시지 템플릿 |
workload_name | string | 워크로드 이름 | 메시지 템플릿 |
alert_title | string | Alert 규칙 제목 | 메시지 템플릿 |
alert_time | string | 트리거 시각 (ISO 8601) | 메시지 템플릿 |
사용 가능한 함수:
max(array)- 배열의 최댓값min(array)- 배열의 최솟값avg(array)- 배열의 평균값sum(array)- 배열 값의 합
규칙 표현식 예시:
evaluation_period_minutes >= 5 &&
(max(cpu_utilization_arr) >= 80 || avg(memory_utilization_arr) >= 80)메시지 템플릿 예시:
🔴 ${alert_title}
Workload: ${namespace}/${workload_name}
CPU Usage: ${max(cpu_utilization_arr)}%
Memory Usage: ${avg(memory_utilization_arr)}%
Evaluation Period: ${evaluation_period_minutes} minutes
Time: ${alert_time}기본 설정:
- 확인 주기: 1분
- 기본 대상: 모든 deployment
- 기본 규칙:
evaluation_period_minutes >= 5 && (max(cpu_utilization_arr) >= 80 || avg(memory_utilization_arr) >= 80)
2. Deployment 스케줄링 단계
이벤트 유형: deployment_scheduling_phase
설명: deployment 라이프사이클의 START/END 이벤트를 모니터링합니다.
사용 가능한 필드:
| 필드 | 타입 | 설명 | 사용 컨텍스트 |
|---|---|---|---|
phase | string | "START" 또는 "END" | 규칙 표현식, 메시지 템플릿 |
deployment_count | number | 해당 phase의 deployment 수 | 규칙 표현식, 메시지 템플릿 |
scheduling_title | string | 스케줄링 설정의 제목 | 메시지 템플릿 |
occurred_at | number | phase가 발생한 시점의 Unix timestamp | 메시지 템플릿 |
alert_title | string | Alert 규칙 제목 | 메시지 템플릿 |
alert_time | number | Alert가 발생한 시점의 Unix timestamp | 메시지 템플릿 |
규칙 표현식 예시:
phase == "START" || phase == "END"메시지 템플릿 예시:
📦 Deployment ${phase == "START" ? "Started" : "Ended"}
${scheduling_title}: ${deployment_count} deployment(s) ${phase == "START" ? "started" : "ended"}
Time: ${alert_time}기본 설정:
- 확인 주기: 1분
- 기본 대상: 없음 (직접 설정 필요)
- 기본 규칙:
phase == "START" || phase == "END"
3. Autopilot 로그 누락
이벤트 유형: autopilot_logs_missing
설명: Autopilot 로그가 일정 시간 이상 수신되지 않을 때 감지합니다.
사용 가능한 필드:
| 필드 | 타입 | 설명 | 사용 컨텍스트 |
|---|---|---|---|
missing_duration_minutes | number | 마지막 로그 수신 이후 경과 시간(분) | 규칙 표현식, 메시지 템플릿 |
error_duration_minutes | number | Autopilot 작업이 마지막으로 성공한 이후 경과 시간(분) | 규칙 표현식, 메시지 템플릿 |
namespace | string | 리소스 namespace | 메시지 템플릿 |
workload_name | string | 워크로드 이름 | 메시지 템플릿 |
alert_title | string | Alert 규칙 제목 | 메시지 템플릿 |
alert_time | number | Alert가 발생한 시점의 Unix timestamp | 메시지 템플릿 |
규칙 표현식 예시:
missing_duration_minutes >= 3 && error_duration_minutes >= 1메시지 템플릿 예시:
⚠️ Autopilot Logs Missing
Workload: ${namespace}/${workload_name}
Missing for: ${missing_duration_minutes} minutes
Action: Check Autopilot pod health
Time: ${alert_time}기본 설정:
- 확인 주기: 1분
- 기본 대상: 모든 deployment
- 기본 규칙:
missing_duration_minutes >= 3
평가 파이프라인
Alert 평가 파이프라인은 메트릭 수집부터 알림 전송까지 다섯 단계를 거쳐 이벤트를 처리합니다.
요청 흐름
메트릭 수집과 이벤트 생성
메트릭 수집기는 여러 소스에서 데이터를 가져옵니다.
- Kubernetes API: Pod 메트릭, deployment 상태
- Prometheus: CPU, 메모리 사용률
- Autopilot 로그: 로그 timestamp, 갭 감지
이벤트는 세 가지 유형으로 집계됩니다.
deployment_workload_metrics: 평가 기간(예: 최근 5분) 동안 집계deployment_scheduling_phase: 즉시 발생하는 START/END 이벤트autopilot_logs_missing: 지속 시간을 계산하는 갭 감지
활성 Alert 로드
deleted_at IS NULL인 Alert를 데이터베이스에서 조회해 평가가 필요한 모든 활성 Alert 설정을 가져옵니다.
이벤트 유형별 필터링
alert.event_type과 event.event_type을 비교해 현재 이벤트와 관련 있는 Alert만 처리합니다.
대상별 필터링
이벤트 리소스가 Alert 대상과 일치하는지 확인합니다.
EventTargets::None: 평가 건너뜀 (Alert 비활성화)EventTargets::All: 해당 유형의 모든 리소스와 일치EventTargets::Specific: 목록에 지정된 리소스만 일치 (namespace/name 와일드카드 지원)
평가 주기 확인
중복 Alert를 막기 위해 마지막 실행이 event_rule_check_interval_min 이내면 평가를 건너뜁니다.
JavaScript 컨텍스트 준비
이벤트 필드(예: cpu_utilization_arr, namespace, workload_name)로 JavaScript 평가 컨텍스트를 구성합니다.
규칙 표현식 실행
내장 JavaScript 엔진으로 event_rule_expression을 실행합니다.
- 표현식은 반드시 boolean을 반환해야 합니다 (
true= 트리거,false= 건너뜀) - 구문 오류가 있으면 평가가 실패합니다 (오류로 로깅됨)
- 평가당 100ms 타임아웃
- 메모리 제한: 평가당 10MB
JavaScript 엔진: 샌드박스 환경에서 실행되는 내장 JavaScript 런타임(QuickJS 또는 V8)을 사용합니다. 파일시스템, 네트워크, 시스템 API에는 접근할 수 없습니다.
표현식 결과 검증
결과가 boolean인지 확인하고, 필요하면 타입 강제 변환을 처리합니다.
Alert 채널 로드
alert_messages_json에 참조된 채널 설정을 가져옵니다.
메시지 템플릿 렌더링
각 메시지마다 이벤트 컨텍스트를 사용해 변수를 치환합니다.
Template: "CPU: ${max(cpu_utilization_arr)}%"
Context: { cpu_utilization_arr: [70, 75, 82, 88] }
Result: "CPU: 88%"템플릿 문법:
${variable}- 단순 변수 치환${function(array)}- 함수 호출 (max, avg, min, sum)${condition ? 'yes' : 'no'}- 삼항 연산자 (제한적으로 지원)
템플릿 함수 적용
배열 값에 내장 함수(max, avg, min, sum)를 실행해 집계 지표를 계산합니다.
템플릿 출력 검증
모든 변수가 정상적으로 치환됐는지 확인합니다. 변수가 누락되면 렌더링 오류가 발생하고 Alert가 전송되지 않습니다.
채널 설정 조회
alert_channel_id로 데이터베이스에서 채널을 조회해 엔드포인트 정보(URL, 인증, proxy 설정)를 가져옵니다.
HTTP 요청 구성
채널 유형(HTTP webhook, Slack webhook, Slack Web API)에 맞춰 적절한 헤더와 본문으로 HTTP 요청을 구성합니다.
전송 실행
적절한 인증과 헤더로 알림을 전송합니다. Alert 폭주를 막기 위해 자동 재시도는 하지 않습니다.
전송 결과 기록
timestamp, 응답, 상태, 오류 상세(있는 경우)를 담아 AlertLog 항목을 기록합니다. 로그는 30일간 보관됩니다.
전송 메커니즘
Wave는 세 가지 알림 전송 방식을 지원하며, 각각 요청 구성 방식과 오류 처리 방식이 다릅니다.
HTTP Webhook 전송
범용 HTTP webhook 전송은 HTTP 요청을 받을 수 있는 모든 엔드포인트를 지원합니다.
요청 구성:
POST /webhook HTTP/1.1
Host: example.com
Content-Type: application/json
Authorization: Bearer <token>
User-Agent: WaveAutoscale/1.0
{
"text": "<rendered message>"
}HTTP 요청 생성
설정된 method(POST/PUT/PATCH/DELETE)와 대상 URL로 요청을 만듭니다.
커스텀 헤더 추가
채널 설정에 지정된 커스텀 헤더(예: Authorization, Content-Type)를 적용합니다.
요청 본문 설정
렌더링된 메시지를 JSON으로 인코딩해 요청 본문으로 설정합니다.
Proxy 적용
설정돼 있으면 HTTP proxy를 통해 요청을 라우팅합니다 (인증이 필요한 proxy도 지원).
요청 실행
30초 타임아웃으로 요청을 보내고 응답을 기다립니다.
응답 파싱
HTTP 상태 코드와 응답 본문을 파싱합니다. 디버깅을 위해 로그로 남깁니다.
성공 기준:
- HTTP 2xx 상태 코드
- 응답 본문 수신 (디버깅용으로 로깅됨)
실패 처리:
- HTTP 4xx/5xx → 상태 코드와 응답 본문을 포함해 오류 로깅
- Timeout → 타임아웃 오류 로깅
- Network 오류 → 연결 오류 로깅
- 자동 재시도 없음 (Alert 폭주 방지를 위한 설계입니다)
Slack Webhook 전송
Incoming webhook을 사용한 간단한 Slack 연동입니다.
요청 구성:
POST /services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX HTTP/1.1
Host: hooks.slack.com
Content-Type: application/json
{
"text": "<rendered message>"
}Webhook URL로 POST 전송
메시지를 담은 JSON 본문으로 Slack webhook URL에 HTTP POST 요청을 보냅니다.
Slack 처리
Slack이 webhook을 처리해 설정된 채널에 메시지를 게시합니다.
응답 파싱
Slack은 "ok"(성공) 또는 오류 메시지로 응답합니다. 결과를 파싱해 로깅합니다.
성공 기준:
- HTTP 200 상태
- 응답 본문에 "ok" 포함
실패 처리:
- Slack 오류 로깅 (invalid_token, channel_not_found 등)
- Rate limiting 처리 (HTTP 429 → 로깅, 재시도 없음)
Slack Web API 전송
더 풍부한 기능을 위해 Web API를 사용하는 고급 Slack 연동입니다.
요청 구성:
POST /api/chat.postMessage HTTP/1.1
Host: slack.com
Content-Type: application/json
Authorization: Bearer xoxb-<token>
{
"channel": "C1234567890",
"text": "<rendered message>"
}요청 인증
API 인증을 위해 Authorization: Bearer 헤더에 bot token을 포함합니다.
대상 채널 지정
채널 ID(예: C1234567890) 또는 채널 이름(예: #alerts)으로 대상 채널을 지정합니다.
API 엔드포인트로 POST 전송
Slack Web API의 chat.postMessage 엔드포인트로 요청을 보냅니다.
API 응답 파싱
Slack은 메시지 상세 정보 또는 오류 정보를 담은 JSON으로 응답합니다.
성공 기준:
- HTTP 200 상태
ok: true가 포함된 JSON 응답
실패 처리:
- 인증 오류 (invalid_auth, token_revoked)
- 채널 오류 (channel_not_found, not_in_channel)
- Rate limiting (HTTP 429)
- 모든 오류는 Slack API 응답의 상세 정보와 함께 로깅됨
성능 특성
평가 처리량
- 평가되는 Alert 수: 평가 주기당 최대 1000 alerts/second
- 표현식 평가: 규칙당 약 1ms (JavaScript 실행)
- 대상 매칭: O(n) (n = EventTargets에 지정된 리소스 수)
전송 지연 시간
- 로컬 처리: 10ms 미만 (규칙 평가 + 템플릿 렌더링)
- HTTP 전송: 100~500ms (엔드포인트 지연 시간에 따라 다름)
- Slack 전송: 200~800ms (Slack API 지연 시간에 따라 다름)
- 전체 End-to-End: 이벤트 생성부터 알림 전송까지 약 1~2초
리소스 사용량
- 메모리: Alert 규칙 1000개당 약 50MB
- CPU: 분당 100건 평가 시 약 0.1 core
- 데이터베이스: Alert 규칙당 약 1KB, Alert 로그 항목당 약 500 bytes
- 네트워크: 미미함 (알림 전송을 위한 outbound HTTP 요청만 발생)
확장성 한계
- 클러스터당 최대 Alert 수: 10,000개 (soft limit, 설정 가능)
- 클러스터당 최대 채널 수: 1,000개 (soft limit)
- 최대 Alert 로그 보관 기간: 30일 (설정 가능)
- 최대 메시지 크기: 4KB (Slack 제한)
- 최대 동시 전송 수: 100 (connection pool 크기)
보안 모델
인증
- API 접근: Alert/채널 CRUD에는 Bearer token 인증이 필요합니다
- RBAC: 역할 기반 접근 제어 (Alert 관리에는 admin 권한 필요)
- 감사 추적: 모든 변경 사항은 user ID와 timestamp와 함께 기록됩니다
채널 보안
HTTP Webhook:
- HTTPS를 강력히 권장합니다 (HTTP도 허용되지만 권장하지 않음)
- Bearer token/API key는 암호화해 저장합니다
- 로그에는 자격 증명이 노출되지 않습니다 (AlertLog 항목에서 마스킹됨)
Slack 연동:
- Bot token은 암호화해 저장합니다
- Webhook URL은 secret으로 취급합니다
- Token은 로그에 남거나 API 응답에 노출되지 않습니다
표현식 샌드박싱
- 격리된 샌드박스에서 JavaScript 실행
- 파일시스템, 네트워크, 시스템 콜에 접근 불가
- 메모리와 CPU 제한 적용
- 타임아웃으로 무한 루프 방지
네트워크 보안
- Outbound 연결만 허용 (Alert 채널로부터의 inbound 없음)
- 엔터프라이즈 환경을 위한 proxy 지원
- TLS 인증서 검증 적용
- 자격 증명 캐싱 없음 (전송마다 자격 증명을 새로 조회)
오류 처리와 디버깅
검증 오류
규칙 표현식 검증:
{
"is_valid": false,
"error": "Syntax error: Unexpected token '}'",
"metadata": null
}메시지 템플릿 검증:
{
"is_valid": false,
"error": "Invalid fields used: unknown_field. Allowed fields: cpu_utilization_arr, memory_utilization_arr",
"metadata": {
"used_fields": ["unknown_field"],
"preview": null
}
}런타임 오류
규칙 평가 실패:
is_error: true로 AlertLog에 기록- 사유: "JavaScript execution error: < details> "
- Alert는 계속 활성 상태로 유지됩니다 (자동으로 비활성화되지 않음)
전송 실패:
is_error: true로 AlertLog에 기록- 사유에는 HTTP 상태 코드와 응답 본문이 포함됩니다
- 예시: "HTTP 401: Unauthorized - Invalid token"
디버깅 팁
- Alert 로그 확인: 무슨 일이 있었는지 파악하는 가장 확실한 방법입니다
- 채널 테스트: 프로덕션에 배포하기 전에 테스트 버튼을 사용하세요
- 표현식 검증: 규칙을 저장하기 전에 검증 API를 사용하세요
- 지연 시간 모니터링: AlertLog의
created_at을 추적해 전송 시간을 측정하세요 - 변경 사항 감사:
updated_attimestamp를 확인해 문제와 설정 변경 사이의 연관성을 파악하세요
고급 주제
커스텀 함수
현재 규칙 표현식에서 지원하는 함수는 다음과 같습니다.
max(array) // Maximum value
min(array) // Minimum value
avg(array) // Average (mean) value
sum(array) // Sum of all values사용 예시:
// Alert if max CPU in last 5min > 80% AND avg memory > 70%
evaluation_period_minutes >= 5 &&
max(cpu_utilization_arr) > 80 &&
avg(memory_utilization_arr) > 70Alert 중복 제거
Alert는 기본적으로 중복 제거되지 않습니다. 규칙이 매 확인 주기마다 true로 평가되면 그때마다 알림이 전송됩니다.
권장 사항: Alert가 짧은 간격으로 연달아 발생하지 않도록 평가 기간 조건을 추가하세요.
// Without period requirement (alerts every minute if CPU > 80%)
max(cpu_utilization_arr) > 80
// With period requirement (alerts only if sustained 5+ minutes)
evaluation_period_minutes >= 5 && max(cpu_utilization_arr) > 80다중 채널 전송
하나의 Alert는 여러 채널로 전송될 수 있습니다.
{
"alert_messages_json": [
{
"alert_channel_id": "pagerduty-prod",
"message": "CRITICAL: ${alert_title} - ${namespace}/${workload_name}"
},
{
"alert_channel_id": "slack-ops",
"message": "⚠️ Alert: ${alert_title}\nWorkload: ${namespace}/${workload_name}\nCPU: ${max(cpu_utilization_arr)}%"
}
]
}두 메시지는 각각 독립적으로 렌더링되고 전송됩니다. 하나가 실패해도 다른 하나는 전송을 계속 시도합니다.
Proxy 설정
HTTP proxy가 필요한 엔터프라이즈 환경을 위한 설정입니다.
{
"type": "http",
"data": {
"url": "https://external-api.example.com/webhook",
"proxy": "http://proxy.corp.example.com:8080"
}
}Proxy는 다음에 적용됩니다:
- HTTP webhook 전송
- Slack webhook 전송
- Slack Web API 전송
Proxy 인증이 필요하면 proxy URL에 포함해야 합니다.
http://username:password@proxy.corp.example.com:8080