Metric#
Adicionado na versão 1.12.0.
O módulo ngx_stream_metric_module permite criar métricas
arbitrárias calculadas em tempo real para tráfego stream (TCP e UDP).
Esses valores de métricas são armazenados em memória compartilhada e
exibidos em tempo real no ramo da API /status/stream/metric_zones/.
Vários tipos de agregação de dados são suportados (contadores,
histogramas, médias móveis, etc.) com agrupamento por chaves arbitrárias.
Para o esquema da resposta, consulte a referência da API de zona de métricas stream.
Nota
Ao recarregar a configuração, uma zona criada por metric_zone ou
metric_complex_zone mantém seus valores acumulados apenas enquanto
seu layout de armazenamento não mudar. A zona começa vazia se o tamanho da
zona, o número de métricas ou um modo diferirem da configuração anterior,
se o count de average mean mudar, se o window de
average mean for alternado para ou de off, ou se o número
de buckets de histogram mudar; o motivo é então registrado no
log de erro no nível info. Outros parâmetros,
como o factor de average exp, o intervalo window de
average mean ou os limites dos buckets de histogram, podem
ser alterados sem perder os valores acumulados.
Ao compilar a partir do código-fonte, o módulo é
compilado por padrão junto com o módulo Stream
(habilitado com --with-stream); ele pode ser desabilitado com a
opção de compilação --without-stream_metric_module.
Em pacotes e imagens de nossos repositórios, o
módulo está incluído na compilação. Contando conexões por endereço de cliente: Se uma conexão for estabelecida na porta A métrica Calcula o valor da métrica para a zona de memória compartilhada especificada name. Parâmetros: key — uma string arbitrária (frequentemente uma variável) usada para agrupar valores.
O comprimento máximo é de 255 bytes; chaves mais longas são truncadas.
Na saída da API, o Angie anexa value — um número (pode ser uma variável) processado pelo modo
selecionado. Se omitido, o padrão é Se Se Se Várias diretivas Exemplo de uso: Nota Métricas com uma chave vazia ou com um par Isso é útil, por exemplo, para o modo Nota Lembre-se de que as variáveis são avaliadas em fases diferentes. Por
exemplo, é impossível usar Padrão — stream Define uma métrica complexa — um conjunto de métricas com modos
independentes. Cada linha no corpo do bloco define um nome de
submétrica, um modo e parâmetros opcionais do modo. O tamanho da
zona deve ser de pelo menos oito páginas de memória do sistema. Exemplo de uso: Na árvore da API, tal modelo de métrica complexa se parece com o seguinte: Padrão — stream Cria uma zona de memória compartilhada do size especificado com o
name fornecido para armazenar métricas. O nome da zona serve como um
nó no ramo Parâmetros: Se Se mode — algoritmo de processamento de dados (veja a seção Modos de Operação); parameters — configurações adicionais para o modo selecionado
(por exemplo, Exemplo de uso: Na árvore da API, o modelo de zona de memória compartilhada se parece com o seguinte: Nota Em uma zona de 1 MB, com um tamanho de chave de 39 bytes e um único
modo de métrica, aproximadamente 8.000 entradas de chaves únicas
podem ser armazenadas. Lista de modos de operação de métricas disponíveis: Os exemplos abaixo usam o endpoint Cada atualização da métrica incrementa o contador em Valor padrão — Exemplos: Atualizando a métrica: Valor esperado da métrica na API: O gauge aumenta ou diminui seu valor dependendo do sinal do número
informado. Um valor positivo aumenta o contador, enquanto um valor
negativo o diminui. Um valor de Valor padrão — Exemplos: Atualizando a métrica: Valor esperado da métrica na API: Atualizações adicionais: Valor esperado da métrica na API: Armazena o último valor recebido sem qualquer agregação. Se value for
omitido, Exemplos: Atualizando a métrica: Valor esperado da métrica na API: Atualizações adicionais: Valor esperado da métrica na API: Salva o mínimo de dois valores — o valor atualmente armazenado e o novo. Exemplos: Atualizando a métrica: Valor esperado da métrica na API: Salva o máximo de dois valores — o valor atualmente armazenado e o novo. Exemplos: Atualizando a métrica: Valor esperado da métrica na API: Calcula o valor médio usando o algoritmo de
suavização exponencial. Aceita um parâmetro opcional Quanto maior o coeficiente, mais peso os novos valores têm. Se você
especificar Exemplos: Atualizando a métrica: Valor esperado da métrica na API: Calcula a média aritmética. Aceita parâmetros opcionais
Nota Por exemplo, Exemplos: Atualizando a métrica: Valor esperado da métrica na API: Se você aguardar 5 segundos desde a última atualização, o valor esperado será: Cria um conjunto de "buckets", incrementando o contador correspondente
se o novo valor não exceder o limite do bucket. Os parâmetros são
fornecidos como uma lista de limites numéricos. Útil para analisar
distribuições, como durações de sessão. Os parâmetros obrigatórios são numbers — os valores de limite dos
buckets, normalmente listados em ordem crescente. Nota O valor de bucket Exemplos: Atualizando a métrica: Valor esperado da métrica na API: Atualizações adicionais: Valor esperado da métrica na API: Atualização adicional: Valor esperado da métrica na API: Variáveis são criadas para cada métrica: Para métricas complexas, uma variável adicional é adicionada: De forma semelhante à diretiva metric, o setter da
variável O setter aceita uma chave com um sufixo opcional Exemplo de uso: Após três conexões à porta Nota Ao ler Além disso, o valor armazenado na variável As variáveis Nota Para métricas complexas, os valores das submétricas na variável
Exemplo de uso: Com esta configuração, uma conexão à porta Uma conexão à porta Nota Se uma string vazia for atribuída a O cálculo ocorre somente depois que tanto Nesse caso, o valor armazenado em O valor em O valor em Para métricas complexas, o valor de uma submétrica específica pode ser
obtido usando a variável Exemplo de uso: Com esta configuração, uma conexão à porta Resposta: Resposta: Resposta: O Angie inclui um módulo Prometheus integrado para exibir
métricas no
formato Prometheus,
que suporta métricas personalizadas, incluindo aquelas coletadas no
lado stream. Como a exposição do Prometheus é um recurso exclusivo de
HTTP, as diretivas prometheus_template e
prometheus são configuradas em um bloco
Como exemplo de integração, considere a seguinte configuração: Após cinco conexões à porta Os valores da métrica serão: No formato Prometheus,
a métrica está disponível em Exemplo de configuração#
stream {
metric_zone connections:1m count;
server {
listen 12345;
metric connections $remote_addr on=connect;
}
}
http {
server {
listen 80;
location /status/ {
allow 127.0.0.1;
deny all;
api /status/;
}
}
}
12345:$ nc 127.0.0.1 12345 </dev/null
connections é atualizada em tempo real:{
"stream": {
"metric_zones": {
"connections": {
"discarded": 0,
"metrics": {
"127.0.0.1": 1
}
}
}
}
}
Diretivas#
metric#
... a toda chave de 255 bytes,
incluindo aquela cujo comprimento original era exatamente 255 bytes.
Uma chave pode, ela própria, conter caracteres = — apenas o
texto posterior ao último = é tratado como o valor, de modo
que tudo o que vem antes dele (incluindo qualquer =
incorporado) passa a fazer parte da chave;0. Se o parâmetro não
puder ser convertido para um número, o padrão é 1;on — um parâmetro opcional que especifica em qual ponto do
processamento da sessão a métrica é calculada:on=connect, o cálculo ocorre durante a fase
Pre-access, antes que qualquer dado seja lido do cliente;on=preread, o cálculo ocorre uma vez por sessão, quando os
primeiros dados do lado upstream — recebidos do servidor para o qual
foi feito proxy com proxy_pass, ou gerados por
return — são enviados ao cliente; nesse ponto,
módulos como proxy_protocol, ssl_preread
e mqtt_preread já processaram os dados iniciais do cliente;on=end (padrão), o cálculo ocorre durante a fase
Log, quando a sessão termina.metric podem ser especificadas no mesmo nível de
configuração. Essas diretivas são herdadas do nível de configuração anterior
se e somente se não houver diretivas metric definidas no nível atual.
Portanto, um único metric em um bloco server cancela todas as
regras herdadas de stream, em todos os três estágios on e não
apenas no seu próprio.metric sessions $remote_addr=$session_time on=end;
key=value inválido
são ignoradas. Um value omitido é tratado como 0:metric foo $bar; # Equivalente a $bar=0
count, que ignora
valores numéricos e simplesmente reage ao fato de que uma métrica foi
atualizada.$upstream_bytes_sent (bytes
enviados ao upstream) com on=connect (antes que a conexão
tenha sido encaminhada via proxy para algum destino).metric_complex_zone#
metric_complex_zone name:size [expire=on | off] [discard_key=name] { ... }metric_complex_zone sessions:1m expire=on discard_key="old" {
# nome submétrica modo parâmetros
min_time min;
avg_time average exp factor=60;
max_time max;
total count;
}
{
"discarded": 3,
"metrics": {
"key1": {
"min_time": 20,
"avg_time": 50,
"max_time": 80,
"total": 2
},
"old": {
"min_time": 3,
"avg_time": 40,
"max_time": 152,
"total": 80
}
}
}
metric_zone#
metric_zone name:size [expire=on | off] [discard_key=name] mode [parameters];/status/stream/metric_zones/.
O tamanho da zona deve ser de pelo menos oito páginas de memória do
sistema.expire=<on|off> — comportamento quando a zona está cheia:on, as métricas mais antigas (por tempo de atualização)
são descartadas para liberar memória para as novas;off (padrão) — as novas métricas recebidas são
descartadas, preservando as entradas existentes.discard_key=<name> — define uma métrica com a chave name
onde os valores das métricas descartadas são acumulados. Por padrão,
nenhuma métrica desse tipo é criada. A chave reservada não pode ser
atualizada manualmente.factor para average exp).metric_zone session_time:1m max;
{
"discarded": 0,
"metrics": {
"key1": 123,
"key2": 10.5
}
}
Modos de operação#
count — contador;gauge — medidor (incremento/decremento);last — o último valor recebido;min — valor mínimo;max — valor máximo;average exp — média móvel exponencial (EMA) (parâmetro factor);average mean — média sobre uma janela (parâmetros window e count);histogram — distribuição em "buckets" (uma lista de valores de limite)./status/ do
exemplo de configuração. Cada
resultado está disponível em
/status/stream/metric_zones/<zone>/metrics/.count#
1,
independentemente do valor fornecido.0.metric_zone count:1m count;
# Como parte de uma métrica complexa:
#
# metric_complex_zone count:1m {
# some_metric_name count;
# }
server {
listen 12345;
metric count KEY;
}
$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12345 </dev/null
{
"KEY": 4
}
gauge#
0 não altera o contador.0.metric_zone gauge:1m gauge;
# Como parte de uma métrica complexa:
#
# metric_complex_zone gauge:1m {
# some_metric_name gauge;
# }
server {
listen 12351;
metric gauge KEY;
}
server {
listen 12352;
metric gauge KEY=5;
}
server {
listen 12353;
metric gauge KEY=-5;
}
server {
listen 12354;
metric gauge KEY=8;
}
$ nc 127.0.0.1 12351 </dev/null
{
"KEY": 0
}
$ nc 127.0.0.1 12352 </dev/null
$ nc 127.0.0.1 12353 </dev/null
$ nc 127.0.0.1 12354 </dev/null
{
"KEY": 8
}
last#
0 é usado.metric_zone last:1m last;
# Como parte de uma métrica complexa:
#
# metric_complex_zone last:1m {
# some_metric_name last;
# }
server {
listen 12361;
metric last KEY;
}
server {
listen 12362;
metric last KEY=8000;
}
server {
listen 12363;
metric last KEY=37;
}
server {
listen 12364;
metric last KEY=-3.5;
}
$ nc 127.0.0.1 12361 </dev/null
{
"KEY": 0
}
$ nc 127.0.0.1 12362 </dev/null
$ nc 127.0.0.1 12363 </dev/null
$ nc 127.0.0.1 12364 </dev/null
{
"KEY": -3.5
}
min#
metric_zone min:1m min;
# Como parte de uma métrica complexa:
#
# metric_complex_zone min:1m {
# some_metric_name min;
# }
server {
listen 12371;
metric min KEY=42.999;
}
server {
listen 12372;
metric min KEY=-512;
}
server {
listen 12373;
metric min KEY=1;
}
$ nc 127.0.0.1 12371 </dev/null
$ nc 127.0.0.1 12372 </dev/null
$ nc 127.0.0.1 12373 </dev/null
{
"KEY": -512
}
max#
metric_zone max:1m max;
# Como parte de uma métrica complexa:
#
# metric_complex_zone max:1m {
# some_metric_name max;
# }
server {
listen 12381;
metric max KEY=42.999;
}
server {
listen 12382;
metric max KEY=-512;
}
server {
listen 12383;
metric max KEY=1;
}
$ nc 127.0.0.1 12381 </dev/null
$ nc 127.0.0.1 12382 </dev/null
$ nc 127.0.0.1 12383 </dev/null
{
"KEY": 42.999
}
average exp#
factor=<number> — um coeficiente que
determina o quanto o novo valor influencia a média. Valores inteiros de
0 a 99 são permitidos. O padrão é 90.90, o resultado será 90% do novo valor e
10% da média anterior.metric_zone avg_exp:1m average exp factor=60;
# Como parte de uma métrica complexa:
#
# metric_complex_zone avg_exp:1m {
# some_metric_name average exp factor=60;
# }
server {
listen 12391;
metric avg_exp KEY=100;
}
server {
listen 12392;
metric avg_exp KEY=200;
}
server {
listen 12393;
metric avg_exp KEY=0;
}
server {
listen 12394;
metric avg_exp KEY=8;
}
server {
listen 12395;
metric avg_exp KEY=30;
}
$ nc 127.0.0.1 12391 </dev/null
$ nc 127.0.0.1 12392 </dev/null
$ nc 127.0.0.1 12393 </dev/null
$ nc 127.0.0.1 12394 </dev/null
$ nc 127.0.0.1 12395 </dev/null
{
"KEY": 30.16
}
average mean#
window=<off|time> e count=<number>, definindo o
intervalo de tempo e o tamanho da amostra para cálculo da média,
respectivamente. Padrões: window=off (toda a amostra é usada) e
count=10.window=5s considerará apenas eventos dos
últimos 5 segundos. O parâmetro window não pode ser
0. O parâmetro count=number controla o tamanho da
amostra (valores em cache) para um cálculo de média mais suave.metric_zone avg_mean:1m average mean window=5s count=8;
# Como parte de uma métrica complexa:
#
# metric_complex_zone avg_mean:1m {
# some_metric_name average mean window=5s count=8;
# }
server {
listen 12401;
metric avg_mean KEY=0.1;
}
server {
listen 12402;
metric avg_mean KEY=0.4;
}
server {
listen 12403;
metric avg_mean KEY=10;
}
server {
listen 12404;
metric avg_mean KEY=1;
}
$ nc 127.0.0.1 12401 </dev/null
$ nc 127.0.0.1 12401 </dev/null
$ nc 127.0.0.1 12402 </dev/null
$ nc 127.0.0.1 12403 </dev/null
$ nc 127.0.0.1 12404 </dev/null
$ nc 127.0.0.1 12404 </dev/null
{
"KEY": 2.1
}
{
"KEY": 0
}
histogram#
inf ou +Inf pode ser usado para
capturar todos os valores que excedem o bucket mais alto
especificado.metric_zone hist:1m histogram 0.1 0.2 0.5 1 2 inf;
# Como parte de uma métrica complexa:
#
# metric_complex_zone hist:1m {
# some_metric_name histogram 0.1 0.2 0.5 1 2 inf;
# }
server {
listen 12411;
metric hist KEY=0.25;
}
server {
listen 12412;
metric hist KEY=2;
}
server {
listen 12413;
metric hist KEY=1000;
}
$ nc 127.0.0.1 12411 </dev/null
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 1,
"inf": 1
}
}
$ nc 127.0.0.1 12412 </dev/null
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 2,
"inf": 2
}
}
$ nc 127.0.0.1 12413 </dev/null
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 2,
"inf": 3
}
}
Variáveis integradas#
$metric_<name>$metric_<name>_key$metric_<name>_value$metric_<name>_value_<metric>$metric_<name>#$metric_<name> pode ser usado para atualizar uma
métrica. O cálculo ocorre quando a variável é definida — por exemplo,
por meio da diretiva set, que é avaliada durante a
fase Pre-access (a mesma etapa que
on=connect), ou de forma programática a partir do módulo
Stream JS, por exemplo em um manipulador
js_access.=value. O
último = separa a chave do valor; sem o sufixo, o valor é
0. A chave e o valor podem conter texto, variáveis, ou
combinações de ambos. Essas são as mesmas regras de análise usadas em
metric.stream {
metric_zone hits:1m count;
# Neste ponto, a variável $metric_hits é adicionada
server {
listen 12345;
metric hits client=1 on=connect;
}
server {
listen 12346;
set $metric_hits client=1;
return "$metric_hits\n";
}
}
12345 e uma conexão à porta
12346:$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12346 </dev/null
client=4
$metric_<name> de volta, obtém-se a chave junto com o
valor calculado atual da métrica, na forma key=value — e
não a string literal que foi atribuída. No exemplo acima, a conexão
atribui o valor literal client=1, mas como o modo
count ignora o valor atribuído e simplesmente incrementa a
cada atualização, ler $metric_hits posteriormente retorna
client=4 — o novo total do contador, que já inclui as três
atualizações anteriores feitas pela porta 12345.$metric_<name>_key
passa a ser a chave especificada.$metric_<name>_key e $metric_<name>_value#$metric_<name>_key e $metric_<name>_value
definem a chave e o valor, respectivamente. A atualização da métrica
ocorre quando $metric_<name>_value é definida, desde que a
chave em $metric_<name>_key já tenha sido definida.$metric_<name>_value são unidos usando um separador
", ".stream {
metric_zone level:1m gauge;
# As variáveis $metric_level, $metric_level_key e $metric_level_value são adicionadas aqui.
metric_complex_zone stats:1m {
count count;
min min;
avg average exp;
}
# $metric_stats, $metric_stats_key e $metric_stats_value são adicionadas aqui.
server {
listen 12345;
metric level sensor=10 on=connect;
}
server {
listen 12346;
set $metric_level_key "sensor";
set $metric_level_value 5;
# Ou: set $metric_level sensor=5;
return "Updated with '$metric_level'\nValue='$metric_level_value'\n";
}
server {
listen 12347;
set $metric_stats_key bar;
set $metric_stats_value 9;
# Ou: set $metric_stats bar=9;
return "Updated with '$metric_stats'\nValues='$metric_stats_value'\n";
}
}
12345 (que define o
valor inicial do gauge como 10) seguida de uma conexão à porta
12346 produz:$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12346 </dev/null
Updated with 'sensor=15'
Value='15'
12347 produz:$ nc 127.0.0.1 12347 </dev/null
Updated with 'bar=1, 9, 9'
Values='1, 9, 9'
$metric_<name>_value, o
valor é reconhecido como 0. Se a string for composta por
caracteres que não podem ser convertidos em um número, ela é
reconhecida como 1.$metric_<name>_key
quanto $metric_<name>_value tiverem sido definidas.$metric_<name> passa a ser
igual ao novo par calculado key=value, e não aos valores
literais recém-atribuídos.$metric_<name>_key representa a última chave
especificada por meio de variáveis.$metric_<name>_value representa o último valor
calculado para a chave definida em $metric_<name>_key.$metric_<name>_value_<metric>#$metric_<name>_value_<metric>, onde
<metric> é o nome da submétrica.stream {
metric_complex_zone foo:1m {
count count;
min min;
avg average exp;
}
# Adiciona $metric_foo, $metric_foo_key, $metric_foo_value,
# e $metric_foo_value_count, $metric_foo_value_min, $metric_foo_value_avg.
server {
listen 12345;
set $metric_foo_key bar;
set $metric_foo_value 9;
# Ou: set $metric_foo bar=9;
return "Updated with '$metric_foo'\nValues='$metric_foo_value'\nCount='$metric_foo_value_count'\n";
}
}
12345 produz:$ nc 127.0.0.1 12345 </dev/null
Updated with 'bar=1, 9, 9'
Values='1, 9, 9'
Count='1'
Exemplos adicionais#
Monitorando conexões por protocolo#
metric_zone protocols:1m count;
server {
listen 12345;
listen 12346 udp;
metric protocols $protocol;
}
{
"TCP": 340,
"UDP": 58
}
Distribuição do tempo de sessão do upstream#
metric_zone upstream_time:10m expire=on histogram
0.05 0.1 0.3 0.5 1 2 5 10 inf;
server {
listen 12345;
proxy_pass backend;
metric upstream_time $upstream_addr=$upstream_session_time on=end;
}
{
"discarded": 0,
"metrics": {
"backend1:8080": {
"0.05": 12,
"0.1": 28,
"0.3": 56,
"0.5": 78,
"1": 92,
"2": 97,
"5": 99,
"10": 100,
"inf": 100
}
}
}
Conexões ativas#
stream {
metric_zone active_connections:2m gauge;
server {
listen 12345;
metric active_connections service_a=1 on=connect;
metric active_connections service_a=-1 on=end;
}
server {
listen 12346;
metric active_connections service_b=1 on=connect;
metric active_connections service_b=-1 on=end;
}
}
http {
server {
listen 8080;
location /connections/ {
allow 127.0.0.1;
deny all;
api /status/stream/metric_zones/active_connections/metrics/;
}
}
}
{
"service_a": 42,
"service_b": 17
}
Suporte ao Prometheus#
http, fazendo referência à zona de métricas stream por meio da
mesma árvore unificada da API /status/.stream {
# Criando a métrica "upload"
metric_complex_zone upload:1m discard_key="other" {
stats histogram 64 256 1024 4096 16384 +Inf;
sum gauge;
count count;
avg_size average exp;
}
upstream backend {
server 127.0.0.1:15001;
}
server {
listen 12345;
# Atualizando a métrica ao final da sessão com o total
# de bytes recebidos do cliente
proxy_pass backend;
metric upload angie=$bytes_received on=end;
}
}
http {
# Descrevendo o template Prometheus para a métrica "upload"
prometheus_template upload_metric {
'stats{le="$1"}' $p8s_value
path=~^/stream/metric_zones/upload/metrics/angie/stats/(.+)$
type=histogram;
'stats_sum' $p8s_value
path=/stream/metric_zones/upload/metrics/angie/sum;
'stats_count' $p8s_value
path=/stream/metric_zones/upload/metrics/angie/count;
'avg_size' $p8s_value
path=/stream/metric_zones/upload/metrics/angie/avg_size;
}
server {
listen 80;
# Destino para coleta de métricas
location /prometheus/upload_metric/ {
prometheus upload_metric;
}
}
}
12345, enviando payloads de
16384, 64448, 64, 1028 e 1028
bytes:$ head -c 16384 /dev/urandom | nc 127.0.0.1 12345
$ head -c 64448 /dev/urandom | nc 127.0.0.1 12345
$ head -c 64 /dev/urandom | nc 127.0.0.1 12345
$ head -c 1028 /dev/urandom | nc 127.0.0.1 12345
$ head -c 1028 /dev/urandom | nc 127.0.0.1 12345
{
"stats": {
"64": 1,
"256": 1,
"1024": 1,
"4096": 3,
"16384": 4,
"+Inf": 5
},
"sum": 82952,
"count": 5,
"avg_size": 1077.9376
}
/prometheus/upload_metric/:# Angie Prometheus template "upload_metric"
# TYPE stats histogram
stats{le="64"} 1
stats{le="256"} 1
stats{le="1024"} 1
stats{le="4096"} 3
stats{le="16384"} 4
stats{le="+Inf"} 5
stats_sum 82952
stats_count 5
avg_size 1077.9376