Como usar o Prometheus para detectar anomalias no GitLab


Um dos recursos básicos da linguagem de consulta do Prometheus é a agregação em tempo real de séries temporais . Você também pode usar a linguagem de consulta do Prometheus para detectar anomalias nos dados de séries temporais. 

A equipe do Mail.ru Cloud Solutions traduziu um artigo do engenheiro da equipe de infraestrutura do GitLab , onde você encontrará exemplos de código que podem ser testados em seus sistemas.

Para que serve a detecção de anomalias?


Há quatro razões principais que determinam a importância da detecção de anomalias para o GitLab:

  1. Diagnóstico de incidentes : podemos detectar quais serviços foram além do escopo normal, reduzindo o tempo de detecção de incidentes (MTTD) e, consequentemente, oferecer uma solução mais rápida para o problema.
  2. Detecção de degradação do desempenho : por exemplo, se uma regressão é introduzida em um serviço que faz com que ele acesse outro serviço com muita frequência, podemos detectar e corrigir rapidamente esse problema.
  3. Detecção e eliminação de abuso : o GitLab fornece mecanismos de entrega e integração ( GitLab CI / CD ) e hospedagem (páginas do GitLab) e um número limitado de usuários que podem usar esses mecanismos.
  4. Segurança : a detecção de anomalias é importante para detectar tendências incomuns nas séries temporais do GitLab.

Por esses e outros motivos, o autor do artigo decidiu descobrir como configurar a definição de anomalias na série temporal do GitLab usando as regras e consultas do Prometheus.

Qual é o nível de agregação correto?


Primeiro, as séries temporais devem ser corretamente agregadas. No exemplo abaixo, usamos o contador http_requests_total padrão para recuperar dados, embora muitas outras métricas também o fizessem.

http_requests_total{
 job="apiserver",
 method="GET",
 controller="ProjectsController",
 status_code="200",
 environment="prod"
}

Essa métrica de teste possui vários parâmetros: método, controlador, código de status (status_code), ambiente, além de parâmetros adicionados pelo próprio Prometheus, por exemplo, trabalho e instância.

Agora você precisa escolher o nível certo de agregação de dados. Demais, de menos - tudo isso é importante para detectar anomalias. Se os dados estiverem muito agregados, há dois problemas em potencial:

  1. Você pode ignorar a anomalia porque a agregação oculta problemas que ocorrem em subconjuntos de seus dados.
  2. Se você encontrar uma anomalia, é difícil relacioná-la a uma parte separada do seu sistema sem esforço adicional.

Se os dados não forem agregados o suficiente, isso pode levar a um aumento no número de falsos positivos, bem como a uma interpretação incorreta dos dados válidos como errôneos.

Com base em nossa experiência, o nível de agregação mais correto é o nível de serviço, ou seja, incluímos o rótulo de trabalho (trabalho) e ambiente (ambiente) e descartamos todos os outros rótulos.

A agregação, que discutiremos ao longo do artigo, inclui: job - http_request, agregation - cinco minutos, que é calculado com base no trabalho e no ambiente em cinco minutos.

- record: job:http_requests:rate5m
expr: sum without(instance, method, controller, status_code)
(rate(http_requests_total[5m]))
# --> job:http_requests:rate5m{job="apiserver", environment="prod"}  21321
# --> job:http_requests:rate5m{job="gitserver", environment="prod"}  2212
# --> job:http_requests:rate5m{job="webserver", environment="prod"}  53091

A partir do exemplo acima, é claro que, da série http_requests_total, os subconjuntos são selecionados no contexto de trabalho e ambiente, então seu número é considerado por cinco minutos.

Usando o escore Z para detectar anomalias


Os princípios básicos da estatística podem ser aplicados para detectar anomalias.

Se você souber a média e o desvio padrão da série Prometheus, poderá usar qualquer amostra da série para calcular o escore z. 

O escore Z é uma medida do spread relativo do valor observado ou medido, que mostra quantos desvios padrão seu spread é relativo ao valor médio

Ou seja, o escore z = 0 significa que o escore z é idêntico ao valor médio no conjunto de dados com a distribuição padrão e o escore z = 1 significa que o desvio padrão = 1,0 da média.

Assumimos que os dados básicos têm uma distribuição normal, o que significa que 99,7% das amostras têm um escore z de 0 a 3. Quanto mais o escore z for zero, menor a probabilidade de existir. 

Aplicamos essa propriedade para detectar anomalias na série de dados do Prometheus:

  1. Calculamos a média e o desvio padrão da métrica usando dados com um tamanho de amostra grande. Neste exemplo, usamos dados semanais. Se assumirmos que os registros são avaliados uma vez por minuto, em uma semana teremos um pouco mais de 10.000 amostras.

    # Long-term average value for the series
    - record: job:http_requests:rate5m:avg_over_time_1w
    expr: avg_over_time(job:http_requests:rate5m[1w])
    
    # Long-term standard deviation for the series
    - record: job:http_requests:rate5m:stddev_over_time_1w
    expr: stddev_over_time(job:http_requests:rate5m[1w])

  2. Podemos calcular a pontuação z para a consulta Prometheus assim que obtivermos a média e o desvio padrão para agregação.

    # Z-Score for aggregation
    (
    job:http_requests:rate5m -
    job:http_requests:rate5m:avg_over_time_1w
    ) /  job:http_requests:rate5m:stddev_over_time_1w


