Como calcular percentil em Real-Time Analytics: passo a passo
Aprende a calcular percentis em Real-Time Analytics para monitorizar métricas de latência e desempenho em streaming. Saber calcular percentis (p.ex. P50, P95, P99) em tempo real ajuda a identificar degradações que a média não mostra: por exemplo, uma média de 120 ms pode esconder que P95 = 450 ms, o que significa que 5% dos pedidos estão muito lentos e afetam a experiência do utilizador.
Pré-requisitos
- Conta com acesso a um serviço que suporte consultas em streaming (ex.: Azure Data Explorer/ADX, também aplicável a outros motores que suportem KQL).
- Dados de telemetria com timestamp e um campo numérico (p.ex. latency_ms). Idealmente os eventos têm event time e ingestion time para gerir latência e reordenações.
- Conhecimentos básicos de KQL (filtros, extend, summarize).
- Capacidade de ingestão adequada — por exemplo 1k–10k eventos/s para pequenos setups; para maiores volumes considera partição e compressão.
- Política de retenção e janelas definidas (p.ex. 7 dias de dados, agregações por minuto para dashboards em tempo real).
Passo 1: Estruturar o stream com timestamps e partições
É essencial garantir que os eventos têm timestamps correctos (event time) e, se necessário, uma chave de partição (p.ex. region ou service). Eventos com timestamps errados criam janelas com zeros ou sobreposições. Para streaming em produção, aplica watermarking de 30s–2m conforme a confiança do relógio dos produtores. Partições como service ou region permitem calcular percentis por segmento sem cruzar tráfego heterogéneo.
// Exemplo: dados simulados para testar
let telemetry = datatable(Timestamp:datetime, service:string, latency_ms:double)
[
datetime(2026-08-21 10:00:01), "api-a", 120.5,
datetime(2026-08-21 10:00:02), "api-a", 95.0,
datetime(2026-08-21 10:00:03), "api-b", 300.2,
datetime(2026-08-21 10:00:04), "api-a", 110.1
];
telemetry
Passo 2: Escolher janela temporal e estratégia (disjoint vs sliding)
Decide se queres janelas disjuntas (tumbling) ou janelas móveis (sliding). Janelas tumbling (ex.: 1 minuto) dão agregados simples e são eficientes para relatórios periódicos. Janelas sliding (ex.: janela de 5 minutos com passo de 1 minuto) fornecem percentis mais suaves e contínuos, mas custam mais porque sobrepõem cálculos — tipicamente ~N vezes mais trabalho onde N é o número de passos por janela. Por exemplo, uma janela sliding de 5m com passo de 1m implica calcular 5 vezes mais agregações do que tumbling 1m.
// Tumbling de 1 minuto
telemetry
| where Timestamp > ago(15m)
| summarize percentiles(latency_ms, 50, 95, 99) by bin(Timestamp, 1m), service
// Sliding de 5 minutos com passo de 1 minuto (usar range de bins recorrentes)
telemetry
| where Timestamp > ago(15m)
| serialize
| extend window_start = bin(Timestamp, 1m)
| summarize percentiles(latency_ms, 50, 95, 99) by window_start, service
| order by window_start asc
Passo 3: Usar a função percentiles correctamente
A função percentiles (ou percentileif/percentile conforme o motor) calcula percentis de forma eficiente. Em ADX, percentiles aceita múltiplos percentis como argumentos. Para grandes volumes, considera algoritmos aproximados (TDigest, sketches) ou reduzir a precisão para diminuir custo e latência. Ex.: usar aproximação que dá erro típico de ±1–2% nos quantis para grandes amostras.
// Percentis P50, P95, P99 por serviço por minuto
telemetry
| where Timestamp > ago(30m)
| summarize percentiles(latency_ms, 50, 95, 99) by bin(Timestamp, 1m), service
| project Timestamp, service, P50=latency_ms_50, P95=latency_ms_95, P99=latency_ms_99
Passo 4: Lidar com cardinalidade e outliers
Percentis podem ser pouco fiáveis com poucas amostras. Define um limiar de confiança: por exemplo, cnt >= 10 para visibilidade básica, cnt >= 30 para estatística razoável e cnt >= 100 para alta confiança. Filtra valores inválidos (negativos, ultra-altos por erro) e marca janelas com baixa contagem. Para outliers extremos, podes truncar valores acima de um SLA (ex.: latency_ms > 60s) ou aplicar winsorizing.
// Filtrar valores negativos, calcular contagem e aplicar limiar mínimo de amostras
telemetry
| where Timestamp > ago(30m) and latency_ms >= 0 and latency_ms < 60000
| summarize cnt=count(), percentiles(latency_ms, 50, 95, 99) by bin(Timestamp, 1m), service
| where cnt >= 10
| project Timestamp, service, cnt, P50=latency_ms_50, P95=latency_ms_95, P99=latency_ms_99
Passo 5: Agregar e exportar para dashboards em tempo real
Exporta os resultados para um painel (p.ex. Power BI, Grafana) ou grava numa tabela de agregados para históricos. Em ADX podes usar o connector Power BI para dados em near real-time ou armazenar agregados com .set-or-append / update policy para evitar refazer cálculos. Avalia o custo: agregações por minuto para 100 serviços durante 24h resultam em ~144k janelas/dia; optimiza reduzindo resolução ou usando sketches.
// Exemplo simplificado: escrever para uma tabela de agregados (pseudo-sintaxe)
let aggreg =
telemetry
| where Timestamp > ago(30m) and latency_ms >= 0
| summarize cnt=count(), percentiles(latency_ms, 50, 95, 99) by bin(Timestamp, 1m), service;
// Em ADX, podes usar .set-or-append para gravar numa tabela existente
// .set-or-append Aggregates <| aggreg
Verificar o resultado
Confirma que tens linhas por cada janela e que cnt (contagem) faz sentido. Compara percentis com um histograma (bins de 10–50 ms) para validar forma da distribuição. Erros comuns: eventos com timestamps no futuro/antes causando janelas vazias, contagens baixas e percentis NaN, e janelas com valores anómalos por reenvios. Se P95/P99 variarem muito em curto espaço, investiga causas (deploy, GC, overload).
Conclusão
Calcular percentis em Real-Time Analytics permite medir a experiência real do utilizador e detectar regressões que a média não mostra. Próximos passos: experimentar janelas sliding para visibilidade contínua, usar TDigest/sketches para reduzir custos em grandes volumes, e integrar com alertas (ex.: alertar se P95 > 300 ms por 3 janelas consecutivas). Decide qual percentil usar consoante o teu SLA — P95 é útil para latências gerais, P99 para spikes raros.