Metric#
Adicionado na versão 1.11.0.
O módulo ngx_http_metric_module permite criar métricas arbitrárias calculadas
em tempo real. Esses valores de métricas são armazenados em memória compartilhada e exibidos
em tempo real no ramo da API /status/http/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.
Ao compilar a partir do código-fonte, o módulo é
compilado por padrão; ele pode ser desabilitado com a opção de
compilação --without-http_metric_module.
Em pacotes e imagens de nossos repositórios, o módulo está incluído na compilação.
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.
Exemplo de configuração#
Contando requisições de API:
http {
metric_zone api_requests:1m count;
server {
listen 80;
location /api/ {
allow 127.0.0.1;
deny all;
api /status/;
metric api_requests $http_user_agent on=request;
}
}
}
Se uma requisição for feita para /api/ com esta configuração:
$ curl 127.0.0.1/api/ --user-agent "Firefox"
A métrica api_requests é atualizada em tempo real:
{
"http": {
"metric_zones": {
"api_requests": {
"discarded": 0,
"metrics": {
"Firefox": 1
}
}
}
}
}
Diretivas#
metric#
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. Se a chave for maior, ela será truncada para 255 bytes e anexada com reticências
...;value — um número (pode ser uma variável) processado pelo modo selecionado. Se omitido, o padrão é
0. Se o parâmetro não puder ser convertido para um número, o padrão é1;on— um parâmetro opcional especificando quando a métrica é calculada:Se
on=request, o cálculo ocorre quando a requisição é recebida;Se
on=response, o cálculo ocorre durante a preparação da resposta;Se
on=end(padrão), o cálculo ocorre após o envio da resposta.
Nota
No caso de redirecionamento interno, métricas no estágio on=request
são calculadas no location original. No entanto,
métricas on=response e on=end serão calculadas
no novo location.
Várias diretivas 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 location cancela todas as
regras herdadas de server ou http, em todos os três estágios on e não
apenas no seu próprio.
Exemplo de uso:
metric requests $http_user_agent=$request_time;
Nota
Métricas com uma chave vazia ou um par key=value inválido são ignoradas.
Um value omitido é tratado como 0:
metric foo $bar; # Equivalente a $bar=0
Isso é útil, por exemplo, para o modo count, que ignora
valores numéricos e simplesmente reage ao fato de que uma métrica foi atualizada.
Nota
Lembre-se de que variáveis são avaliadas em diferentes fases. Por exemplo,
é impossível usar $bytes_sent (bytes enviados ao cliente)
com on=request (quando a requisição é recebida).
metric_complex_zone#
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: 32K quando o tamanho da página é 4K.
Exemplo de uso:
metric_complex_zone requests: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;
}
Na árvore da API, tal modelo de métrica complexa se parece com o seguinte:
{
"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
}
}
}
| Número; a contagem de métricas descartadas na zona de memória compartilhada |
| Objeto; seus membros são métricas complexas com chaves definidas. Eles são objetos contendo um conjunto de submétricas com valores calculados |
metric_zone#
| |
Padrão | — |
http |
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 /status/http/metric_zones/.
O tamanho da zona deve ser de pelo menos oito páginas de memória do sistema:
32K quando o tamanho da página é 4K.
Parâmetros:
expire=<on|off>— comportamento quando a zona está cheia:Se
on, as métricas mais antigas (por tempo de atualização) são descartadas para liberar memória para novas;Se
off(padrão) — novas métricas recebidas são descartadas, preservando as entradas existentes.
discard_key=<name>— define uma métrica com a chave name onde valores de métricas descartadas são acumulados. Por padrão, nenhuma métrica desse tipo é criada. A chave reservada não pode ser atualizada manualmente.mode — algoritmo de processamento de dados (veja a seção Modos de Operação);
parameters — configurações adicionais para o modo selecionado (por exemplo,
factorparaaverage exp).
Exemplo de uso:
metric_zone request_time:1m max;
Na árvore da API, o modelo de zona de memória compartilhada se parece com o seguinte:
{
"discarded": 0,
"metrics": {
"key1": 123,
"key2": 10.5,
}
}
| Número; a contagem de métricas descartadas na zona de memória compartilhada |
| Objeto; seus membros são métricas com chaves definidas e valores calculados |
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.
Modos de operação#
Lista de modos de operação de métricas disponíveis:
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âmetrofactor);average mean— média sobre uma janela (parâmetroswindowecount);histogram— distribuição em "buckets" (uma lista de valores de limite).
count#
O contador aumenta seu valor em 1 a cada atualização de métrica.
Valor padrão — 0.
Nota
Qualquer atualização de métrica (com qualquer valor) aumenta monotonicamente o contador em 1.
Exemplos:
metric_zone count:1m count;
# Como parte de uma métrica complexa:
#
# metric_complex_zone count:1m {
# some_metric_name count;
# }
server {
listen 80;
location /metric/ {
metric count KEY;
}
location ~ ^/metric/set/(.+)$ {
metric count KEY=$1;
}
location /api/ {
api /status/http/metric_zones/count/metrics/;
}
}
Atualizando a métrica:
$ curl 127.0.0.1/metric/
$ curl 127.0.0.1/metric/set/1
$ curl 127.0.0.1/metric/set/23
$ curl 127.0.0.1/metric/set/-32
Valor esperado da métrica na API:
{
"KEY": 4
}
gauge#
O gauge aumenta ou diminui seu valor dependendo do sinal do número
passado. Um valor positivo aumenta o contador, enquanto um valor
negativo o diminui. Um valor de 0 não altera o contador.
Valor padrão — 0.
Exemplos:
metric_zone gauge:1m gauge;
# Como parte de uma métrica complexa:
#
# metric_complex_zone gauge:1m {
# some_metric_name gauge;
# }
server {
listen 80;
location /metric/ {
metric gauge KEY;
}
location ~ ^/metric/set/(.+)$ {
metric gauge KEY=$1;
}
location /api/ {
api /status/http/metric_zones/gauge/metrics/;
}
}
Atualizando a métrica:
$ curl 127.0.0.1/metric/
Valor esperado da métrica na API:
{
"KEY": 0
}
Atualizações adicionais:
$ curl 127.0.0.1/metric/set/5
$ curl 127.0.0.1/metric/set/-5
$ curl 127.0.0.1/metric/set/8
Valor esperado da métrica na API:
{
"KEY": 8
}
last#
Armazena o último valor recebido sem qualquer agregação. Se value for
omitido, 0 é usado.
Exemplos:
metric_zone last:1m last;
# Como parte de uma métrica complexa:
#
# metric_complex_zone last:1m {
# some_metric_name last;
# }
server {
listen 80;
location /metric/ {
metric last KEY;
}
location ~ ^/metric/set/(.+)$ {
metric last KEY=$1;
}
location /api/ {
api /status/http/metric_zones/last/metrics/;
}
}
Atualizando a métrica:
$ curl 127.0.0.1/metric/
Valor esperado da métrica na API:
{
"KEY": 0
}
Atualizações adicionais:
$ curl 127.0.0.1/metric/set/8000
$ curl 127.0.0.1/metric/set/37
$ curl 127.0.0.1/metric/set/-3.5
Valor esperado da métrica na API:
{
"KEY": -3.5
}
min#
Salva o mínimo de dois valores — o valor atualmente armazenado e o novo.
Exemplos:
metric_zone min:1m min;
# Como parte de uma métrica complexa:
#
# metric_complex_zone min:1m {
# some_metric_name min;
# }
server {
listen 80;
location /metric/ {
metric min KEY;
}
location ~ ^/metric/set/(.+)$ {
metric min KEY=$1;
}
location /api/ {
api /status/http/metric_zones/min/metrics/;
}
}
Atualizando a métrica:
$ curl 127.0.0.1/metric/set/42.999
$ curl 127.0.0.1/metric/set/-512
$ curl 127.0.0.1/metric/set/1
$ curl 127.0.0.1/metric/
Valor esperado da métrica na API:
{
"KEY": -512
}
max#
Salva o máximo de dois valores — o valor atualmente armazenado e o novo.
Exemplos:
metric_zone max:1m max;
# Como parte de uma métrica complexa:
#
# metric_complex_zone max:1m {
# some_metric_name max;
# }
server {
listen 80;
location /metric/ {
metric max KEY;
}
location ~ ^/metric/set/(.+)$ {
metric max KEY=$1;
}
location /api/ {
api /status/http/metric_zones/max/metrics/;
}
}
Atualizando a métrica:
$ curl 127.0.0.1/metric/set/42.999
$ curl 127.0.0.1/metric/set/-512
$ curl 127.0.0.1/metric/set/1
$ curl 127.0.0.1/metric/
Valor esperado da métrica na API:
{
"KEY": 42.999
}
average exp#
Calcula o valor médio usando o algoritmo de suavização exponencial.
Aceita um parâmetro opcional 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.
Quanto maior o coeficiente, mais peso os novos valores têm. Se você especificar
90, o resultado será 90% do novo valor e 10%
da média anterior.
Exemplos:
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 80;
location ~ ^/metric/set/(.+)$ {
metric avg_exp KEY=$1;
}
location /api/ {
api /status/http/metric_zones/avg_exp/metrics/;
}
}
Atualizando a métrica:
$ curl 127.0.0.1/metric/set/100
$ curl 127.0.0.1/metric/set/200
$ curl 127.0.0.1/metric/set/0
$ curl 127.0.0.1/metric/set/8
$ curl 127.0.0.1/metric/set/30
Valor esperado da métrica na API:
{
"KEY": 30.16
}
average mean#
Calcula a média aritmética. Aceita parâmetros opcionais
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.
Nota
Por exemplo, 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.
Exemplos:
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 80;
location ~ ^/metric/set/(.+)$ {
metric avg_mean KEY=$1;
}
location /api/ {
api /status/http/metric_zones/avg_mean/metrics/;
}
}
Atualizando a métrica:
$ curl 127.0.0.1/metric/set/0.1
$ curl 127.0.0.1/metric/set/0.1
$ curl 127.0.0.1/metric/set/0.4
$ curl 127.0.0.1/metric/set/10
$ curl 127.0.0.1/metric/set/1
$ curl 127.0.0.1/metric/set/1
Valor esperado da métrica na API:
{
"KEY": 2.1
}
Se você aguardar 5 segundos desde a última atualização, o valor esperado será:
{
"KEY": 0
}
histogram#
Cria um conjunto de "buckets", incrementando o contador relevante 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 tempos de resposta.
Parâmetros obrigatórios são numbers — os valores de limite dos buckets, listados em ordem crescente.
Nota
O valor de bucket inf ou +Inf pode ser usado para capturar todos
os valores que excedem o bucket mais alto especificado.
Exemplos:
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 80;
location ~ ^/metric/set/(.+)$ {
metric histogram KEY=$1;
}
location /api/ {
api /status/http/metric_zones/hist/metrics/;
}
}
Atualizando a métrica:
$ curl 127.0.0.1/metric/set/0.25
Valor esperado da métrica na API:
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 1,
"inf": 1
}
}
Atualizações adicionais:
$ curl 127.0.0.1/metric/set/2
Valor esperado da métrica na API:
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 2,
"inf": 2
}
}
Atualização adicional:
$ curl 127.0.0.1/metric/set/1000
Valor esperado da métrica na API:
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 2,
"inf": 3
}
}
Variáveis integradas#
Variáveis são criadas para cada métrica:
$metric_<name>$metric_<name>_key$metric_<name>_value
Para métricas complexas, uma variável adicional é adicionada:
$metric_<name>_value_<metric>
$metric_<name>#
Semelhante à diretiva metric, a variável setter $metric_<name>
pode ser usada para atualizar uma métrica. O cálculo ocorre durante a
fase de Rewrite,
permitindo o processamento de métricas a partir do módulo njs, por exemplo.
O valor usado para definir a variável deve seguir a estrutura chave=valor.
Tanto a chave quanto o valor podem consistir em texto, variáveis e combinações destes.
A chave é uma string arbitrária para agrupar valores. O valor é um número
processado pelo modo selecionado. Se omitido, o padrão é 0.
Se o parâmetro não puder ser convertido para um número, o padrão é 1.
Exemplo de uso:
http {
metric_zone counter:1m count;
# Neste ponto, a variável $metric_counter é adicionada
server {
listen 80;
location /metric/ {
set $metric_counter $http_user_agent; # Equivalente a $http_user_agent=0
}
location /api/ {
allow 127.0.0.1;
deny all;
api /status/http/metric_zones/counter/;
}
}
}
Calculando métricas usando o módulo njs:
http {
js_import metrics.js;
resolver 127.0.0.53;
metric_complex_zone requests:1m {
min_time min;
max_time max;
total count;
}
location /metric/ {
js_content metrics.js_request;
js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
}
location /api/ {
allow 127.0.0.1;
deny all;
api /static/http/metric_zones/requests/;
}
}
Arquivo metrics.js:
async function js_request(r) {
let start_time = Date.now();
let results = await Promise.all([ngx.fetch('https://google.com/'),
ngx.fetch('https://google.ru/')]);
// Usando a variável setter $metric_requests
r.variables.metric_requests = `google={Date.now() - start_time}`;
}
export default {js_request};
Após várias requisições para location /metric/, os valores podem parecer assim:
{
"discarded": 0,
"metrics": {
"google": {
"min_time": 70,
"max_time": 432,
"total": 6
}
}
}
Nota
Após definir a variável, você pode recuperar seu valor; ele será igual
ao par chave=valor especificado.
Além disso, o valor armazenado na variável $metric_<name>_key
mudará para a chave especificada.
$metric_<name>_key e $metric_<name>_value#
As variáveis $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.
Nota
Para métricas complexas, os valores das submétricas na variável $metric_<name>_value
são unidos usando um separador ", ".
Exemplo de uso:
http {
metric_zone gauge:1m gauge;
# As variáveis $metric_gauge, $metric_gauge_key e $metric_gauge_value são adicionadas aqui.
metric_complex_zone complex:1m {
hist histogram 1 2 3;
avg average exp;
}
# $metric_complex, $metric_complex_key e $metric_complex_value são adicionadas aqui.
server {
listen 80;
location /gauge/ {
set $metric_gauge_key "foo";
set $metric_gauge_value 1;
# Ou: set $metric_gauge foo=1;
return 200 "Updated with '$metric_gauge'\nValue='$metric_gauge_value'\n";
}
location /complex/ {
set $metric_complex_key "foo";
set $metric_complex_value 3;
# Ou: set $metric_complex foo=3;
return 200 "Updated with '$metric_complex'\nValue='$metric_complex_value'\n";
}
}
}
Com esta configuração, uma requisição para /gauge/ produz:
$ curl 127.0.0.1/gauge/
Updated with 'foo=1'
Value='1'
Para /complex/:
$ curl 127.0.0.1/complex/
Updated with 'foo=3'
Value='0 0 1, 3'
Nota
Se uma string vazia for atribuída a $metric_<name>_value, o valor é
reconhecido como 0. Se a string consistir em caracteres que não podem ser
convertidos para um número, ela é reconhecida como 1.
O cálculo ocorre apenas após $metric_<name>_key e
$metric_<name>_value terem sido definidas.
Neste caso, o valor armazenado em $metric_<name> torna-se igual
ao novo par chave=valor.
O valor em $metric_<name>_key representa a última chave especificada
via variáveis.
O valor em $metric_<name>_value representa o último valor calculado
para a chave definida em $metric_<name>_key.
$metric_<name>_value_<metric>#
Para métricas complexas, o valor de uma submétrica específica pode ser recuperado
usando a variável $metric_<name>_value_<metric>, onde
<metric> é o nome da submétrica.
Exemplo de uso:
http {
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 80;
location /foo/ {
set $metric_foo_key bar;
set $metric_foo_value 9;
# Ou: set $metric_foo bar=9;
return 200 "Updated with '$metric_foo'\nValues='$metric_foo_value'\nCount='$metric_foo_value_count'\n";
}
}
}
Com esta configuração, uma requisição para /foo/ produz:
$ curl 127.0.0.1/foo/
Updated with 'bar=9'
Values='1, 9, 9'
Count='1'
Exemplos adicionais#
Monitorando métodos HTTP#
metric_zone http_methods:1m count;
server {
listen 80;
location / {
metric http_methods $request_method;
}
location /metrics/ {
allow 127.0.0.1;
deny all;
api /status/http/metric_zones/http_methods/metrics/;
}
}
Resposta:
{
"GET": 65,
"POST": 20,
"PUT": 10,
"DELETE": 5
}
Distribuição do tempo de resposta 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 80;
location /backend/ {
proxy_pass http://backend;
metric upstream_time $upstream_addr=$upstream_response_time on=end;
}
location /metrics/ {
allow 127.0.0.1;
deny all;
api /status/http/metric_zones/upstream_time/;
}
}
Resposta:
{
"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#
metric_zone active_connections:2m gauge;
server {
listen 80;
server_name site1.com;
location / {
# Incrementamos ao conectar
metric active_connections site1=1 on=request;
# Decrementamos ao finalizar
metric active_connections site1=-1 on=end;
}
}
server {
listen 80;
server_name site2.com;
location / {
metric active_connections site2=1 on=request;
metric active_connections site2=-1 on=end;
}
}
server {
listen 8080;
location /connections/ {
allow 127.0.0.1;
deny all;
api /status/http/metric_zones/active_connections/metrics;
}
}
Resposta:
{
"site1": 42,
"site2": 17
}
Suporte ao Prometheus#
O Angie inclui um módulo Prometheus integrado para exibir métricas no formato Prometheus, que suporta métricas personalizadas.
Como exemplo de integração, considere a seguinte configuração:
http {
# 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;
}
# Descrevendo o template Prometheus para a métrica "upload"
prometheus_template upload_metric {
'stats{le="$1"}' $p8s_value
path=~^/http/metric_zones/upload/metrics/angie/stats/(.+)$
type=histogram;
'stats_sum' $p8s_value
path=/http/metric_zones/upload/metrics/angie/sum;
'stats_count' $p8s_value
path=/http/metric_zones/upload/metrics/angie/count;
'avg_size' $p8s_value
path=/http/metric_zones/upload/metrics/angie/avg_size;
}
server {
listen 80;
# Atualizando a métrica
location ~ ^/upload/(.*)$ {
api /status/http/metric_zones/upload/metrics/angie/;
metric upload angie=$1 on=request;
}
# Destino para coleta de métricas
location /prometheus/upload_metric/ {
prometheus upload_metric;
}
}
}
Após várias requisições para /upload/...:
$ curl 127.0.0.1/upload/16384
$ curl 127.0.0.1/upload/64448
$ curl 127.0.0.1/upload/64
$ curl 127.0.0.1/upload/1028
$ curl 127.0.0.1/upload/1028
Os valores da métrica serão:
{
"stats": {
"64": 1,
"256": 1,
"1024": 1,
"4096": 3,
"16384": 4,
"+Inf": 5
},
"sum": 82952,
"count": 5,
"avg_size": 1077.9376
}
No formato Prometheus,
a métrica está disponível em /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