Com base nos princípios estatísticos das distribuições normais, suponha que qualquer valor fora do intervalo de +3 a -3 seja uma anomalia. Dessa forma, podemos criar um aviso sobre essas anomalias. Por exemplo, receberemos um alerta quando nossa agregação ultrapassar esse intervalo por mais de cinco minutos.


Gráfico do número de solicitações por segundo para o serviço GitLab Pages por 48 horas. O escore Z no intervalo de +3 a -3 é destacado em

verde.O escore Z pode ser difícil de interpretar nos gráficos, pois esse valor não possui uma unidade de medida. Mas as anomalias neste gráfico são muito simples de determinar. Tudo o que vai além da zona verde, que mostra um corredor de valores com um escore z de -3 a +3, será um valor anômalo.

O que fazer se a distribuição de dados não for normal


Assumimos que a distribuição dos dados é normal. Caso contrário, nosso escore z será falso.

Existem muitos truques estatísticos para determinar a normalidade da distribuição dos dados, mas a melhor maneira é verificar se o escore z dos seus dados está no intervalo de -4,0 a +4,0.

Duas consultas do Prometheus que mostram escores z mínimos e máximos:

(
max_over_time(job:http_requests:rate5m[1w]) - avg_over_time(job:http_requests:rate5m[1w])
) / stddev_over_time(job:http_requests:rate5m[1w])
# --> {job="apiserver", environment="prod"}  4.01
# --> {job="gitserver", environment="prod"}  3.96
# --> {job="webserver", environment="prod"}  2.96

(
 min_over_time(job:http_requests:rate5m[<1w]) - avg_over_time(job:http_requests:rate5m[1w])
) / stddev_over_time(job:http_requests:rate5m[1w])
# --> {job="apiserver", environment="prod"}  -3.8
# --> {job="gitserver", environment="prod"}  -4.1
# --> {job="webserver", environment="prod"}  -3.2

Se seus resultados estiverem na faixa de -20 a +20, isso significa que muitos dados foram usados ​​e os resultados estão distorcidos. Lembre-se também de que você deve trabalhar com linhas agregadas. As métricas que não têm uma distribuição normal incluem parâmetros como taxa de erro, atraso, comprimento da fila e assim por diante. Mas muitas dessas métricas funcionarão melhor com limites de alerta fixos.

Detecção estatística de anomalias de sazonalidade


Embora o cálculo de escores z funcione bem com a distribuição normal de dados de séries temporais, existe um segundo método que pode fornecer resultados de detecção de anomalias ainda mais precisos. Esse é o uso da sazonalidade estatística. 

A sazonalidade é uma característica de uma métrica de série temporal quando essa métrica sofre alterações regulares e previsíveis que são repetidas em cada ciclo.


Gráfico de solicitações por segundo (RPS) de segunda a domingo por quatro semanas consecutivas O

gráfico acima ilustra o RPS (número de solicitações por segundo) por sete dias - de segunda a domingo, por quatro semanas consecutivas. Esse intervalo de sete dias é chamado de "deslocamento", ou seja, o padrão que será usado para a medição.

Cada semana no gráfico é de uma cor diferente. A sazonalidade dos dados é indicada pela seqüência nas tendências indicadas no gráfico - toda segunda-feira de manhã observamos um aumento semelhante no RPS e à noite na sexta-feira sempre observamos um decréscimo no RPS.

Usando a sazonalidade em nossos dados de séries temporais, podemos prever com mais precisão a ocorrência de anomalias e sua detecção. 

Como usar a sazonalidade


Prometeu usa vários mecanismos estatísticos diferentes para calcular a sazonalidade.

Primeiro, faça um cálculo, adicionando uma tendência de crescimento para a semana aos resultados da semana anterior. A tendência de crescimento é calculada da seguinte forma: subtraia a média móvel da última semana da média móvel da semana passada.

- record: job:http_requests:rate5m_prediction
  expr: >
    job:http_requests:rate5m offset 1w          # Value from last period
    + job:http_requests:rate5m:avg_over_time_1w # One-week growth trend
    — job:http_requests:rate5m:avg_over_time_1w offset 1w

A primeira iteração acaba sendo um pouco "estreita" - usamos a janela de cinco minutos desta semana e da semana anterior para obter nossas previsões.

Na segunda iteração, expandimos nossa cobertura, medindo a média do período de quatro horas da semana anterior e comparando-a com a semana atual. 

Portanto, se tentarmos prever o valor da métrica às oito da manhã da segunda-feira, em vez da mesma janela de cinco minutos da semana anterior, consideraremos o valor médio da métrica das seis às dez da manhã da segunda-feira anterior.

- record: job:http_requests:rate5m_prediction
  expr: >
    avg_over_time(job:http_requests:rate5m[4h] offset 166h) # Rounded value from last period
    + job:http_requests:rate5m:avg_over_time_1w    # Add 1w growth trend
    - job:http_requests:rate5m:avg_over_time_1w offset 1w

