Metric#
Добавлено в версии 1.12.0.
Модуль ngx_stream_metric_module позволяет создавать вычисляемые в реальном
времени произвольные метрики для потокового (TCP и UDP) трафика. Значения таких
метрик сохраняются в разделяемой памяти и отображаются в реальном времени в ветке
API /status/stream/metric_zones/. Поддерживаются различные типы
агрегации данных (счетчики, гистограммы, скользящие средние и др.) с
группировкой по произвольным ключам.
Схема ответа приведена в справочнике API зон потоковых метрик.
Примечание
При перезагрузке конфигурации зона, созданная директивой
metric_zone или
metric_complex_zone, сохраняет накопленные
значения только при неизменной структуре хранимых данных. Зона
начинает работу пустой, если от предыдущей конфигурации отличаются
размер зоны, количество метрик или режим, если изменился
параметр count режима average mean, если параметр
window режима average mean переключен в off или
обратно или если изменилось количество корзин histogram;
причина при этом
записывается в error_log на уровне info. Остальные
параметры, например factor режима average exp,
интервал window режима average mean или границы корзин
histogram, можно менять без потери накопленных значений.
При сборке из исходного кода модуль собирается по
умолчанию вместе с модулем Stream (который включается
параметром --with-stream); его можно отключить с помощью
параметра сборки --without-stream_metric_module.
В пакетах и образах из наших репозиториев модуль
включен в сборку. Подсчет соединений по адресу клиента: Если выполнить соединение с портом В реальном времени происходит обновление метрики По умолчанию — 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,
который поддерживает произвольные метрики, включая метрики, собранные на
потоковой стороне. Поскольку экспорт в формате 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 может быть несколько. Директивы наследуются
с предыдущего уровня конфигурации при условии, что на данном
уровне не описаны свои директивы metric. Поэтому одна
директива metric в блоке server отменяет все правила,
унаследованные от stream, на всех трех стадиях on, а не
только на своей.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), либо программно из модуля
Stream JS, например в обработчике
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