# 🚨 Alerting — SLO-driven monitoring
## 🤔 ¿Qué hago? ¿Cómo lo hago? ¿Y para qué lo hago?
**¿Qué hago?** Defino reglas de alertas en Prometheus basadas en violaciones de SLOs — disponibilidad, latencia y cache hit rate.
**¿Cómo lo hago?** PrometheusRule CRD (Custom Resource Definition) en Kubernetes con alertas preconfiguradas que evalúan métricas cada 30s.
**¿Para qué lo hago?** Sin alertas, los problemas pasan desapercibidos. Con alertas SLO-driven, oncall reacciona antes de que se queme el error budget.
---
## 📋 Alertas de SLO
### 🔵 SLO-1: Disponibilidad < 99.5%
**Métrica:** Error rate (5xx) en ventana rolling 5m
```yaml
alert: SLOAvailabilityViolation
expr: (sum(rate(requests_total{status=~"5.."}[5m])) / sum(rate(requests_total[5m]))) > 0.005
for: 10m
severity: critical
```
**Dispara cuando:**
- > 0.5% de requests fallan con 5xx durante 10 minutos consecutivos
**Error budget:** 3.6 horas/mes
**Acción inmediata:**
1. Revisar logs: `kubectl logs -l app=klaus-proxy | grep ERROR`
2. Check Anthropic status page
3. Revisar Qdrant pod metrics
4. Si persiste > 20 min: escalada a SRE lead
**Dashboard:** Grafana panel "Error Rate (5m rolling)"
---
### 🟠 SLO-2: Latencia p99 > 2s
**Métrica:** Percentil 99 de request_duration_seconds
```yaml
alert: SLOLatencyViolation
expr: histogram_quantile(0.99, rate(request_duration_seconds_bucket[5m])) > 2
for: 10m
severity: warning
```
**Dispara cuando:**
- 99% de requests toman > 2 segundos
**Error budget:** 7.2 minutos de violaciones/mes
**Posibles causas:**
- Qdrant saturado (búsquedas lentas)
- Anthropic sobrecargado
- Network congestion cliente ↔ Anthropic
- Embeddings model latente
**Acción:**
1. Revisar métricas de Qdrant: `kubectl exec -it qdrant-0 -- qdrant-cli stats`
2. Revisar CPU/memory de Klaus-proxy pods
3. Revisar Anthropic latency en su dashboard
4. Considerar escalado de Qdrant replicas si es necesario
**Tuning futuro:**
- Fase 2: p99 < 1.5s
- Fase 3: p99 < 1s
---
### 🟡 SLO-3: Cache hit rate < 70%
**Métrica:** Cache hits / total hits
```yaml
alert: SLOCacheHitRateViolation
expr: |
(sum(rate(cache_hits_total[5m])) /
(sum(rate(cache_hits_total[5m])) + sum(rate(cache_misses_total[5m])))) < 0.70
for: 15m
severity: info
```
**Dispara cuando:**
- Cache hit rate < 70% durante 15 minutos
**Error budget:** 9 días/mes con cache disabled
**Posibles causas:**
- Cache corrupto (flush necesario)
- Queries no-cacheables (ej: por fecha/usuario)
- Colección llena (evictions)
- Bajo hit rate es normal early morning (queries frescas)
**Acción:**
1. Revisar cache stats: `curl localhost:8000/cache/stats`
2. Si > 50% evictions: aumentar Qdrant memory o limpiar datos antiguos
3. Analizar query patterns: ¿hay patrones no-cacheables?
---
## 🚨 Emergency Alerts
### 🔴 High Error Rate (> 10%/min)
```yaml
alert: HighErrorRate
expr: sum(rate(requests_total{status=~"5.."}[1m])) > 0.1
for: 1m
severity: critical
```
**Dispara en:** Emergencia total (> 10% de requests con 5xx)
**Acción:** Rollback inmediato o escalada a VP Eng
---
### 🔴 Qdrant Connection Failure (> 5% fallos)
```yaml
alert: QdrantConnectionFailure
expr: (sum(rate(requests_failed_total{error_type=~".*Qdrant.*"}[1m])) / sum(rate(requests_total[1m]))) > 0.05
for: 2m
severity: critical
```
**Acción:**
- Check Qdrant pod status: `kubectl get pods -l app=qdrant`
- Revisar logs: `kubectl logs qdrant-0`
- Reiniciar pod si está hung: `kubectl restart pods qdrant-0`
---
### ⚠️ Anthropic Timeout Rate (> 10%)
```yaml
alert: AnthropicTimeoutRate
expr: (sum(rate(requests_failed_total{error_type=~".*Timeout.*"}[1m])) / sum(rate(requests_total[1m]))) > 0.10
for: 2m
severity: warning
```
**Acción:**
- Revisar Anthropic status
- Increase client-side timeouts si es necesario
- Circuit breaker pasará a OPEN automáticamente
---
## ⚙️ Integración con Prometheus
### PrometheusRule en Helm
```yaml
# helm/prometheus-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: klaude-proxy-slo-alerts
namespace: klaude
spec:
groups:
- name: slo.availability
interval: 30s
rules:
- alert: SLOAvailabilityViolation
expr: ...
for: 10m
annotations: ...
```
### Instalación en cluster
```bash
# Helm despliega la PrometheusRule
helm install klaude ./helm \
--namespace klaude \
--set prometheusRule.enabled=true \
--set prometheusRule.namespace=klaude
# Verificar PrometheusRule
kubectl get prometheusrules -A
kubectl describe prometheusrule klaude-proxy-slo-alerts -n klaude
```
---
## 📲 Notificación al oncall
### Integración con OpsGenie / Slack / PagerDuty
En Prometheus alertmanager.yml:
```yaml
# prometheus/alertmanager.yml
route:
receiver: 'klaude-team'
group_by: ['alertname', 'severity']
receivers:
- name: 'klaude-team'
slack_configs:
- api_url: 'https://hooks.slack.com/...'
channel: '#klaude-alerts'
title: '{{ .GroupLabels.alertname }}'
text: '{{ .CommonAnnotations.description }}'
pagerduty_configs:
- service_key: 'YOUR_SERVICE_KEY'
severity: '{{ .GroupLabels.severity }}'
```
---
## 📊 Recording Rules — Métricas derivadas
```yaml
- name: derived_metrics
interval: 30s
rules:
- record: slo:availability:30d
expr: |
sum(rate(requests_total{status=~"2..|3..|4.."}[30d])) /
sum(rate(requests_total[30d]))
- record: slo:latency_p99:5m
expr: histogram_quantile(0.99, rate(request_duration_seconds_bucket[5m]))
- record: slo:cache_hit_rate:5m
expr: |
sum(rate(cache_hits_total[5m])) /
(sum(rate(cache_hits_total[5m])) + sum(rate(cache_misses_total[5m])))
```
---
## 🎯 Error Budget Management
### Tracking error budget
```promql
# Error budget quemado en 30 días
slo:error_budget_used:30d =
(1 - slo:availability:30d) / (1 - 0.995) * 100
# Si > 100%, SLO violado
```
### Tabla de decisiones
| Error budget | Decisión |
| --- | --- |
| **> 90% usado** | 🟡 Freeze de cambios no-críticos. Solo hotfixes. |
| **> 75% usado** | 🟡 Desacelerar PRs. Extra testing antes de merge. |
| **< 50% usado** | 🟢 Velocidad normal. Experi mentación permitida. |
| **< 25% usado** | 🟢 Abierto para innovación. Cambios arriesgados OK. |
---
## 🧪 Testing de alertas
### Test de sintaxis
```bash
promtool check rules helm/prometheus-rules.yaml
```
### Simular violación (en desarrollo)
```bash
# Inyectar métrica fake que cause alert
curl -X POST http://localhost:9091/metrics/job/test \
-d 'requests_total{status="500"} 1000'
# Verificar alert en Prometheus UI
# http://localhost:9090/alerts
```
---
## 📈 Dashboard recomendado (Grafana)
```
┌─────────────────────────────────────────────────────────┐
│ Klaus-proxy SLO Dashboard │
├─────────────────────────────────────────────────────────┤
│ 📊 Availability (30d) │ 🕐 Latency p99 (5m) │
│ 99.52% (SLO: 99.5%) │ 1.8s (SLO: < 2s) │
├──────────────────────────────────────────────────────────┤
│ 💾 Cache Hit Rate (5m) │ 🚨 Error Rate (1m) │
│ 73% (SLO: > 70%) │ 0.3% (SLO: < 0.5%) │
├──────────────────────────────────────────────────────────┤
│ 📈 Request Volume (rate/s) │ 🔌 Circuit Breaker Status │
│ 250 req/s │ Forward: CLOSED │
│ │ Stream: CLOSED │
└──────────────────────────────────────────────────────────┘
```
---
## 🚀 Mejoras futuras
- [ ] Alerting por percentil dinámico (p95, p50)
- [ ] Correlación de eventos (alert cuando múltiples SLOs violan)
- [ ] Runbook automático (botón para ejecutar diagnostic)
- [ ] Predictive alerting (ML en anomalías de tráfico)
- [ ] SLO burn rate alerts (% de error budget quemado por hora)
---
## 📚 Referencias
- [Prometheus Alerting Docs](https://prometheus.io/docs/alerting/latest/overview/)
- [Google SRE — Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/)
- [Prometheus AlertManager](https://github.com/prometheus/alertmanager)