webserver-llc / angie

Angie - drop-in replacement for Nginx
https://en.angie.software
BSD 2-Clause "Simplified" License
1.2k stars 65 forks source link

Api/metrics мониторинг отсутствие peers в upstream #81

Open karabanov opened 6 months ago

karabanov commented 6 months ago

Здравствуйте.

Есть один недостаток который мешает корректно мониторить состояние upstream с помощью prometheus, а именно, если перестало резолвиться DNS имя сервера указанного в upstream, то все метрики angie_http_upstreams_peers_* пропадают из выдачи, при этом в Console Light для такого upstream выводиться сообщение No servers with 'all' state found in this upstream group.

image

В шаблоне prometheus_all присутствует метрика angie_http_upstreams_peers_state:

'angie_http_upstreams_peers_state{upstream="$1",peer="$2"}' $p8st_all_ups_state
    path=~^/http/upstreams/([^/]+)/peers/([^/]+)/state$
    type=gauge
    'help=The current state of an upstream peer in "HTTP": 1 - up, 2 - down, 3 - unavailable, 4 - recovering.';

map $p8s_value $p8st_all_ups_state {
    volatile;
    "up"           1;
    "down"         2;
    "unavailable"  3;
    "recovering"   4;
    default        0;
}

Но она тоже пропадает, что странно ведь в map указано значение по умолчанию.

Я попробовал сделать такой шаблон, чтобы отслеживать эту ситуацию:

'angie_http_upstreams_peers_available{upstream="$1",available="$2"}' $p8st_all_ups_available
    path=~^/http/upstreams/([^/]+)/peers(.*)
    type=gauge
    'help=Availability peers in upstream group.';

map $p8s_value $p8st_all_ups_available {
    volatile;
    "(null)"  0;
    "{}"      0;
    default   0;
}

Но ничего не вышло... Может регулярка в директиве path должна как-то иначе выглядеть? Или требуется доработка модуля http_prometheus?

Помогите пожалуйста решить проблему с мониторингом наличия серверов в upstream.

VBart commented 6 months ago

Если включен динамический резолвинг, то список серверов обновляется согласно ответу DNS сервера. Если ответ пустой, то все сервера удаляются из upstream. Метрики привязаны к конкретным серверам, а те в свою очередь запрашиваются из DNS. Нет серверов, нет и метрик по ним.

VBart commented 6 months ago

У вас получается, что объект /http/upstreams/([^/]+)/peers пуст и не срабатывает матчинг - там нет метрик, которые бы имели значение, сохраняемое в $p8s_value. Пустые списки и объекты пропускаются, так что встроенными средствами модуля такую метрику сейчас получить не получится.

karabanov commented 6 months ago

Если включен динамический резолвинг, то список серверов обновляется согласно ответу DNS сервера. Если ответ пустой, то все сервера удаляются из upstream. Метрики привязаны к конкретным серверам, а те в свою очередь запрашиваются из DNS. Нет серверов, нет и метрик по ним.

@VBart, а можете добавить метрику для случая, когда в upstream нет серверов, чтобы эту ситуацию было видно не только в Console Light, но и в Prometheus метриках? Полагаю достаточно сделать так, чтобы в случае отсутствия серверов API возвращало не пустой объект, а что-то, что можно матчить.

Было бы очень удобно получать алерт от Promrtheus, когда такое происходит - у нас это довольно частая ситуация, так как речь идёт о так называемой Keepalive Proxy, которая позволяет приложению не умеющему самостоятельно работать с keepalive соединениями (приложение на PHP), всё таки с ними работать.

Сейчас у нас Keepalive Proxy реализована на базе Nginx и bash скрипта, который присылает алерт в Slack если DNS имя перестало резолвиться, убирает из конфига неработающий upstream и выполняет reload - всё это очень неудобно, Angie благодаря наличию параметра resolve и метрик идеально подходит на роль Keepalive Proxy, только вот не хватает одной метрики, чтобы отслеживать ситуацию, когда в upstream не осталось серверов.

VBart commented 6 months ago

Да, надо придумать как это лучше всего сделать.

