Metric#
Добавлено в версии 1.12.0.
Модуль ngx_stream_metric_module позволяет создавать вычисляемые в реальном
времени произвольные метрики для потокового (TCP и UDP) трафика. Значения таких
метрик сохраняются в разделяемой памяти и отображаются в реальном времени в ветке
API /status/stream/metric_zones/. Поддерживаются различные типы
агрегации данных (счетчики, гистограммы, скользящие средние и др.) с
группировкой по произвольным ключам.
Схема ответа приведена в
справочнике API зон потоковых метрик. Подсчет соединений по адресу клиента: Если выполнить соединение с портом В реальном времени происходит обновление метрики По умолчанию — stream, server Подсчитывает значение метрики с указанным названием зоны разделяемой памяти. Параметры: ключ — произвольная строка (часто переменная), по которой
группируются значения. Максимальная длина — 255 байт; более длинные ключи
обрезаются. В выводе API Angie добавляет значение — число (может быть переменной), обрабатываемое выбранным режимом.
Если пропущено, считается Если Если Если Пример использования: Примечание Метрики с пустым ключом или неправильной парой Что полезно, например, для режима Примечание Важно помнить, что переменные вычисляются в разных фазах. Например,
невозможно использовать По умолчанию — stream Определяет составную метрику — набор метрик с независимыми режимами.
Каждая строка в теле блока задает название подметрики, режим
и необязательные параметры режима.
Размер зоны должен составлять не менее восьми системных страниц памяти. Пример использования: В API дереве шаблон такой составной метрики выглядит следующим образом: По умолчанию — stream Создает зону разделяемой памяти указанного размера с именем название,
в которой хранятся метрики. Имя зоны является узлом в ветке
Параметры: Если Если режим — алгоритм обработки значений (см. раздел Режимы работы); параметры — дополнительная настройка выбранного режима
(например, Пример использования: В API дереве шаблон зоны разделяемой памяти выглядит следующим образом: Примечание В зоне размером 1 мегабайт при размере ключа 39 байт и с одним режимом
метрики может разместиться около 8 тысяч записей с уникальным ключом. Список доступных режимов работы метрик: В примерах ниже используется конечная точка Каждое обновление метрики увеличивает счетчик на Значение по умолчанию — Примеры: Обновление метрики: Ожидаемое значение метрики в API: Счетчик увеличивает или уменьшает свое значение в зависимости от знака
переданного числа. Положительное значение увеличивает счетчик, отрицательное —
уменьшает. Значение Значение по умолчанию — Примеры: Обновление метрики: Ожидаемое значение метрики в API: Дальнейшие обновления: Ожидаемое значение метрики в API: Хранит последнее полученное значение без какой-либо агрегации.
Если значение опущено, используется Примеры: Обновление метрики: Ожидаемое значение метрики в API: Дальнейшие обновления: Ожидаемое значение метрики в API: Сохраняет минимальное из двух значений — уже сохраненного и нового. Примеры: Обновление метрики: Ожидаемое значение метрики в API: Сохраняет наибольшее из двух значений — уже сохраненного и нового. Примеры: Обновление метрики: Ожидаемое значение метрики в API: Вычисляет среднее значение по алгоритму
экспоненциального сглаживания. Принимает необязательный параметр Чем больше коэффициент, тем сильнее новые значения влияют на среднее.
Если указать Примеры: Обновление метрики: Ожидаемое значение метрики в API: Вычисляет среднее арифметическое. Принимает необязательные параметры
Примечание Например, Примеры: Обновление метрики: Ожидаемое значение метрики в API: Если подождать 5 секунд с момента последнего обновления метрики, то
ожидаемое значение метрики в API: Создает набор "бакетов", увеличивая соответствующий счетчик, если новое
значение не превосходит порога бакета. Формат параметров — список числовых
порогов. Полезен для анализа распределения, например длительности сессий. В качестве обязательных параметров передаются числа — предельные значения
бакетов, обычно перечисляемые в порядке возрастания. Примечание Значение бакета Примеры: Обновление метрики: Ожидаемое значение метрики в API: Дальнейшее обновление: Ожидаемое значение метрики в API: Дальнейшее обновление: Ожидаемое значение метрики в API: Для каждой метрики создаются переменные: Для составной метрики добавляется переменная: Аналогично директиве metric, можно использовать сеттер
переменной Сеттер принимает ключ с необязательным суффиксом Пример использования: После трех соединений с портом Примечание Чтение переменной Также изменится значение, хранящееся в переменной Переменные Примечание Для составной метрики значения подметрик в переменной
Пример использования: Для такой конфигурации соединение с портом Соединение с портом Примечание Если в качестве значения для переменной Подсчет метрики произойдет только после того, как заданы значения
переменных В таком случае значение, сохраненное в Значение, которое хранится в Значение, которое хранится в Для составной метрики значение конкретной подметрики можно получить при
помощи переменной Пример использования: Для такой конфигурации соединение с портом Ответ: Ответ: Ответ: В Angie есть встроенный модуль для отображения метрик
в формате Prometheus,
который поддерживает произвольные метрики, включая метрики, собранные на
потоковой стороне. Поскольку экспорт в формате Prometheus — HTTP-функция,
директивы prometheus_template и
prometheus задаются в блоке В качестве примера интеграции рассмотрим следующую конфигурацию: После пяти соединений с портом Значения метрики будут следующими: В формате Prometheus
метрика доступна на Пример конфигурации#
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:{
"stream": {
"metric_zones": {
"connections": {
"discarded": 0,
"metrics": {
"127.0.0.1": 1
}
}
}
}
}
Директивы#
metric#
metric название ключ=значение [on=connect| preread| end];... к любому ключу длиной
255 байт, даже если до сохранения его длина составляла ровно 255 байт. Ключ
может сам содержать символы = — значением считается только текст
после последнего =, поэтому все, что стоит перед ним (включая
вложенные =), становится ключом;0. Если параметр невозможно преобразовать
в число, считается 1;on — необязательный параметр, указывающий, в какой момент
обработки сессии происходит подсчет метрики:on=connect, подсчет происходит на фазе Pre-access,
до чтения каких-либо данных от клиента;on=preread, подсчет происходит один раз за сессию —
в момент, когда клиенту отправляются первые данные, полученные от
проксируемого с помощью proxy_pass сервера или
сформированные директивой return; к этому моменту
такие модули, как proxy_protocol,
ssl_preread и mqtt_preread, уже
обработали начальные данные клиента;on=end (по умолчанию), подсчет происходит на фазе Log,
когда сессия завершается.metric sessions $remote_addr=$session_time on=end;
ключ=значение
не учитываются. Пропущенное значение учитывается как 0:metric foo $bar; # Эквивалентно $bar=0
count, который игнорирует
числовое значение и реагирует лишь на факт обновления метрики.$upstream_bytes_sent (количество байт,
отправленных апстриму) при on=connect (до того, как соединение
куда-либо проксировано).metric_complex_zone#
metric_complex_zone название:размер [expire=on| off] [discard_key=название] { ... }metric_complex_zone sessions: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
}
}
}
metric_zone#
metric_zone название:размер [expire=on| off] [discard_key=название] режим [параметры];/status/stream/metric_zones/.
Размер зоны должен составлять не менее восьми системных страниц памяти.expire=<on|off> — поведение при переполнении зоны:on, самые старые метрики по времени обновления отбрасываются,
освобождая память под поступающие;off (по умолчанию) — отбрасываются поступающие метрики,
сохраняя информацию об установленных.discard_key=<название> — задает метрику с ключом название,
в которой сохраняются значения отброшенных метрик. По умолчанию такая
метрика не создается. Зарезервированный ключ нельзя обновлять вручную.factor для average exp).metric_zone session_time:1m max;
{
"discarded": 0,
"metrics": {
"ключ1": 123,
"ключ2": 10.5
}
}
Режимы работы#
count — счетчик обращений;gauge — стрелка (инкремент/декремент);last — последнее поступившее значение;min — минимальное значение;max — максимальное значение;average exp — скользящее среднее (параметр factor);average mean — среднее за окно (параметры window и count);histogram — распределение по "бакетам" (перечень пороговых значений)./status/ из
примера конфигурации. Результат каждого
примера доступен по адресу /status/stream/metric_zones/<зона>/metrics/.count#
1 независимо от
переданного значения.0.metric_zone count:1m count;
# В качестве составной метрики:
#
# 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 не изменяет счетчик.0.metric_zone gauge:1m gauge;
# В качестве составной метрики:
#
# 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.metric_zone last:1m last;
# В качестве составной метрики:
#
# 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;
# В качестве составной метрики:
#
# 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;
# В качестве составной метрики:
#
# 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=<число> — коэффициент,
по которому установленное значение учитывается при расчете среднего.
Допустимы целые числа от 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 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|время> и 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 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 или +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 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
}
}
Встроенные переменные#
$metric_<name>$metric_<name>_key$metric_<name>_value$metric_<name>_value_<metric>$metric_<name>#$metric_<name> для подсчета метрики. Подсчет происходит
в момент установки переменной — например, через директиву set,
которая вычисляется на фазе Pre-access (той же, что и
on=connect), либо программно из модуля
njs, например в обработчике
js_access.=значение.
Ключ от значения отделяет последний символ =; без суффикса
используется значение 0. Ключ и значение могут состоять из текста,
переменных или их комбинаций. Такие же правила разбора использует директива
metric.stream {
metric_zone hits:1m count;
# В этот момент добавилась переменная $metric_hits
server {
listen 12345;
metric hits client=1 on=connect;
}
server {
listen 12346;
set $metric_hits client=1;
return "$metric_hits\n";
}
}
12345 и одного соединения
с портом 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> возвращает ключ вместе с текущим
подсчитанным значением метрики, в виде ключ=значение, а не ту
строку, которая была присвоена буквально. В примере выше буквально
присваивается значение client=1, но поскольку режим count
игнорирует присвоенное значение и просто увеличивает счетчик при каждом
обновлении, чтение переменной $metric_hits после этого возвращает
client=4 — новое значение счетчика, уже учитывающее три
предыдущих обновления с порта 12345.$metric_<name>_key,
на указанный ключ.$metric_<name>_key и $metric_<name>_value#$metric_<name>_key и $metric_<name>_value задают
соответственно ключ и значение. Обновление метрики происходит в момент
установки значения $metric_<name>_value, если ключ в
$metric_<name>_key уже задан.$metric_<name>_value объединены при помощи разделяющего
символа ", ".stream {
metric_zone level:1m gauge;
# В этот момент добавились переменные $metric_level, $metric_level_key
# и $metric_level_value
metric_complex_zone stats:1m {
count count;
min min;
avg average exp;
}
# В этот момент добавились переменные $metric_stats, $metric_stats_key
# и $metric_stats_value
server {
listen 12345;
metric level sensor=10 on=connect;
}
server {
listen 12346;
set $metric_level_key "sensor";
set $metric_level_value 5;
# Либо: 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;
# Либо: set $metric_stats bar=9;
return "Updated with '$metric_stats'\nValues='$metric_stats_value'\n";
}
}
12345 (устанавливающее
начальное значение стрелки в 10), за которым следует соединение
с портом 12346, дает:$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12346 </dev/null
Updated with 'sensor=15'
Value='15'
12347 дает:$ nc 127.0.0.1 12347 </dev/null
Updated with 'bar=1, 9, 9'
Values='1, 9, 9'
$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>#$metric_<name>_value_<metric>, указав имя
подметрики в качестве <metric>.stream {
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 12345;
set $metric_foo_key bar;
set $metric_foo_value 9;
# Либо: set $metric_foo bar=9;
return "Updated with '$metric_foo'\nValues='$metric_foo_value'\nCount='$metric_foo_value_count'\n";
}
}
12345 дает:$ nc 127.0.0.1 12345 </dev/null
Updated with 'bar=1, 9, 9'
Values='1, 9, 9'
Count='1'
Дополнительные примеры#
Мониторинг соединений по протоколу#
metric_zone protocols:1m count;
server {
listen 12345;
listen 12346 udp;
metric protocols $protocol;
}
{
"TCP": 340,
"UDP": 58
}
Распределение времени сессии 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
}
}
}
Активные подключения#
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
}
Поддержка Prometheus#
http, обращаясь к
потоковой зоне метрики через единое дерево API /status/.stream {
# Создание метрики "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;
# Обновление метрики по завершении сессии общим количеством
# байт, полученных от клиента
proxy_pass backend;
metric upload angie=$bytes_received on=end;
}
}
http {
# Описание шаблона Prometheus для метрики "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;
# Таргет для сбора метрик
location /prometheus/upload_metric/ {
prometheus upload_metric;
}
}
}
12345, при которых были отправлены
данные размером 16384, 64448, 64, 1028
и 1028 байт:$ 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