SLIs, SLOs e Error Budgets
"O BoxOffice é confiável o bastante?" Ninguém responde a isso sem números. O gerente de produto quer lançar um novo mapa de lugares na semana anterior a uma abertura de vendas no estádio; a engenheira de plantão diz que o caminho de compra teve um mês ruim e quer congelar os deploys. Sem uma definição compartilhada de "bom o bastante", essa discussão é opinião contra opinião. A prática de Site Reliability Engineering (SRE) do Google introduziu um vocabulário que transforma a discussão em aritmética1, e hoje ele é padrão no mercado:
| Termo | Nome completo | Natureza | Exemplo no BoxOffice |
|---|---|---|---|
| SLI | Service Level Indicator | Uma medida do que os usuários vivenciam | % das requisições de reserva que têm sucesso em menos de 500 ms |
| SLO | Service Level Objective | Uma meta interna para um SLI, em uma janela | ≥ 99,9% em 28 dias |
| Error budget | — | A falha que o SLO permite: 1 − SLO | 0,1% das reservas podem falhar ou ser lentas |
| SLA | Service Level Agreement | Um contrato com clientes, com penalidades | Prometido às casas de show parceiras: 99,5% ao mês, ou créditos |
flowchart LR
tel["Telemetria<br/>(métricas, logs, traces)"] -->|"agregada em"| sli["SLI<br/>eventos bons / válidos"]
sli -->|"comparado com"| slo["SLO<br/>meta interna"]
slo -->|"a diferença é"| budget["Error budget<br/>licença para correr risco"]
slo -->|"versão mais folgada"| sla["SLA<br/>contrato externo"]
budget -->|"orienta"| decisions["Lançar ou congelar?<br/>Acionar ou abrir chamado?"] Comece pelas jornadas do usuário
Um SLO só é útil se mede o que importa para os usuários. Comece listando as jornadas críticas de usuário (CUJs, critical user journeys) do BoxOffice — as poucas interações que precisam funcionar — e depois decida como medir cada uma.
| Jornada crítica | Por que importa | Tipo de SLI |
|---|---|---|
| Navegar pelo catálogo e pelas páginas de eventos | A maior parte do tráfego; primeira impressão | Disponibilidade + latência |
| Entrar na sala de espera e ser admitido | A flash sale depende disso | Disponibilidade + latência das atualizações de posição |
| Reservar lugares | Receita; fortemente consistente | Disponibilidade + latência |
| Pagar e ter o pedido confirmado | Receita; provedor externo envolvido | Disponibilidade (de ponta a ponta, incluindo a saga) |
| Receber os ingressos por e-mail / no app | Confiança; assíncrono | Atualidade (freshness): tempo da confirmação até a entrega |
| Buscar eventos | Descoberta | Latência + qualidade (resultados não desatualizados) |
Nem toda jornada precisa da mesma meta. A navegação tolera uma página lenta de vez em quando; um pagamento que falha perde uma venda e a confiança de um fã.
SLI — medindo o que os usuários sentem
Um SLI é melhor escrito como uma razão de eventos, para ficar sempre entre 0% e 100%2:
As duas palavras importam. Bom define sucesso do ponto de vista do usuário — "o status não é 5xx e a latência é menor que 500 ms". Válido exclui o que não deve contar — respostas 4xx causadas pelo cliente, requisições de health check, testes de carga sintéticos.
| Categoria de SLI | Evento bom | Exemplo no BoxOffice |
|---|---|---|
| Disponibilidade | Requisição respondida sem erro do servidor | POST /holds devolveu não-5xx |
| Latência | Requisição respondida abaixo de um limite | GET /events/{id} em < 300 ms |
| Atualidade | Dado ou efeito colateral recente o bastante | E-mail de confirmação enviado < 2 min depois do OrderConfirmed |
| Correção | A saída está certa | Nenhum lugar vendido duas vezes (verificado por um job de reconciliação) |
| Durabilidade | Dados armazenados podem ser lidos de volta | Todo pedido confirmado pode ser lido um dia depois |
Evite métricas de vaidade
Uso de CPU, heap da JVM ou número de pods não são SLIs. Um serviço pode estar a 95% de CPU e atender todos bem, ou a 5% de CPU e estar completamente fora (em deadlock, mal roteado). Elas são úteis para diagnosticar; SLIs precisam refletir o que os usuários vivenciam.
Onde medir
| Ponto de medição | Vê | Não vê |
|---|---|---|
| Métricas da aplicação (OpenTelemetry, Micrometer) | Detalhe por rota, barato | Requisições que nunca chegaram ao app (LB, DNS, rede) |
| Logs do load balancer / gateway | Tudo o que chegou à borda | Falhas do lado do cliente, CDN |
| Probes sintéticos | Uma jornada roteirizada de fora, mesmo sem tráfego | A diversidade dos usuários reais |
| Telemetria do cliente (navegador / app) | O que os usuários realmente vivenciam | Ruidosa; depende da rede dos usuários |
Uma escolha comum é calcular os SLIs no gateway (perto do usuário, mas sob seu controle) e complementá-los com probes sintéticos da jornada de compra. Com métricas OpenTelemetry exportadas para o Prometheus (veja Sinais), o SLI de disponibilidade da rota de reserva em 5 minutos é:
sum(rate(http_server_request_duration_seconds_count{service_name="gateway", http_route="/holds", http_response_status_code!~"5.."}[5m]))
/
sum(rate(http_server_request_duration_seconds_count{service_name="gateway", http_route="/holds"}[5m]))
Um SLI de atualidade para trabalho assíncrono
SLIs de requisição não enxergam falhas assíncronas: POST /orders pode estar 100% verde enquanto o consumidor notification está duas horas atrasado (veja Mensageria). O BoxOffice mede a jornada "receber os ingressos" com um SLI de atualidade: para cada OrderConfirmed, o tempo até o e-mail ser aceito pelo provedor. Evento bom: menos de 2 minutos. O SLO: 99% das confirmações em 28 dias. O consumer lag em segundos é o sinal de alerta antecipado.
SLO — a meta
Um SLO é uma meta para um SLI em uma janela:
SLI ≥ metaem umajanela
| SLO do BoxOffice | Significado |
|---|---|
| Reservas: 99,9% com sucesso em < 500 ms, em 28 dias | No máximo 1 em cada 1.000 reservas pode falhar ou ser lenta |
| Páginas do catálogo: 99,5% servidas em < 300 ms, em 28 dias | A navegação tolera mais lentidão |
| Entrega de ingressos: 99% em até 2 min da confirmação, em 28 dias | Atualidade do caminho assíncrono |
| Sala de espera da abertura de vendas: 99,95% das atualizações de posição com sucesso, durante cada abertura | Um SLO restrito ao evento para as horas que mais importam |
Use uma janela móvel (os últimos 28 dias, avançando a cada minuto) em vez de um mês de calendário: 28 dias sempre contêm quatro de cada dia da semana, e o orçamento não "zera" magicamente no dia 1º.
Como escolher o número:
- Meça primeiro. Olhe o SLI dos últimos 30–90 dias e defina o SLO um pouco abaixo do que você já alcança. Uma meta que você já perde toda semana é ruído.
- Respeite a matemática das dependências. O
ordernão pode prometer mais que o produto do que ele chama de forma síncrona (Confiabilidade — disponibilidade composta). Se o provedor de pagamento oferece 99,9%, um SLO de compra de 99,99% é ficção. - Pergunte o que os usuários percebem. Ir de 99,9% para 99,99% custa muito (veja a tabela de noves); se os fãs não perceberiam, o dinheiro rende mais em funcionalidades.
- Nunca 100%. Não deixa espaço para deploys, manutenção ou o inevitável, e todas as suas dependências estão abaixo disso de qualquer forma.
Error budget
O error budget é a quantidade de não confiabilidade que o SLO permite — a licença do time para correr riscos:
O caminho de compra recebe cerca de 1.000.000 de requisições por dia. Em 28 dias são 28.000.000 de requisições, e um SLO de 99,9% permite
Um deploy ruim que devolve erros para 5% das requisições durante 3 horas (\(0.05 \times 3 \times 41\,667 \approx 6\,250\) falhas) gasta cerca de 22% do orçamento do mês em uma tarde.
Para um SLO de 99,9% em 28 dias:
Orçamentos por tempo são intuitivos ("temos 40 minutos de indisponibilidade"), mas tratam as 3 da manhã como as 10:00 de um dia de abertura de vendas. Orçamentos por requisições pesam as falhas pelo tráfego que elas atingem.
Burn rate
O burn rate diz com que velocidade o orçamento está sendo gasto em relação à janela2:
Com um SLO de 99,9%, uma taxa de erros de 0,1% é um burn rate de 1 — o orçamento dura exatamente os 28 dias. Uma taxa de erros de 1,44% é um burn rate de 14,4, que esgota o orçamento em \(28 / 14.4 \approx 1.9\) dia.
A simulação abaixo acompanha o orçamento do caminho de compra em uma janela de 28 dias com números ilustrativos: um fundo tranquilo de 0,01% de erros, um deploy ruim no dia 9 (5% de erros por 3 horas) e uma degradação lenta a partir do dia 16 (0,2% de erros — um burn rate de apenas 2).
Os dois incidentes ensinam lições diferentes:
- O deploy ruim tem um burn rate enorme (50×) por pouco tempo. Ele precisa acionar alguém em minutos, e o orçamento mostra quanto custou: cerca de um quinto do mês.
- A degradação lenta nunca parece dramática — 0,2% de erros não assustaria ninguém num dashboard — mas a 2× ela esgota o orçamento por volta do dia 26. Só um alerta de queima lenta, em uma janela longa, a pega.
Alertando pelo burn rate
Alerte pelo orçamento, não por taxas de erro brutas ou CPU. O SRE Workbook recomenda alertas multijanela e multi-burn-rate2: uma janela longa para medir a relevância e uma janela curta para encerrar o alerta logo que o problema for corrigido.
| Severidade | Burn rate | Janela longa | Janela curta | Orçamento consumido quando dispara |
|---|---|---|---|---|
| Acionar (page) | 14,4× | 1 h | 5 min | 2% |
| Acionar (page) | 6× | 6 h | 30 min | 5% |
| Chamado (ticket) | 1× | 3 dias | 6 h | 10% |
Experimente
A janela tem os dois incidentes do gráfico acima e alguns soluços curtos. Dê play (acelere com o botão 1×) e compare as quatro faixas de alerta.
- Soluços: a regra ingênua (erros > 0,1% em 5 min) aciona alguém em quase todos — 10 vezes neste mês —, embora os 14 soluços juntos custem só 1,6% do orçamento. As regras de burn rate ficam quietas.
- Deploy ruim (dia 9, 5% por 3 h): a regra de 14,4× aciona 17 minutos depois do início, quando o incidente custou 2,2% do orçamento; a de 6× vem após 42 minutos (5,3%). O incidente inteiro custa 22,3%.
- Degradação lenta (2× a partir do dia 16): nenhum page; o ticket de 3 dias dispara 34 horas depois (dia 17,4), com 39% do orçamento gasto — mais de 8 dias antes de ele acabar (dia 25,9).
- Aperte limpar incidentes, avance até o dia 2, pause e injete 0,7% por 3 dias: nenhum page rápido, mas a regra de 6× aciona após cerca de 5 horas. Com 20% por 30 min o page chega após 4 minutos, e mesmo assim o incidente custa cerca de 15%: um alerta só salva o orçamento que ainda não foi queimado.
O lab 9 provisiona as mesmas regras de 14,4× e 6× (como page e ticket) para o order, com um SLO de 99,5%.
# Prometheus alerting rule: purchase path, SLO 99.9% (budget = 0.001)
- alert: PurchaseErrorBudgetFastBurn
expr: |
(
sum(rate(http_server_request_duration_seconds_count{service_name="gateway", http_route=~"/holds|/orders", http_response_status_code=~"5.."}[1h]))
/ sum(rate(http_server_request_duration_seconds_count{service_name="gateway", http_route=~"/holds|/orders"}[1h]))
) > (14.4 * 0.001)
and
(
sum(rate(http_server_request_duration_seconds_count{service_name="gateway", http_route=~"/holds|/orders", http_response_status_code=~"5.."}[5m]))
/ sum(rate(http_server_request_duration_seconds_count{service_name="gateway", http_route=~"/holds|/orders"}[5m]))
) > (14.4 * 0.001)
labels:
severity: page
annotations:
summary: "Purchase path burning the 28-day error budget 14.4x faster than allowed"
Os detalhes do projeto de alertas, do roteamento e do plantão estão em Observabilidade — alertas.
No código do BoxOffice: o SLO como regra de alerta (labs 8 e 9)
O Hands-on 8 — SLO e alerta de burn rate escreve a promessa do catalog: 99,5% das requisições, sem contar os health checks, respondidas sem 5xx em 28 dias — a 100 req/s, um orçamento de cerca de 1,21 milhão de requisições com falha. Ele provisiona a regra de 14,4× como page e a de 6× como ticket, em arquivos que o Grafana carrega na inicialização. O Hands-on 9 — Game day copia o arquivo para o order, para que uma falha escondida no caminho do pagamento acione os operadores. Leia o trecho buscando as três partes da regra: a consulta A (a razão de erros em 1 h, dividida pelo orçamento 0,005, é o burn rate), a consulta B (a mesma em 5 min; B repete A com [5m], cortada aqui) e a condição C, que exige as duas. http_route!~"/actuator.*" deixa as probes fora do SLI.
- uid: order-availability-fast-burn
title: "order 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="order", http_route!~"/actuator.*", http_response_status_code=~"5.."}[1h]))
/ sum(rate(http_server_request_duration_seconds_count{service_name="order", 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: order-availability
annotations:
summary: "order is burning its 28-day error budget 14.4x too fast"
description: 'Burn rate {{ printf "%.1f" $values.A.Value }} (1 h) and {{ printf "%.1f" $values.B.Value }} (5 min): at this pace about 2% of the 28-day budget is gone in one hour.'
A política de error budget
Um error budget é só um número num dashboard, a menos que produto e engenharia combinem de antemão o que acontece à medida que ele é gasto. Esse acordo é a política de error budget:
Política de error budget do BoxOffice (caminho de compra)
- Orçamento acima de 50%: operação normal; deploy em qualquer dia útil; experimentos permitidos.
- Orçamento entre 0 e 50%: deploys precisam de plano de rollback e canary; um item de confiabilidade entra em toda sprint.
- Orçamento esgotado: deploys de funcionalidades no caminho de compra ficam congelados até o SLI de 28 dias voltar acima do SLO; só correções e trabalho de confiabilidade são lançados.
- Regra de abertura de vendas: nenhum deploy no caminho de compra nas 24 horas anteriores a uma grande abertura, qualquer que seja o orçamento.
- Um único incidente > 20% do orçamento: postmortem sem culpados obrigatório, com itens de ação (veja Resposta a incidentes).
Assinada pelo gerente de produto e pela liderança de engenharia do caminho de compra; revisada a cada trimestre.
O orçamento como ferramenta de negociação
O gerente de produto quer lançar o novo mapa de lugares; a engenheira está receosa. O orçamento responde de forma objetiva: "temos 70% do orçamento e a mudança sai atrás de uma feature flag para 5% dos fãs — pode lançar." Ou: "temos 8% e a abertura do estádio é na sexta — espera até a semana que vem." Note que funciona também no sentido inverso: um orçamento sem uso é sinal de que o time está cauteloso demais e poderia ir mais rápido.
SLA — o contrato
Um SLA é um acordo formal com clientes que define o serviço esperado e as compensações (em geral créditos) se ele não for cumprido. É um documento jurídico: descumpri-lo custa dinheiro.
Um SLA tipicamente define: serviços e regiões cobertos; o compromisso (por exemplo, 99,9% de uptime mensal); como ele é medido; exclusões (manutenção programada, problemas causados pelo cliente, força maior); e a tabela de créditos.
Os compromissos abaixo vêm das páginas públicas de SLA dos provedores3; as condições mudam com o tempo, então sempre leia a página atual.
| Provedor | Serviço | Compromisso mensal | Condição |
|---|---|---|---|
| AWS | Amazon EC2 | 99,99% (no nível da região) | Instâncias em várias AZs |
| AWS | Amazon RDS | 99,95% | Implantações Multi-AZ |
| AWS | Amazon S3 Standard | 99,9% | — |
| Google Cloud | Compute Engine | 99,99% | Instâncias em várias zonas |
| Azure | Virtual Machines | 99,99% | Duas ou mais VMs em zonas de disponibilidade |
Duas lições se escondem nessa tabela. Primeiro, os números mais altos só valem se você implantar com redundância — a redundância é o preço do nove extra. Segundo, a compensação é um crédito na sua fatura, não uma indenização pelos ingressos que você deixou de vender: um SLA transfere um pouco de risco financeiro; ele não torna seu sistema disponível.
| SLO | SLA | |
|---|---|---|
| Público | O time de engenharia | Clientes, parceiros, advogados |
| Natureza | Meta interna | Contrato jurídico |
| Rigor | Mais rígido | Mais folgado |
| Quando não é cumprido | Trabalho de confiabilidade, congelamento de deploys | Créditos, multas, reputação |
Mantenha o SLO mais rígido que o SLA (por exemplo, SLO de 99,95%, SLA de 99,9%): a diferença é uma margem de segurança que avisa muito antes de o contrato estar em risco.
Na entrevista
Na etapa de requisitos, transforme o vago "altamente disponível" em SLOs por jornada: "reservas 99,9% abaixo de 500 ms; navegação 99,5%; e-mail de ingressos em até 2 minutos para 99%". Depois use-os: eles justificam a redundância (matemática das dependências), a assincronia (remover dependências não críticas) e os alertas (burn rate). Diga que 99,99% significa cerca de 4 minutos por mês, então exige failover automatizado. Entrevistadores valorizam mais ouvir por que um número foi escolhido do que o número em si.
Boas práticas
- Mantenha SLOs e suas regras de alerta como código, no repositório, revisados como qualquer mudança — uma meta que ninguém consegue comparar ou reproduzir se desvia. No BoxOffice:
slo-catalog.yamleslo-order.yaml, carregados pelo Grafana na inicialização (labs 8 e 9, quadro acima). - Tire do SLI as probes e o tráfego sintético com um filtro de label explícito — health checks a cada poucos segundos inflam a taxa de sucesso com requisições que nenhum fã fez. No BoxOffice:
http_route!~"/actuator.*"nas regras. - Comece cada SLO um pouco abaixo de 30–90 dias de SLI medido e revise-o a cada trimestre — uma meta que você já perde toda semana é ruído; uma que você sempre supera é um orçamento que ninguém gasta.
- Mostre o error budget restante onde as entregas são planejadas — a decisão de lançar ou congelar vira rotina em vez de debate: 28.000 compras com falha a cada 28 dias a 99,9%.
- Acrescente um SLO com escopo de evento para cada grande abertura de vendas — uma hora ruim quase não mexe num orçamento de 28 dias, mas é a hora que importa; a sala de espera promete 99,95% durante cada abertura.
Armadilhas comuns
- Medir a coisa errada: um SLI do endpoint de health check não diz nada sobre
POST /holds. - Médias em vez de limites ou percentis: uma média de 80 ms pode esconder 5% dos fãs esperando 4 s.
- SLOs demais: dois ou três por jornada, sobre os quais alguém age, valem mais que trinta que ninguém lê.
- Ignorar os caminhos assíncronos: APIs verdes, e-mails com três horas de atraso. Adicione SLIs de atualidade.
- SLO sem política: se nada muda quando o orçamento acaba, o SLO é decoração.
- Misturar janelas: um orçamento calculado em 30 dias comparado com um SLO de 28 dias leva a decisões erradas.
Como se conecta
flowchart LR
CUJ["jornadas críticas do usuário"] --> SLI["SLI = eventos bons / válidos"]
TEL["telemetria no gateway<br/>→ Observabilidade"] --> SLI
SLI --> SLO["SLO em uma janela<br/>móvel de 28 dias"]
DEP["matemática das dependências<br/>→ disponibilidade composta"] --> SLO
SLO --> EB["orçamento de erros = 1 − SLO"]
SLO --> SLA["SLA: um contrato<br/>externo mais frouxo"]
EB --> BR["alertas de burn rate multijanela<br/>→ Observabilidade — alertas"]
EB --> POL["política de orçamento:<br/>entregar ou congelar?"]
POL --> DEL["canário, congelamento de deploys<br/>→ Cloud-native — entrega"]
POL --> PM["postmortem acima de 20% do orçamento<br/>→ Resposta a incidentes"] Componentes da paleta: metrics (o SLI é uma razão de contadores de requisições) · alerting (regras de burn rate multijanela) · apigw (onde o BoxOffice mede o SLI da compra) · kafka (o consumer lag, alerta antecipado do SLI de frescor da entrega de ingressos) · payment (seus 99,9% limitam o SLO da compra). Cenários: observability-stack, flash-sale (o SLO por evento de abertura de vendas). Continua em: Observabilidade — alertas, Observabilidade — resposta a incidentes, Estimativas — matemática da disponibilidade, Cloud-native — entrega, Hands-on 8 — SLO e alerta de burn rate.
-
BEYER, B. et al. Site Reliability Engineering. O'Reilly, 2016. Capítulo 3, "Embracing Risk"; capítulo 4, "Service Level Objectives". ↩
-
BEYER, B. et al. The Site Reliability Workbook. O'Reilly, 2018. Capítulo 2, "Implementing SLOs"; capítulo 5, "Alerting on SLOs". ↩↩↩
-
AWS Service Level Agreements; Google Cloud Service Level Agreements; Azure Service Level Agreements. ↩