Definir o que cada sinal permite concluir
Um operador precisa de distinguir observação, hipótese e conclusão antes de decidir uma ação. Um alerta fechado, um nó Ready e um endpoint HTTP 200 descrevem factos diferentes. Nenhum destes sinais, isoladamente, prova que um processo de reconciliação voltou a produzir o resultado correto. Começa a investigação pelo impacto no consumidor e constrói uma linha de evidências: pedido, resposta, processamento, dado produzido e confirmação pelo sistema seguinte. Regista identidade, versão, intervalo temporal e população observada para evitar comparar sinais de execuções diferentes. No exercício, recebe um dossier fictício com quatro indicadores verdes e um teste funcional falhado. Para cada indicador, escreve a afirmação limitada que ele suporta e a verificação que ainda falta. A prioridade de mitigação deve seguir o impacto e o procedimento autorizado. O objetivo é permitir que outra pessoa continue a investigação sem transformar uma hipótese inicial numa causa supostamente confirmada.
Preservar resets e distribuições nas métricas
Counters de instâncias distintas podem reiniciar em momentos diferentes. Se os somares antes de calcular rate, o crescimento de uma instância pode ocultar a descida de outra. Calcula a taxa por série original antes de agregar, mantendo os labels necessários à identidade. Também não combines percentis como se fossem médias. Dois p95 locais, mesmo acompanhados de contagens iguais, não descrevem as caudas que determinam o p95 conjunto. O exercício Python desta aula usa percentis nearest-rank definidos sobre observações inteiras, sem interpolação. Em dois conjuntos, as contagens locais são 100 e os p95 são 10 e 100 ms; o p95 global muda de 100 para 50 ms, enquanto a média local continua em 55. Executa o exemplo e explica a informação perdida. Em observabilidade real, escolhe distribuições agregáveis e uma resolução adequada, documentando aproximações. O exercício não simula o motor Prometheus nem valida a interpolação de histogramas de um fornecedor.
Rever a população selecionada por uma consulta
Um filtro pode ser sintaticamente válido e excluir os eventos necessários ao diagnóstico. Em Cloud Logging, uma comparação sobre um campo ausente em jsonPayload falha silenciosamente. No exemplo original, A tem stage ready, B tem stage failed e C não tem stage. A comparação stage!=ready seleciona B, mas não C. Negar a igualdade inclui B e C, porque a igualdade não é verdadeira em nenhum dos dois. Usa o caminho completo do campo na consulta real e distingue campos ausentes de campos definidos com valores por omissão. Antes de usar contagens para aceitar uma release, ensaia entradas representativas, incluindo ausência e valores inesperados. O exercício pede que classifiques cada evento à mão e expliques se a intenção é selecionar apenas falhas conhecidas ou também estados desconhecidos. Depois documenta essa intenção no runbook. Uma consulta que omite estados desconhecidos não demonstra que todos os eventos excluídos foram bem sucedidos.
Separar saúde de aplicação, Pod e nó
Running não equivale a Ready. Uma aplicação pode manter o processo ativo enquanto uma dependência impede servir pedidos. Readiness permite retirar o Pod do tráfego normal de um Service sem reiniciar o container apenas por essa falha. Liveness e startup probes têm outras finalidades. Na atualização, um PDB não substitui a estratégia do Deployment: os controllers de workload não ficam limitados pelo PDB durante rolling updates da aplicação. Revê as opções do workload e capacidade efetiva antes de prometer disponibilidade mínima. Em GKE, node auto-repair responde a condições de saúde do nó; não corrige uma configuração inválida da aplicação em nós saudáveis. O exercício mostra CrashLoopBackOff numa versão nova e nós Ready. Identifica a camada em falha, a mitigação autorizada e os sinais que provariam recuperação. Recriar infraestrutura ou retirar readiness sem corrigir a causa pode prolongar a indisponibilidade e tornar o diagnóstico mais difícil para o turno seguinte.
Validar a resposta e o ciclo de vida do alerta
Um endpoint pode devolver HTTP 200 com uma página de login em vez do documento esperado. Configura validação de conteúdo apropriada ao contrato e ao contexto de acesso do consumidor. Um teste de conectividade continua útil, mas identifica o seu âmbito e complementa-o com verificação funcional. No exemplo, o JSON é pequeno; não se pretende prometer inspeção ilimitada de qualquer resposta por uptime checks. Também distingue o ciclo de vida de um alerta da saúde do serviço. Se o autoclose fecha um alerta depois de a telemetria deixar de chegar, o fecho não prova que a métrica regressou ao normal. Investiga a perda de observação e executa um teste independente antes de declarar recuperação. No exercício, escreve duas mensagens para o comité: uma descreve apenas o estado do alerta; a outra descreve o estado conhecido do serviço e a próxima verificação. Essa separação evita que o fecho administrativo encerre prematuramente a investigação operacional.
Reconciliar mensagens e pontos de recuperação
Exactly-once em Pub/Sub tem condições e não elimina a gestão correta de acknowledgments. No caso da aula, a pull subscription opera na mesma região, mas o ack ID expirou e é rejeitado com INVALID_ARGUMENT. Repetir esse ID indefinidamente não confirma a entrega atual. Gere prazos e reconcilia efeitos já produzidos antes de repetir trabalho de negócio. O máximo de tentativas de uma dead-letter policy é aproximado, mesmo com IAM correto; não o uses como contador exato de execuções. Para recuperação Cloud SQL, consulta a janela PITR efetiva e compara-a com o instante pedido. Catorze dias de backups não provam que todos os instantes desses dias têm os logs necessários para PITR. O exercício pede um inventário de evidência: identificador da entrega, estado do efeito, janela recuperável e decisão sobre perdas aceitáveis. Cada mecanismo deve ser avaliado segundo a garantia que oferece, mantendo o objetivo de negócio visível na decisão técnica.
Transformar incidentes em melhorias verificáveis
Um postmortem sem culpabilização mantém a sequência factual e procura condições que tornaram o erro possível. Se o operador seguiu um runbook aprovado sem validação do alvo, e dois ambientes tinham nomes quase iguais, repetir apenas o nome da pessoa não corrige o risco. Define ações que melhorem identificação, validação e ensaios, com responsável e evidência de conclusão. A governação de releases também precisa de regras explícitas. Uma política de error budget pode suspender features e permitir correções urgentes de segurança sob revisão própria. Aplicar essa exceção não significa renomear uma feature para contornar o limite. No exercício, analisa a política fictícia fornecida e classifica duas mudanças, justificando o caminho de aprovação de cada uma. Evita transformar uma política de exemplo do fornecedor numa regra universal para qualquer organização. O valor está em decisões consistentes, previamente acordadas, que liguem fiabilidade e risco ao trabalho que a equipa executa depois do incidente.
Preparar a aceitação e a continuidade entre turnos
Nos casos finais, o aluno deve explicar por que motivo o serviço ainda não pode ser aceite com a evidência apresentada. Um caso combina conteúdo errado e uma consulta que exclui eventos relevantes. O outro combina rollout com indisponibilidade, configuração inválida e confiança excessiva em PDB e auto-repair. Produz uma decisão curta com impacto, contenção, responsável e próxima condição de aceitação. Liga cada ação ao mecanismo correto e evita declarar recuperação apenas porque um recurso voltou a um estado administrativo esperado. Guarda os resultados do exercício local e explica a definição de percentil usada, para que outro colega reproduza o cálculo. No handover internacional, distingue factos confirmados, hipóteses abertas e operações em curso, incluindo efeitos que ainda precisam de reconciliação. Estes exercícios são originais e fictícios. O Python valida dados finitos locais; não executa Kubernetes, Prometheus, Pub/Sub ou Cloud SQL e não substitui ensaios autorizados no ambiente real.
"""Original finite-data exercise; no Prometheus or cloud service is executed."""
from math import ceil
from pathlib import Path
import hashlib
import json
import platform
def nearest_rank(values, percentile):
if not values or not isinstance(percentile, int) or not 1 <= percentile <= 100:
raise ValueError('Nonempty observations and an integer percentile 1..100 are required')
ordered = sorted(values)
return ordered[ceil(percentile * len(ordered) / 100) - 1]
def analyze(tail):
a = [10] * 95 + [tail] * 5
b = [20] * 94 + [100] * 6
local = [nearest_rank(a, 95), nearest_rank(b, 95)]
return {'counts': [len(a), len(b)], 'local_p95_ms': local,
'mean_local_p95_ms': sum(local) / 2,
'global_p95_ms': nearest_rank(a + b, 95)}
def main():
checks = []
def check(name, condition):
if not condition:
raise AssertionError(name)
checks.append(name)
high_tail = analyze(1000)
lower_tail = analyze(50)
check('both fixtures retain equal counts', high_tail['counts'] == lower_tail['counts'] == [100, 100])
check('both fixtures retain identical local percentiles', high_tail['local_p95_ms'] == lower_tail['local_p95_ms'] == [10, 100])
check('both averages are 55', high_tail['mean_local_p95_ms'] == lower_tail['mean_local_p95_ms'] == 55)
check('high tail gives global 100', high_tail['global_p95_ms'] == 100)
check('lower tail gives global 50', lower_tail['global_p95_ms'] == 50)
check('same retained summaries cannot determine global percentile', high_tail['global_p95_ms'] != lower_tail['global_p95_ms'])
check('mean of local percentiles fails in both fixtures', all(x['global_p95_ms'] != x['mean_local_p95_ms'] for x in [high_tail, lower_tail]))
boundary_cases = 0
for n in range(1, 41):
values = list(range(1, n + 1))
for percentile in [50, 90, 95, 99, 100]:
expected_rank = (percentile * n + 99) // 100
if nearest_rank(values, percentile) != expected_rank:
raise AssertionError((n, percentile))
if nearest_rank(list(reversed(values)), percentile) != expected_rank:
raise AssertionError(('order', n, percentile))
boundary_cases += 1
check('rank and ordering checks cover 200 finite cases', boundary_cases == 200)
outcomes = set()
for tail in range(11, 111):
result = analyze(tail)
if result['counts'] != [100, 100] or result['local_p95_ms'] != [10, 100]:
raise AssertionError(('summary', tail))
if result['global_p95_ms'] != max(20, min(tail, 100)):
raise AssertionError(('global', tail))
outcomes.add(result['global_p95_ms'])
check('100 tail variations preserve the retained summaries', len(range(11, 111)) == 100)
check('identical summaries allow 81 different global p95 values', len(outcomes) == 81)
for values, percentile in [([], 95), ([1], 0), ([1], 101), ([1], 95.5)]:
try:
nearest_rank(values, percentile)
except ValueError:
continue
raise AssertionError('invalid input was accepted')
check('invalid percentile inputs are rejected', True)
check('one observation has the same p95', nearest_rank([7], 95) == 7)
print(json.dumps({'scriptSha256': hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
'checks': len(checks), 'checkNames': checks,
'fixtures': {'highTail': high_tail, 'lowerTail': lower_tail},
'rankCases': boundary_cases, 'tailCases': 100, 'distinctGlobalResults': len(outcomes),
'python': platform.python_version(), 'vendorExecution': False,
'network': False, 'persistentWrites': False, 'independentVerification': False}, indent=2))
if __name__ == '__main__':
main()
Duas populações com as mesmas contagens e p95 locais podem ter p95 globais diferentes; um check HTTP verde também pode representar uma página errada.
Armadilhas comuns
Fazer média de percentis, omitir campos ausentes, atribuir ao PDB controlo universal de disponibilidade e confundir fecho de alerta ou nó Ready com recuperação.
Tópicos relacionados: Observabilidade e qualidade dos indicadores · Gestão de incidentes e aprendizagem operacional · Resiliência e recuperação de serviço
Conserva a informação necessária para interpretar cada sinal e demonstra recuperação no percurso funcional exigido pelo consumidor.
Referência: Prometheus query functions · Current linked standard guide; edition date unconfirmed (2026-09-30 inspection)