Metric#
Добавлено в версии 1.11.0.
Модуль ngx_http_metric_module позволяет создавать вычисляемые в реальном времени
произвольные метрики. Значения таких метрик сохраняются в разделяемой памяти
и отображаются в реальном времени в ветке API /status/http/metric_zones/.
Поддерживаются различные типы агрегации данных (счетчики, гистограммы, скользящие средние и др.)
с группировкой по произвольным ключам.
Схема ответа приведена в справочнике API зон HTTP-метрик.
При сборке из исходного кода модуль собирается по
умолчанию; его можно отключить с помощью
параметра сборки --without-http_metric_module.
В пакетах и образах из наших репозиториев модуль включен в сборку.
Примечание
При перезагрузке конфигурации зона, созданная директивой
metric_zone или
metric_complex_zone, сохраняет накопленные
значения только при неизменной структуре хранимых данных. Зона
начинает работу пустой, если от предыдущей конфигурации отличаются
размер зоны, количество метрик или режим, если изменился
параметр count режима average mean, если параметр
window режима average mean переключен в off или
обратно или если изменилось количество корзин histogram;
причина при этом
записывается в error_log на уровне info. Остальные
параметры, например factor режима average exp,
интервал window режима average mean или границы корзин
histogram, можно менять без потери накопленных значений.
Пример конфигурации#
Подсчет запросов к 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;
}
}
}
Если с такой конфигурацией выполнить запрос на /api/:
$ curl 127.0.0.1/api/ --user-agent "Firefox"
В реальном времени происходит обновление метрики api_requests:
{
"http": {
"metric_zones": {
"api_requests": {
"discarded": 0,
"metrics": {
"Firefox": 1
}
}
}
}
}
Директивы#
metric#
| |
По умолчанию | — |
http, server, location |
Подсчитывает значение метрики с указанным названием зоны разделяемой памяти.
Параметры:
ключ — произвольная строка (часто переменная), по которой группируются значения. Максимальная длина — 255 байт; более длинные ключи обрезаются. В выводе API Angie добавляет
...к любому ключу длиной 255 байт, даже если до сохранения его длина составляла ровно 255 байт. Если ключ сам содержит один или несколько символов=, в качестве значения воспринимается только подстрока после последнего=; все, что стоит до него, становится частью ключа;значение — число (может быть переменной), обрабатываемое выбранным режимом. Если пропущено, считается
0. Если параметр невозможно преобразовать в число, считается1;on— необязательный параметр, указывающий в какой момент происходит подсчет метрики:Если
on=request, подсчет происходит при получении запроса;Если
on=response, подсчет происходит при подготовке ответа;Если
on=end(по умолчанию), подсчет происходит после отправки ответа.
Примечание
В случае внутреннего перенаправления, метрики на стадии on=request
посчитаются в исходном location. При этом метрики
on=response и on=end будут подсчитаны уже в новом
location.
Директив metric может быть несколько. Директивы наследуются
с предыдущего уровня конфигурации при условии, что на данном
уровне не описаны свои директивы metric. Поэтому одна
директива metric в блоке location отменяет все правила,
унаследованные от server или http, на всех трех стадиях
on, а не только на своей.
Пример использования:
metric requests $http_user_agent=$request_time;
Примечание
Метрики с пустым ключом или неправильной парой ключ=значение
не учитываются. Пропущенное значение учитывается как 0:
metric foo $bar; # Вместо $bar=0
Что полезно, например, для режима count, который игнорирует
числовое значение и реагирует на факт обновления метрики.
Примечание
Важно помнить, что переменные вычисляются в разных фазах. Например,
невозможно использовать $bytes_sent (количество отправленных байт клиенту)
при on=request (при получении запроса).
metric_complex_zone#
| |
По умолчанию | — |
http |
Определяет составную метрику — набор метрик с независимыми режимами. Каждая строка в теле блока задает название подметрики, режим и необязательные параметры режима. Размер зоны должен составлять не менее восьми системных страниц памяти: 32K при размере страницы 4K.
Пример использования:
metric_complex_zone requests:1m expire=on discard_key="old" {
# название подметрики режим работы параметры
min_time min;
avg_time average exp factor=60;
max_time max;
total count;
}
В API дереве шаблон такой составной метрики выглядит следующим образом:
{
"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#
| |
По умолчанию | — |
http |
Создает зону разделяемой памяти указанного размера с именем название,
в которой хранятся метрики. Имя зоны является узлом в ветке
/status/http/metric_zones/.
Размер зоны должен составлять не менее восьми системных страниц памяти:
32K при размере страницы 4K.
Параметры:
expire=<on|off>— поведение при переполнении зоны:Если
on, самые старые метрики по времени обновления отбрасываются, освобождая память под поступающие;Если
off(по умолчанию) — отбрасываются поступающие метрики, сохраняя информацию об установленных.
discard_key=<название>— задает метрику с ключом название, в которой сохраняются значения отброшенных метрик. По умолчанию такая метрика не создается. Зарезервированный ключ нельзя обновлять вручную.режим — алгоритм обработки значений (см. раздел Режимы работы);
параметры — дополнительная настройка выбранного режима (например,
factorдляaverage exp).
Пример использования:
metric_zone request_time:1m max;
В API дереве шаблон зоны разделяемой памяти выглядит следующим образом:
{
"discarded": 0,
"metrics": {
"ключ1": 123,
"ключ2": 10.5
}
}
Примечание
В зоне размером 1 мегабайт при размере ключа 39 байт и с одним режимом метрики может разместиться около 8 тысяч записей с уникальным ключом.
Режимы работы#
Список доступных режимов работы метрик:
count— счетчик обращений;gauge— стрелка (инкремент/декремент);last— последнее поступившее значение;min— минимальное значение;max— максимальное значение;average exp— скользящее среднее (параметрfactor);average mean— среднее за окно (параметрыwindowиcount);histogram— распределение по "бакетам" (перечень пороговых значений).
В примерах ниже используется конечная точка Каждое обновление метрики увеличивает счетчик на Значение по умолчанию — Примеры: Обновление метрики: Ожидаемое значение метрики в API: Счетчик увеличивает или уменьшает свое значение в зависимости
от знака переданного числа. При положительном — увеличивает счетчик.
При отрицательном — уменьшает. Переданное значение Значение по умолчанию — Примеры: Обновление метрики: Ожидаемое значение метрики в API: Обновление метрики: Ожидаемое значение метрики в API: Хранит последнее полученное значение без какой-либо агрегации.
Если значение опущено, используется Примеры: Обновление метрики: Ожидаемое значение метрики в API: Обновление метрики: Ожидаемое значение метрики в API: Сохраняет минимальное из двух значений — уже сохраненного и нового. Примеры: Обновление метрики: Ожидаемое значение метрики в API: Сохраняет наибольшее из двух значений — уже сохраненного и нового. Примеры: Обновление метрики: Ожидаемое значение метрики в API: Вычисляет среднее значение по алгоритму
экспоненциального сглаживания. Принимает необязательный параметр Чем больше коэффициент, тем сильнее новые значения влияют на среднее.
Если указать Примеры: Обновление метрики: Ожидаемое значение метрики в API: Вычисляет среднее арифметическое. Принимает необязательные параметры
Примечание Например, Примеры: Обновление метрики: Ожидаемое значение метрики в API: Если подождать 5 секунд, с момента последнего обновления метрики, то
ожидаемое значение метрики в API: Создает набор "бакетов", увеличивая соответствующий счетчик,
если новое значение не превосходит порога бакета.
Формат параметров — список числовых порогов.
Полезен для анализа распределения, например времени ответа. В качестве обязательных параметров передаются числа — предельные значения
бакетов, обычно перечисляемые в порядке возрастания. Примечание Значение бакета Примеры: Обновление метрики: Ожидаемое значение метрики в API: Обновление метрики: Ожидаемое значение метрики в API: Обновление метрики: Ожидаемое значение метрики в API:/api/ из
примера конфигурации. Результат каждого
примера доступен по адресу /api/http/metric_zones/<зона>/metrics/.count#
1 независимо от
переданного значения.0.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;
}
}
$ 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;
}
}
$ 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;
}
}
$ 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;
}
}
$ 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;
}
}
$ 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;
}
}
$ 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;
}
}
$ 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 hist KEY=$1;
}
}
$ 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, можно использовать сеттер переменной
$metric_<name> для подсчета метрики. Подсчет метрики будет происходить в фазе
Rewrite,
что позволяет производить обработку метрики, например, из модуля
njs.
Сеттер принимает ключ с необязательным суффиксом =значение.
Без суффикса используется значение 0. Ключ и значение могут состоять
из текста, переменных или их комбинаций.
Пример использования:
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/;
}
}
}
Подсчет метрики с помощью модуля 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/;
}
}
Файл 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=0 0 1, 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>#
Для составной метрики значение конкретной подметрики можно получить при помощи
переменной $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=1, 9, 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#
Angie имеет встроенный модуль Prometheus для отображения метрик в формате 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
метрика доступна на /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