webserver-llc/angie

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

karabanov opened this issue · 12 comments

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

Есть один недостаток который мешает корректно мониторить состояние 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.

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

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

Если включен динамический резолвинг, то список серверов обновляется согласно ответу 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 не осталось серверов.

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

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

    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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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