Пока могу предложить такое обходное решение:

    upstream one {
        #...
        zone one 1m;
    }

    map $peers_len $is_peers_empty {
        4           1;
        default     0;
    }

    prometheus_template test {
        angie_peers_empty $is_peers_empty type=gauge;
    }

    server {
        listen 8000;

        location / {
            auth_request /api_peers/;
            auth_request_set $peers_len $sent_http_content_length;

            prometheus test;
        }

        location =/api_peers/ {
            internal;
            api /status/http/upstreams/one/peers/;
        }
    }

Для одного upstream блока работает. Если нужно несколько, то тут уже сложнее, понадобится njs.

VBart commented 6 months ago

Поясню, как это работает. auth_request позволяет сделать подзапрос и выставить переменную из ответа на подзапрос. В данном случае мы делаем подзапрос в API и если peers для upstream one пустой, то API вернет ответ {}\r\n - что ровно 4 байта. По размеру ответа в 4 байта с помощью map мы и определяем, что список пуст (к сожалению auth_request не дает доступ к самому телу ответа, поэтому приходится использовать косвенные признаки).

karabanov commented 6 months ago

Поясню, как это работает. auth_request позволяет сделать подзапрос и выставить переменную из ответа на подзапрос. В данном случае мы делаем подзапрос в API и если peers для upstream one пустой, то API вернет ответ {}\r\n - что ровно 4 байта. По размеру ответа в 4 байта с помощью map мы и определяем, что список пуст (к сожалению auth_request не дает доступ к самому телу ответа, поэтому приходится использовать косвенные признаки).

Интересный механизм, но к сожалению upstrame в конфиге сотни, да и njs добавлять не хочется.

Будет очень хорошо если доработаете API, чтобы оно возвращало не пустой объект.

VBart commented 6 months ago

Подумаем, что с этим можно сделать. Не хотелось бы добавлять дополнительное значение на каждый объект или список в API, иначе это кратно увеличит число таких сопоставлений для генерации метрик. А делать какое-то исключение отдельно для peers - выглядит очень некрасивым решением.

Но вообще, ситуацию, когда не удалось порезолвить - лучше отслеживать по error_log - там будет [error] вида example.com could not be resolved (3: Host not found). Я бы настроил отправку логов на syslog, там зафильтровал подобные сообщения и поставил алерт на них. Такие алерты будут срабатывать оперативнее, т.к. привязаны к самому событию резолвинга, а не к моменту запроса метрик.

Понятно, что это сложнее и требует дополнительных инструментов.

karabanov commented 6 months ago

Подумаем, что с этим можно сделать. Не хотелось бы добавлять дополнительное значение на каждый объект или список в API, иначе это кратно увеличит число таких сопоставлений для генерации метрик. А делать какое-то исключение отдельно для peers - выглядит очень некрасивым решением.

Но вообще, ситуацию, когда не удалось порезолвить - лучше отслеживать по error_log - там будет [error] вида example.com could not be resolved (3: Host not found). Я бы настроил отправку логов на syslog, там зафильтровал подобные сообщения и поставил алерт на них. Такие алерты будут срабатывать оперативнее, т.к. привязаны к самому событию резолвинга, а не к моменту запроса метрик.

Понятно, что это сложнее и требует дополнительных инструментов.

Если добавлять в API дополнительное значение сложно, может быть можно сделать так, чтобы в $p8s_value было значение (null), когда API возвращает пустой объект?

VBart commented 6 months ago

Если добавлять в API дополнительное значение сложно, может быть можно сделать так, чтобы в $p8s_value было значение (null), когда API возвращает пустой объект?

А так устроит, если значение будет только для пустого объекта? Ведь когда он будет непустым - метрики не будет в ответе прометеусу.

karabanov commented 6 months ago

Если добавлять в API дополнительное значение сложно, может быть можно сделать так, чтобы в $p8s_value было значение (null), когда API возвращает пустой объект?

А так устроит, если значение будет только для пустого объекта? Ведь когда он будет непустым - метрики не будет в ответе прометеусу.

Думаю да, вполне устроит.

karabanov commented 2 months ago

Есть ли новости по этому вопросу?

VBart commented 2 months ago

Есть ли новости по этому вопросу?

Функциональность находится в списке идей на реализацию. Как только освободится место в дорожной карте и если не будет более приоритетных задач, то добавим.