Pular para conteúdo

Alertas

Um alerta é um pedido de atenção de um humano, muitas vezes às 3 da manhã. Isso o torna o sinal mais caro do sistema: custa sono, foco e, com o tempo, confiança. Dois modos de falha matam o alerting. Alertas demais — "CPU acima de 80%" em cada pod, cada oscilação de cada dependência — e o engenheiro de on-call aprende a ignorar o pager; o incidente real se afoga no ruído. Alertas de menos, ou os errados — e a primeira pessoa a notar o checkout quebrado é um fã nas redes sociais. Esta página trata de alertas que disparam quando, e somente quando, os usuários estão sendo prejudicados o bastante para que alguém precise agir.


O que merece um page

Um bom page (o acionamento do on-call) é urgente, acionável e sobre um problema visível para o usuário1. Se faltar qualquer um dos três, ele deveria ser outra coisa:

Situação Urgente? Acionável? Usuários afetados? Destino
Checkout falhando para 5% dos fãs durante uma abertura de vendas sim sim sim page para o on-call
Error budget queimando devagar: vai acabar em 10 dias não sim um pouco ticket para o time, nesta semana
O disco do broker Kafka vai encher em 4 dias neste ritmo não sim ainda não ticket
Um de 30 pods do catalog reiniciou e se recuperou não não não só dashboard / log
CPU em 85% enquanto todos os SLIs estão bem não não não nada — ou uma revisão de capacidade
O próprio pipeline de alertas está quebrado sim sim indiretamente page (via um dead man's switch, abaixo)

Sintomas, não causas

Alerte sobre sintomas — o que os usuários vivenciam: erros, latência, atualidade dos dados, corretude. Use causas — CPU, memória, um reinício de pod, uma fila cheia — para dashboards e diagnóstico, não para pages.

Alerta baseado em sintoma Alerta baseado em causa
Exemplo "razão de sucesso do checkout abaixo do SLO" "CPU do PostgreSQL > 90%"
Dispara quando os usuários estão bem? não com frequência (CPU alta, usuários felizes)
Perde problemas reais? raramente — seja qual for a causa, os usuários sentem com frequência — a falha que você não previu não tem alerta
Número de regras poucas, por jornada do usuário muitas, por componente e recurso
Diz onde olhar? não — para isso existem dashboards e traces sim, mas só para modos de falha conhecidos

A exceção é um indicador antecedente que certamente vai virar sintoma e dá tempo para agir — um disco enchendo, um certificado expirando em 7 dias. Esses são tickets, não pages, a menos que o prazo seja de horas.


Do SLO ao alerta

O SLO já diz quanta falha é aceitável: com 99,9% dos checkouts com sucesso numa janela móvel de 28 dias (a janela usada em toda a aula de Confiabilidade), o error budget é 0,1% dos checkouts. A pergunta que um alerta precisa responder, portanto, não é "há erros?" — sempre há — mas "estamos gastando o budget rápido o bastante para ter problemas?".

A medida natural é o burn rate:

\[ \text{burn rate} = \frac{\text{razão de erros observada numa janela}}{1 - \text{SLO}} \]

Um burn rate de 1 gasta exatamente o budget inteiro na janela inteira; um burn rate de 14,4 o gasta 14,4 vezes mais rápido. Se um burn rate \(b\) se mantém por um tempo \(t\), a fração do budget consumida é

\[ \text{budget consumido} = \frac{b \cdot t}{\text{janela do SLO}} \]
Burn rate Error ratio (SLO 99.9%) Budget exhausted in Budget spent in 1 h in 6 h
1× 0.10% 28.0 days 0.1% 0.9%
2× 0.20% 14.0 days 0.3% 1.8%
3× 0.30% 9.3 days 0.4% 2.7%
6× 0.60% 4.7 days 0.9% 5.4%
14.4× 1.44% 46.7 h 2.1% 12.9%
36× 3.60% 18.7 h 5.4% 32.1%
1000× 100.00% 40 min 100.0% 100.0%

Um burn rate de 1000× é uma indisponibilidade total (100% de erros contra um budget de 0,1%): o budget inteiro de 28 dias acaba em cerca de 40 minutos. É por isso que os alertas rápidos precisam disparar em minutos — e por isso que queimas lentas podem esperar o horário comercial.

Seis jeitos de escrever o alerta

O SRE Workbook2 compara seis desenhos progressivamente melhores para um alerta de SLO. Sua qualidade é medida por quatro propriedades: precisão (fração dos alertas que eram problemas reais), recall (fração dos problemas reais que geraram alerta), tempo de detecção e tempo de reset (quanto tempo o alerta continua disparando depois que o problema acaba).

# Regra Precisão Recall Detecção Reset Problema
1 razão de erros > 0,1% em 10 min baixa alto rápida rápido aciona por oscilações que mal tocam o budget
2 razão de erros > 0,1% em 36 h alta alto muito lenta muito lento uma indisponibilidade total leva ~2 min para alertar, e o alerta dura 36 h
3 regra 1 + for: 1h média baixo lenta rápido uma indisponibilidade de 100% ainda espera uma hora
4 burn rate de 14,4× em 1 h alta médio boa lento queimas lentas (3×) nunca alertam; o reset leva até uma hora
5 vários burn rates (14,4× / 6× / 1×) alta alto boa lento complexo; ainda lento para resetar
6 multiwindow, multi-burn-rate alta alto boa rápido o maior número de regras — gere-as com uma ferramenta

Multiwindow, multi-burn-rate

O desenho recomendado combina, para cada severidade, uma janela longa que prova que a queima é significativa e uma janela curta (1/12 da longa) que prova que ela ainda está acontecendo — assim o alerta para rápido quando o problema é corrigido:

Severidade Janela longa Janela curta Burn rate Budget gasto quando dispara
page 1 h 5 min 14,4× 2%
page 6 h 30 min 6× 5%
ticket 3 dias 6 h 1× 10%

O gráfico mostra o tempo de detecção para uma falha súbita com uma dada razão de erros, para as duas regras de page. Note o trade-off que ele codifica: quanto pior o incidente, mais rápido o alerta — e, para uma dada regra, o budget gasto no momento em que ela dispara é sempre o mesmo (2% e 5%).

2026-11-01T21:55:06.027075 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ 1 0 0 1 0 1 1 0 2 error ratio of the incident (%) 1 0 0 1 0 1 1 0 2 time to fire (minutes) SLO 99.9% — how fast the burn-rate alerts fire page: 14.4× over 1 h (+5 min) page: 6× over 6 h (+30 min)

Uma indisponibilidade total (100% de erros) dispara a regra rápida em menos de um minuto; um incidente que faz falhar 2% dos checkouts leva cerca de 43 minutos para disparar a regra rápida, e um que faz falhar 0,7% nunca a dispara, mas dispara a regra de 6 horas depois de cerca de 5 horas. Abaixo de 0,6% — um burn rate menor que 6× — só a regra de ticket o pega.

As regras em PromQL

Regras de gravação (recording rules) pré-calculam a razão de erros da jornada de checkout em cada janela; as regras de alerta as comparam com os limiares. (Ferramentas como Sloth, Pyrra ou a especificação OpenSLO geram essas regras a partir de uma definição curta de SLO, o que evita erros de copiar e colar.)

# prometheus-rules.yaml — checkout availability SLO: 99.9% over 28 days
groups:
  - name: slo-checkout-recordings
    rules:
      - record: slo:checkout_errors:ratio_rate5m
        expr: |
          sum(rate(http_server_request_duration_seconds_count{job="order", http_route="/checkout", http_response_status_code=~"5.."}[5m]))
          /
          sum(rate(http_server_request_duration_seconds_count{job="order", http_route="/checkout"}[5m]))
      - record: slo:checkout_errors:ratio_rate1h
        expr: |
          sum(rate(http_server_request_duration_seconds_count{job="order", http_route="/checkout", http_response_status_code=~"5.."}[1h]))
          /
          sum(rate(http_server_request_duration_seconds_count{job="order", http_route="/checkout"}[1h]))
      # ... the same expression for 30m, 6h and 3d

  - name: slo-checkout-alerts
    rules:
      - alert: CheckoutErrorBudgetFastBurn
        expr: |
          slo:checkout_errors:ratio_rate1h > (14.4 * 0.001)
          and
          slo:checkout_errors:ratio_rate5m > (14.4 * 0.001)
        labels:
          severity: page
          team: checkout
        annotations:
          summary: "Checkout is burning its 28-day error budget at more than 14.4x"
          runbook_url: "runbooks/checkout-slo.md"
      - alert: CheckoutErrorBudgetSlowBurn
        expr: |
          slo:checkout_errors:ratio_rate6h > (6 * 0.001)
          and
          slo:checkout_errors:ratio_rate30m > (6 * 0.001)
        labels:
          severity: page
          team: checkout
      - alert: CheckoutErrorBudgetTicket
        expr: |
          slo:checkout_errors:ratio_rate3d > (1 * 0.001)
          and
          slo:checkout_errors:ratio_rate6h > (1 * 0.001)
        labels:
          severity: ticket
          team: checkout

Um SLO de latência funciona do mesmo jeito: os "eventos ruins" são as requisições mais lentas que o limiar, calculadas a partir do bucket do histograma que termina no limiar:

# fraction of checkouts slower than 2 s over 1 h (the "error ratio" of a latency SLO)
1 - (
  sum(rate(http_server_request_duration_seconds_bucket{job="order", http_route="/checkout", le="2"}[1h]))
  /
  sum(rate(http_server_request_duration_seconds_count{job="order", http_route="/checkout"}[1h]))
)

No código do BoxOffice: os alertas de burn rate do catalog (lab 8)

O Hands-on 8 — SLO e alerta de burn rate escreve as duas primeiras regras da tabela acima como regras de alerta do Grafana, provisionadas a partir de um arquivo: um SLO de 99,5% em 28 dias para o catalog (um orçamento de 0,5%), com os health checks fora do SLI porque nenhum fã fez essas requisições. A consulta A é o burn rate em 1 h, a consulta B (não mostrada) a mesma expressão em 5 min, e C dispara só quando as duas passam de 14,4. Duas escolhas diferem da tabela: a regra de 6× é um ticket, não um page (um sinal mais barato para um time pequeno), e o for: 1m acrescenta um minuto de confirmação. Na execução de teste do lab, parar o banco disparou o page após cerca de 440 s, com burn rates de 17,0 (1 h) e 200,0 (5 min).

infra/grafana/alerting/slo-catalog.yaml (the fast-burn page)
- uid: catalog-availability-fast-burn
  title: "catalog availability SLO: fast burn"
  condition: C
  data:
    - refId: A          # burn rate over the long window (1 h)
      relativeTimeRange: { from: 3600, to: 0 }
      datasourceUid: prometheus
      model:
        refId: A
        instant: true
        expr: |
          (
            sum(rate(http_server_request_duration_seconds_count{service_name="catalog", http_route!~"/actuator.*", http_response_status_code=~"5.."}[1h]))
            / sum(rate(http_server_request_duration_seconds_count{service_name="catalog", http_route!~"/actuator.*"}[1h]))
          ) / 0.005
    - refId: C
      datasourceUid: __expr__
      model:
        refId: C
        type: math
        expression: "$A > 14.4 && $B > 14.4"
  for: 1m
  noDataState: OK
  execErrState: Error
  labels:
    severity: page
    slo: catalog-availability

BoxOffice — a abertura das 10h00, pelos olhos do alerta

Às 10h02 o provedor de pagamentos fica lento; às 10h03 a razão de erros do checkout (timeouts devolvidos como 504) chega a 4%. Isso é um burn rate de 40×: a média de 1 hora da regra rápida cruza 1,44% depois de cerca de 60 × 1,44 / 4 ≈ 22 minutos com 4% constantes… lento demais para uma abertura de vendas que acaba em 30 minutos. Por isso o time adiciona um SLO dedicado à abertura de vendas com uma janela mais curta (por exemplo, 99% dos checkouts abaixo de 2 s durante a hora da abertura, alertando sobre janelas de 5 minutos e de 1 minuto) — as regras gerais são calibradas para um budget de 28 dias e não conseguem reagir a um evento que dura meia hora. Jornadas diferentes, SLOs diferentes.


Roteamento: de uma regra disparada até uma pessoa

Uma regra de alerta só produz um alerta disparado. Algo precisa decidir quem fica sabendo, como e com que frequência. No ecossistema Prometheus, isso é o Alertmanager3 (o Grafana Alerting tem os mesmos conceitos): ele agrupa alertas relacionados numa só notificação, deduplica, aplica inibições e silêncios, e roteia pelos labels até os receivers.

flowchart LR
    R["Avaliação da regra<br/>Prometheus / ruler do Mimir"] --> F["Alerta disparado<br/>severity=page, team=checkout"]
    F --> G["Alertmanager<br/>agrupa · deduplica"]
    G --> S{"Silenciado ou<br/>inibido?"}
    S -->|sim| X["Descartado<br/>(ainda visível na UI)"]
    S -->|não| RT{"Roteia pelos labels"}
    RT -->|severity=page| PD["Pager<br/>celular do on-call"]
    RT -->|severity=page| SL["Slack #incidents"]
    RT -->|severity=ticket| TK["Fila de tickets"]
    PD --> ACK["On-call confirma<br/>ou escala após 5 min"]
# alertmanager.yaml (sketch)
route:
  receiver: slack-observability          # default for anything unmatched
  group_by: [alertname, team]
  group_wait: 30s                        # wait to batch related alerts into one notification
  group_interval: 5m
  repeat_interval: 4h
  routes:
    - matchers: [severity="page"]
      receiver: pager-checkout
      continue: true                     # also evaluate the next route
    - matchers: [severity="page"]
      receiver: slack-incidents
    - matchers: [severity="ticket"]
      receiver: ticket-queue

inhibit_rules:
  - source_matchers: [alertname="RegionDown"]
    target_matchers: [severity=~"page|ticket"]
    equal: [region]                      # one page for the region, not fifty for its services

receivers:
  - name: pager-checkout
    pagerduty_configs:
      - routing_key_file: /etc/alertmanager/secrets/pager-checkout
  - name: slack-incidents
    slack_configs:
      - api_url_file: /etc/alertmanager/secrets/slack-incidents
        channel: "#incidents"
  - name: slack-observability
    slack_configs:
      - api_url_file: /etc/alertmanager/secrets/slack-observability
        channel: "#observability"
  - name: ticket-queue
    webhook_configs:
      - url: http://ticket-bridge:8080/alerts
Mecanismo O que faz Uso no BoxOffice
Agrupamento muitos alertas com os mesmos labels → uma notificação 40 pods do order falhando → um page, não 40
Inibição um alerta suprime outros enquanto dispara RegionDown silencia os alertas por serviço daquela região
Silêncio cala alertas correspondentes por um período, com autor e motivo manutenção planejada do banco na terça, 02h00–03h00
Escalonamento (na ferramenta de paging) se ninguém confirmar em N minutos, aciona o secundário, depois o gestor primário dormindo ou sem sinal

Quem vigia o vigia?

Se o Prometheus ou o Alertmanager cair, nada alerta — e o silêncio se parece exatamente com saúde. Duas proteções padrão:

  • Um dead man's switch: uma regra que sempre dispara (expr: vector(1), muitas vezes chamada Watchdog), enviada a um serviço externo que aciona o page se o sinal de vida parar de chegar.
  • Alertas de ausência de dados: absent(up{job="order"}) ou absent_over_time(...) disparam quando uma métrica some — um exporter caído, uma métrica renomeada, um job que deixou de ser coletado.

Para jornadas com pouco tráfego à noite, uma razão sobre zero requisições é indefinida; probes sintéticas (um check do k6 ou do Blackbox Exporter que compra um ingresso de teste num evento falso a cada minuto) mantêm o SLI significativo a qualquer hora.


Runbooks

Todo page precisa apontar para um runbook: um documento curto que diz a um engenheiro cansado o que o alerta significa e o que tentar primeiro. Runbooks reduzem o MTTR porque os primeiros 10 minutos deixam de ser improviso.

# CheckoutErrorBudgetFastBurn

**Meaning**: checkout is failing at more than 14.4x the rate the 99.9% SLO allows;
at this pace the 28-day budget is gone in about 2 days.

**Impact**: fans cannot buy tickets. During an on-sale, declare an incident immediately (SEV1).

**First checks (5 minutes)**
1. Checkout dashboard: which status codes? which route? since when? any deploy or flag change?
2. Payment provider panel: latency and error ratio of the provider call.
3. Open an exemplar trace of a failed checkout: which span fails or waits?

**Mitigations**
- Recent deploy → roll back (`argocd app rollback order`).
- Provider slow or failing → switch to the secondary provider (flag `payment.provider=secondary`).
- Database saturated → enable the waiting room (flag `waiting-room.enabled=true`).

**Escalate to**: payments team (secondary on-call), then the incident commander rotation.

Máquinas detectam, pessoas reparam

Um alerta não tira uma réplica quebrada do balanceador: um health check faz isso em segundos, e não acorda ninguém. O page é para o que uma máquina não consegue fazer sozinha — restaurar o que foi perdido antes que a próxima falha encontre o BoxOffice com menos redundância do que foi projetado para ter. É por isso que o runbook acima reduz o MTTR, e por isso que uma réplica que reinicia e se recupera sozinha não vale um page.

Experimente. No observability-stack, uma das três réplicas do catalog morre em t = 50 s e fica morta por 80 s. Adicione Metrics (conectado ao balanceador, à aplicação e ao banco) e um Health Check conectado ao balanceador, e rode: os erros duram 3 s, e a disponibilidade é de 99,4%. Agora adicione Alerting conectado ao Metrics e rode de novo.

O que você deveria ter observado?

A curva de erros não muda: a disponibilidade continua em 99,4%, porque o health check já tinha tirado a réplica morta da rotação após 3 s. O que muda é o reparo: com alguém acionado, a réplica volta em t = 90 s em vez de t = 130 s, e o BoxOffice roda com duas de suas três réplicas por 40 s em vez de 80 s. Sem o health check, o Alerting sozinho também não ajuda os fãs — o balanceador continua mandando um terço das requisições para a réplica morta por 30 s (93,8% de disponibilidade). Máquinas contornam uma falha em segundos; pessoas a reparam em minutos, e o alerta é o que dá início aos minutos.


Trade-offs

Decisão Opção A Opção B Orientação
Sobre o que alertar causas (CPU, reinícios) sintomas (queima do SLO) sintomas acionam pages; causas vão para dashboards e tickets
Limiares razão de erros estática burn rate em relação ao SLO burn rate — o limiar acompanha a meta de negócio
Janelas uma janela janela longa + curta multiwindow: preciso e reseta rápido
Sensibilidade acionar cedo (mais alarmes falsos) acionar tarde (mais budget perdido) calibre pelo budget: queimas rápidas acionam page, lentas viram ticket
Notificação tudo no Slack page / ticket / dashboard por severidade um canal que todo mundo silencia não é alerting

Na entrevista

Quando o entrevistador perguntar "como você saberia se isso quebrou?", responda com um SLO e o alerta de burn rate dele, não com uma lista de métricas: "SLO de checkout de 99,9% em 28 dias; page quando o burn rate de 1 hora passar de 14,4×, confirmado pela janela de 5 minutos, ticket para queimas lentas; todo alerta aponta para um runbook." Mencione que você alerta sobre sintomas e usa dashboards e traces para as causas, e que um dead man's switch protege o próprio pipeline de alertas. É uma resposta de nível sênior em quatro frases.

Boas práticas

  • Derive todo page de um SLO, e mantenha as regras como código — o limite passa a seguir uma meta de negócio, e toda mudança é revisada. No BoxOffice: infra/grafana/alerting/slo-catalog.yaml, provisionado na inicialização (caixa acima).
  • Tire do SLI os health checks e a sua própria carga sintética — os orquestradores chamam /actuator/health a cada poucos segundos e ele quase nunca falha, inflando a taxa de sucesso com requisições que nenhum fã fez. No BoxOffice: http_route!~"/actuator.*" em toda consulta das regras do lab 8.
  • Ponha o burn rate, as janelas e o link do runbook na notificação — quem está de plantão julga a gravidade antes de abrir o notebook. No BoxOffice: a descrição "Burn rate 17.0 (1 h) and 200.0 (5 min)" do alerta do lab 8.
  • Teste todo alerta causando a sua falha — um alerta nunca visto disparando é uma hipótese; cronometre da falha ao page. No BoxOffice: o lab 8 para o db e registra Pending e Firing (cerca de 440 s numa execução de teste).
  • Combine cada alerta de SLO baseado em razão com uma verificação de "sem tráfego" — com zero requisições a razão fica indefinida, então noDataState: OK mantém as noites silenciosas mas também esconde uma borda que não envia nada; acrescente um probe sintético ou um alerta de tráfego caindo a zero.

Armadilhas comuns

  • Acionar pages por causas: CPU, memória e reinícios acordam pessoas à toa e as treinam a ignorar o pager.
  • for: 1h para reduzir ruído: também atrasa em uma hora o page de uma indisponibilidade total; use burn rates.
  • Uma única janela de SLO para toda situação: um budget de 28 dias não protege uma abertura de vendas de 30 minutos; dê aos eventos críticos o próprio SLO.
  • Alertas sem runbook ou sem dono: o alerta dispara, ninguém sabe o que fazer, o incidente dura mais.
  • Sem dead man's switch: a stack de monitoramento morre em silêncio, e o silêncio parece saúde.
  • Nunca apagar alertas: revise cada page depois do turno — se não era acionável, corrija ou apague.

Como se conecta

flowchart LR
    SLO["SLO 99.9% over 28 days<br/>→ SLIs, SLOs e error budgets"] --> BUD["error budget 0.1%"]
    SLI["SLI from metrics<br/>(RED, histograms)"] --> BR["burn rate =<br/>error ratio ÷ budget"]
    BUD --> BR
    BR --> MW["multiwindow rules:<br/>14.4× and 6× page, 1× ticket"]
    MW --> AM["Alertmanager: group,<br/>inhibit, silence, route"]
    AM --> PAGE["page + runbook"]
    AM --> TK["ticket"]
    PAGE --> IR["Incident Response"]
    DMS["dead man's switch,<br/>absent(), synthetic probes"] --> AM
    MW -.-> ONS["on-sale SLO,<br/>short windows"]

Componentes da paleta: alerting · metrics (o SLI e as recording rules) · payment (o provedor lento que queima o budget da abertura de vendas) · kafka (um disco de broker enchendo: ticket, não page). Cenários: observability-stack, flash-sale (uma abertura de vendas de 30 minutos precisa do próprio SLO). Continua em: SLIs, SLOs e error budgets (SLI, SLO, política de error budget), Resposta a Incidentes, Cloud-native — entrega (rollbacks citados no runbook), Hands-on 8 — SLO e alerta de burn rate.


Pontos-chave

  • Um page precisa ser urgente, acionável e visível para o usuário; todo o resto é ticket, dashboard ou nada.
  • Alerte sobre sintomas derivados do SLO; as causas servem ao diagnóstico.
  • Burn rate = razão de erros observada ÷ error budget; com uma janela de 28 dias, 14,4× gasta cerca de 2% do budget numa hora (14,4 ÷ 672 h).
  • Use regras multiwindow, multi-burn-rate: 14,4× (1 h + 5 min) e 6× (6 h + 30 min) acionam page, 1× (3 d + 6 h) abre um ticket.
  • O Alertmanager agrupa, deduplica, inibe, silencia e roteia; um dead man's switch e alertas de absent() vigiam o vigia.
  • Todo alerta tem um dono e um runbook.


  1. EWASCHUK, R. My Philosophy on Alerting. Google, 2013. Suas regras estão resumidas em BEYER, B. et al. Site Reliability Engineering — Monitoring Distributed Systems. O'Reilly, 2016. Capítulo 6. ↩

  2. BEYER, B. et al. The Site Reliability Workbook — Alerting on SLOs. O'Reilly, 2018. Capítulo 5. ↩

  3. PROMETHEUS. Alertmanager e Alerting rules. ↩