A solicitação indicou 166 horas, ou seja, duas horas a menos que uma semana inteira (7 * 24 = 168), já que queremos usar um período de quatro horas com base no horário atual, portanto, precisamos que o deslocamento seja duas horas a menos que uma semana inteira. 


RPS real (amarelo) e previsto (azul) em duas semanas

Uma comparação do RPS real com nossa previsão mostra que nossos cálculos foram razoavelmente precisos. No entanto, este método tem uma desvantagem.
 
Por exemplo, em 1º de maio, o GitLab foi usado menos do que o habitual às quartas-feiras, pois esse dia era de folga. Como a tendência estimada de crescimento depende de como o sistema foi usado na semana anterior, nossas previsões para a próxima semana, ou seja, na quarta-feira, 8 de maio, deram um RPS menor do que realmente.

Esse erro pode ser corrigido fazendo três previsões por três semanas consecutivas antes da quarta-feira, 1º de maio, ou seja, as três quartas-feiras anteriores. A solicitação permanece a mesma, mas o deslocamento é ajustado.

- record: job:http_requests:rate5m_prediction
  expr: >
   quantile(0.5,
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 166h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 1w
       , "offset", "1w", "", "")
     or
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 334h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 2w
       , "offset", "2w", "", "")
     or
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 502h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 3w
       , "offset", "3w", "", "")
   )
   without (offset)


Há três previsões no gráfico para três semanas antes de 8 de maio, em comparação com o RPS real de quarta-feira, 8 de maio. Você pode ver que as duas previsões são muito precisas, mas a previsão para a semana de 1º de maio permanece imprecisa

Além disso, não precisamos de três previsões, precisamos de uma previsão. O valor médio não é uma opção, pois será borrado pelos nossos dados RPS distorcidos de 1º de maio. Em vez disso, você precisa calcular a mediana. Prometheus não possui uma consulta mediana, mas podemos usar agregação quantil em vez da mediana.

O único problema é que estamos tentando incluir três séries na agregação, e essas três séries são na verdade a mesma série em três semanas. Em outras palavras, eles têm os mesmos rótulos, por isso é difícil reuni-los. 

Para evitar confusão, criamos um rótulo chamado deslocamento e usamos a função de substituição de rótulo para adicionar um deslocamento a cada uma das três semanas. Então, na agregação quantil, descartamos esses rótulos, e isso nos dá uma média de três.

- record: job:http_requests:rate5m_prediction
  expr: >
   quantile(0.5,
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 166h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 1w
       , "offset", "1w", "", "")
     or
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 334h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 2w
       , "offset", "2w", "", "")
     or
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 502h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 3w
       , "offset", "3w", "", "")
   )
   without (offset)

Agora, nossa previsão com uma mediana de três agregações se tornou mais precisa.


Previsão mediana versus RPS real

Como descobrir que nossa previsão é realmente precisa


Para verificar a precisão da previsão, podemos retornar ao z-score. É usado para medir a discrepância da amostra com sua previsão em desvios-padrão. Quanto maior o desvio padrão em relação à previsão, maior a probabilidade de um valor específico ser extraviado.


O intervalo de desvio projetado é de +1,5 a -1,5.

Você pode alterar nosso gráfico Grafana para usar uma previsão sazonal, em vez de uma média móvel semanal. O intervalo de valores normais para uma hora específica do dia está sombreado em verde. Tudo o que vai além da zona verde é considerado um desvio. Nesse caso, o erro ocorreu na tarde de domingo, quando nosso provedor de nuvem teve alguns problemas de rede.

É uma boa prática usar um escore z de ± 2 para previsões sazonais.

Como configurar alertas com o Prometheus


Se você deseja configurar um alerta para eventos anormais, pode aplicar a regra do Prometheus bastante simples, que verifica se o escore z de um indicador está no intervalo entre +2 e -2.

- alert: RequestRateOutsideNormalRange
  expr: >
   abs(
     (
       job:http_requests:rate5m - job:http_requests:rate5m_prediction
     ) / job:http_requests:rate5m:stddev_over_time_1w
   ) > 2
  for: 10m
  labels:
    severity: warning
  annotations:
    summary: Requests for job {{ $labels.job }} are outside of expected operating parameters

No GitLab, usamos uma regra de roteamento personalizada que envia um alerta pelo Slack quando detecta anomalias, mas não entra em contato com nossa equipe de suporte.

Como detectar anomalias no GitLab usando o Prometheus


  1. Prometheus pode ser usado para detectar algumas anormalidades.
  2. A agregação adequada é a chave para encontrar anomalias.
  3. A pontuação Z é efetiva se seus dados tiverem uma distribuição normal.
  4. A sazonalidade estatística é um mecanismo poderoso para detectar anomalias.

Traduzido com suporte do Mail.ru Cloud Solutions .

Ainda útil :

  1. Métodos de cache simples no IC do GitLab: um guia de imagens .
  2. Ferramentas GitLab CE prontas e personalizadas no mercado MCS
  3. Nosso canal Telegram sobre transformação digital .

All Articles