Metric#
Модуль Подсчет запросов к API: Если с такой конфигурацией выполнить запрос на В реальном времени происходит обновление метрики По умолчанию — http Создает зону разделяемой памяти указанного размера с именем название,
в которой хранятся метрики. Имя зоны является узлом в ветке
Параметры: Если Если режим — алгоритм обработки значений (см. раздел Режимы работы); параметры — дополнительная настройка выбранного режима
(например, Пример использования: В API дереве шаблон зоны разделяемой памяти выглядит следующим образом: Число; количество отброшенных метрик в зоне разделяемой памяти Объект; его члены — метрики с установленными ключами и подсчитанными значениями Примечание В зоне размером 1 мегабайт при размере ключа 39 байт и с одним режимом
метрики может разместиться около 8 тысяч записей с уникальным ключом. По умолчанию — http Определяет составную метрику — набор метрик с независимыми режимами.
Каждая строка в теле блока задает название подметрики, режим
и необязательные параметры режима. Пример использования: В API дереве шаблон такой составной метрики выглядит следующим образом: Число; количество отброшенных метрик в зоне разделяемой памяти Объект; его члены — составные метрики с установленными ключами. Они представляют собой объекты, содержащие набор подметрик с подсчитанными значениями По умолчанию — http, server, location Подсчитывает значение метрики с указанным названием зоны разделяемой памяти. Параметры: ключ — произвольная строка (часто переменная), по которой группируются
значения. Максимальная длина — 255 байт. Если ключ длиннее, он будет
ограничен размером 255 байт и дополнен значение — число (может быть переменной), обрабатываемое выбранным режимом.
Если пропущено, считается Если Если Если Примечание В случае внутреннего перенаправления, метрики на стадии Пример использования: Примечание Метрики с пустым ключом или неправильной парой Что полезно, например, для режима Примечание Важно помнить, что переменные вычисляются в разных фазах. Например,
невозможно использовать Список доступных режимов работы метрик: Счетчик увеличивает свое значение на Значение по умолчанию — Примечание Любое обновление метрики (с любым значением) монотонно увеличивает
счетчик на Примеры: Обновление метрики: Ожидаемое значение метрики в API: Счетчик увеличивает или уменьшает свое значение в зависимости
от знака переданного числа. При положительном — увеличивает счетчик.
При отрицательном — уменьшает. Переданное значение Значение по умолчанию — Примеры: Обновление метрики: Ожидаемое значение метрики в API: Обновление метрики: Ожидаемое значение метрики в API: Хранит последнее полученное значение без какой-либо агрегации.
Если значение опущено, используется Примеры: Обновление метрики: Ожидаемое значение метрики в API: Обновление метрики: Ожидаемое значение метрики в API: Сохраняет минимальное из двух значений — уже сохраненного и нового. Примеры: Обновление метрики: Ожидаемое значение метрики в API: Сохраняет наибольшее из двух значений — уже сохраненного и нового. Примеры: Обновление метрики: Ожидаемое значение метрики в API: Вычисляет среднее значение по алгоритму
экспоненциального сглаживания. Принимает необязательный параметр Чем больше коэффициент, тем сильнее новые значения влияют на среднее.
Если указать Примеры: Обновление метрики: Ожидаемое значение метрики в API: Вычисляет среднее арифметическое. Принимает необязательные параметры
Примечание Например, Примеры: Обновление метрики: Ожидаемое значение метрики в API: Если подождать 5 секунд, с момента последнего обновления метрики, то
ожидаемое значение метрики в API: Создает набор "бакетов", увеличивая соответствующий счетчик,
если новое значение не превосходит порога бакета.
Формат параметров — список числовых порогов.
Полезен для анализа распределения, например времени ответа. В качестве обязательных параметров передаются числа — предельные значения
бакетов, перечисленные в порядке возрастания. Примечание Значение бакета Примеры: Обновление метрики: Ожидаемое значение метрики в API: Обновление метрики: Ожидаемое значение метрики в API: Обновление метрики: Ожидаемое значение метрики в API: Для каждой метрики создаются переменные: Для составной метрики добавляется переменная: Аналогично директиве metric, можно использовать сеттер переменной
В качестве значения для установки переменной должна использоваться конструкция
Пример использования: Подсчет метрики с помощью модуля
njs: Файл После нескольких запросов на Примечание После установки переменной можно получить ее значение. Оно будет равно
указанной паре Также изменится значение, хранящееся в переменной Переменные Примечание Для составной метрики значения подметрик в переменной Пример использования: Для такой конфигурации после запроса к Для Примечание Если в качестве значения для переменной Подсчет метрики произойдет только после того, как заданы значения переменных
В таком случае значение, сохраненное в Значение, которое хранится в Значение, которое хранится в Для составной метрики значение конкретной подметрики можно получить при помощи
переменной Пример использования: Для такой конфигурации после запроса к Ответ: Ответ: Ответ: Angie имеет встроенный модуль для отображения метрик в
формате Prometheus,
поддерживающий произвольные метрики. В качестве примера интеграции рассмотрим следующую конфигурацию: После нескольких запросов на Значения метрики будут следующими: В формате Prometheus
метрика доступна на ngx_http_metric_module позволяет создавать вычисляемые в реальном времени
произвольные метрики. Значения таких метрик сохраняются в разделяемой памяти
и отображаются в реальном времени в ветке API /status/http/metric_zones/.
Поддерживаются различные типы агрегации данных (счетчики, гистограммы, скользящие средние и др.)
с группировкой по произвольным ключам.Пример конфигурации#
http {
metric_zone api_requests:1m count;
server {
listen 80;
location /api/ {
allow 127.0.0.1;
deny all;
api /;
metric api_requests $http_user_agent on=request;
}
}
}
/api/:$ curl 127.0.0.1/api/ --user-agent "Firefox"
api_requests:{
"status": {
"http": {
"metric_zones": {
"api_requests": {
"discarded": 0,
"metrics": {
"Firefox": 1
}
}
}
}
}
}
Директивы#
metric_zone#
metric_zone название:размер [expire=on|:samp:off] [discard_key=название] режим [параметры];/status/http/metric_zones/.expire=<on|off> — поведение при переполнении зоны:on, самые старые метрики по времени обновления отбрасываются,
освобождая память под поступающие;off (по умолчанию) — отбрасываются поступающие метрики,
сохраняя информацию об установленных.discard_key=<название> — задает метрику с ключом название,
в которой сохраняются значения отброшенных метрик. По умолчанию такая метрика
не создается. Зарезервированный ключ нельзя обновлять вручную.factor для average exp).metric_zone request_time:1m max;
{
"discarded": 0,
"metrics": {
"ключ1": 123,
"ключ2": 10.5,
}
}
discardedmetricsmetric_complex_zone#
metric_complex_zone название:размер [expire=on|:samp:off] [discard_key=название] { ... }metric_complex_zone requests:1m expire=on discard_key="old" {
# название подметрики режим работы параметры
min_time min;
avg_time average exp factor=60;
max_time max;
total count;
}
{
"discarded": 3,
"metrics": {
"ключ1": {
"min_time": 20,
"avg_time": 50,
"max_time": 80,
"total" 2
},
"old": {
"min_time": 3,
"avg_time": 40,
"max_time": 152,
"total": 80
}
}
}
discardedmetricsmetric#
metric название ключ=значение [on=request| response| end];... многоточием;0. Если параметр невозможно преобразовать
в число, считается 1;on — необязательный параметр, указывающий в какой момент происходит
подсчет метрики:on=request, подсчет происходит при получении запроса;on=response, подсчет происходит при подготовке ответа;on=end (по умолчанию), подсчет происходит после отправки ответа.on=request
посчитаются в исходном location. При этом метрики
on=response и on=end будут подсчитаны уже в новом
location.metric requests $http_user_agent=$request_time;
ключ=значение
не учитываются. Пропущенное значение учитывается как 0:metric foo $bar; # Вместо $bar=0
count, который игнорирует
числовое значение и реагирует на факт обновления метрики.$bytes_sent (количество отправленных байт клиенту)
при on=request (при получении запроса).Режимы работы#
count — счетчик обращений;gauge — стрелка (инкремент/декремент);last — последнее поступившее значение;min — минимальное значение;max — максимальное значение;average exp — скользящее среднее (параметр factor);average mean — среднее за окно (параметры window и count);histogram — распределение по "бакетам" (перечень пороговых значений).count#
1 при каждом обновлении метрики.0.1.metric_zone count:1m count;
# В качесте составной метрики:
#
# 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/;
}
}
$ 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
{
"KEY": 4
}
gauge#
0 не изменяет счетчик.0.metric_zone gauge:1m gauge;
# В качесте составной метрики:
#
# 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/;
}
}
$ curl 127.0.0.1/metric/
{
"KEY": 0
}
$ curl 127.0.0.1/metric/set/5
$ curl 127.0.0.1/metric/set/-5
$ curl 127.0.0.1/metric/set/8
{
"KEY": 8
}
last#
0.metric_zone last:1m last;
# В качесте составной метрики:
#
# 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/;
}
}
$ curl 127.0.0.1/metric/
{
"KEY": 0
}
$ 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
{
"KEY": -3.5
}
min#
metric_zone min:1m min;
# В качесте составной метрики:
#
# 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/;
}
}
$ 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/
{
"KEY": -512
}
max#
metric_zone max:1m max;
# В качесте составной метрики:
#
# 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/;
}
}
$ 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/
{
"KEY": 42.999
}
average exp#
factor=<число> — коэффициент,
по которому установленное значение учитывается при расчете среднего.
Допустимы целые числа от 0 до 99. По умолчанию — 90.90, то будет взято 90% от нового значения
и лишь 10% от предыдущего.metric_zone avg_exp:1m average exp factor=60;
# В качесте составной метрики:
#
# 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/;
}
}
$ 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
{
"KEY": 30.16
}
average mean#
window=<off|время> и count=<число>,
задающие соответственно интервал времени и объем выборки для усреднения.
По умолчанию: window=off (учитывается вся выборка) и count=10.window=5s будет учитывать только события последних 5 секунд.
Параметрик window не может принимать значение 0. Параметр
count=число управляет размером выборки (закэшированных значений)
для более плавного подсчета среднего.metric_zone avg_mean:1m average mean window=5s count=8;
# В качесте составной метрики:
#
# 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/;
}
}
$ 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
{
"KEY": 2.1
}
{
"KEY": 0
}
histogram#
inf или +Inf можно использовать
для захвата всех значений, превышающих максимальный бакет.metric_zone hist:1m histogram 0.1 0.2 0.5 1 2 inf;
# В качесте составной метрики:
#
# 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/;
}
}
$ curl 127.0.0.1/metric/set/0.25
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 1,
"inf": 1
}
}
$ curl 127.0.0.1/metric/set/2
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 2,
"inf": 2
}
}
$ curl 127.0.0.1/metric/set/1000
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 2,
"inf": 3
}
}
Встроенные переменные#
$metric_<name>$metric_<name>_key$metric_<name>_value$metric_<name>_value_<metric>$metric_<name>#$metric_<name> для подсчета метрики. Подсчет метрики будет происходить в фазе
Rewrite,
что позволяет производить обработку метрики, например, из модуля
njs.ключ=значение. В качестве ключа и значения можно использовать текст,
переменные и их комбинации. Ключ — произвольная строка, по которой группируются значения.
Значение — число, обрабатываемое выбранным режимом.
Если пропущено, считается 0.
Если параметр невозможно преобразовать в число, считается 1.http {
metric_zone counter:1m count;
# В этот момент добавилась переменная $metric_counter
server {
listen 80;
location /metric/ {
set $metric_counter $http_user_agent; # Вместо $http_user_agent=0
}
location /api/ {
allow 127.0.0.1;
deny all;
api /status/http/metric_zones/counter/;
}
}
}
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/;
}
}
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/')]);
// Используем сеттер переменной $metric_requests
r.variables.metric_requests = `google={Date.now() - start_time}`;
}
export default {js_request};
location /metric/ значения метрики могут быть
следующими:{
"discarded": 0,
"metrics": {
"google": {
"min_time": 70,
"max_time": 432,
"total": 6
}
}
}
ключ=значение.$metric_<name>_key
на указанный ключ.$metric_<name>_key и $metric_<name>_value#$metric_<name>_key и $metric_<name>_value задают
соответственно ключ и значение. Обновление метрики происходит в момент установки
значения $metric_<name>_value, если ключ в $metric_<name>_key
уже задан.$metric_<name>_value
объединены при помощи разделяющего символа ", ".http {
metric_zone gauge:1m gauge;
# В этот момент добавилась переменная $metric_gauge
# А еще переменные $metric_gauge_key и $metric_gauge_value
metric_complex_zone complex:1m {
hist histogram 1 2 3;
avg average exp;
}
# В этот момент добавилась переменная $metric_complex
# А еще переменные $metric_complex_key и $metric_complex_value
server {
listen 80;
location /gauge/ {
set $metric_gauge_key "foo";
set $metric_gauge_value 1;
# Либо 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;
# Либо set $metric_complex foo=3;
return 200 "Updated with '$metric_complex'\nValue='$metric_complex_value'\n";
}
}
}
/gauge/ ожидается слудующий ответ:$ curl 127.0.0.1/gauge/
Updated with 'foo=1'
Value='1'
/complex/:$ curl 127.0.0.1/complex/
Updated with 'foo=3'
Value='0 0 1, 3'
$metric_<name>_value указать
пустую строку, значение будет распознано как 0. Если строка состоит из
символов, которые невозможно преобразовать в число,
она будет распознана как 1.$metric_<name>_key и $metric_<name>_value.$metric_<name>, станет равным
новой паре ключ=значение, указанной при помощи $metric_<name>_key
и $metric_<name>_value.$metric_<name>_key, является последним
указанным через переменные ключом метрики.$metric_<name>_value, является последним
подсчитанным значением метрики с ключом, установленным в $metric_<name>_key.$metric_<name>_value_<metric>#$metric_<name>_value_<metric>, указав имя подметрики в качестве
<metric>.http {
metric_complex_zone foo:1m {
count count;
min min;
avg average exp;
}
# В этот момент добавилась переменная $metric_foo
# А еще переменные $metric_foo_key и $metric_foo_value
# А так же $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;
# Либо set $metric_foo bar=9;
return 200 "Updated with '$metric_foo'\nValues='$metric_foo_value'\nCount='$metric_foo_value_count'\n";
}
}
}
/foo/ ожидается слудующий ответ:$ curl 127.0.0.1/foo/
Updated with 'bar=9'
Values='1, 9, 9'
Count='1'
Дополнительные примеры#
Мониторинг 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/;
}
}
{
"GET": 65,
"POST": 20,
"PUT": 10,
"DELETE": 5
}
Распределение времени ответа 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/;
}
}
{
"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
}
}
}
Активные подключения#
metric_zone active_connections:2m gauge;
server {
listen 80;
server_name site1.com;
location / {
# Увеличиваем при подключении
metric active_connections site1=1 on=request;
# Уменьшаем при завершении
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;
}
}
{
"site1": 42,
"site2": 17
}
Поддержка Prometheus#
http {
# Создание метрики "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;
}
# Описание шаблона Prometheus для метрики "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;
# Обновление метрики
location ~ ^/upload/(.*)$ {
api /status/http/metric_zones/upload/metrics/angie/;
metric upload angie=$1 on=request;
}
# Таргет для сбора метрик
location /prometheus/upload_metric/ {
prometheus upload_metric;
}
}
}
/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
{
"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