Есть два хоста, прописанные в хапрокси. Есть основной (на который идет весь траффик) и есть запасной. Время от времени там бывает так, что на основном какой-то из запросов получает 503 ошибку. А резервный включается через 3 секунды, если основной становится не доступен. Вопрос. Можно ли с помощью хапрокси, сделать так, чтобы тот же запрос на котором ответ 503, автоматически перенаправлялся на резервный без полного переключения траффика на резерв?
Я пробовал с помощью надстройки ЛУА, но не вышло.
Я добился только такого поведения. Клиент отправляет запрос, получает ошибку и если он повторно отправит запрос, то идет редирект на резерв
А вот чтоб автоматом, сразу, без дополнительных запросов - не получается
Половину методов не поддерживает ЛУА, другую половину не поддерживает хапрокси.
Подскажите, поделитесь опытом.
Conf на данный момент вот такой:
```
global
maxconn 100
log stdout local0 info
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
Я добился только такого поведения. Клиент отправляет запрос, получает ошибку и если он повторно отправит запрос, то идет редирект на резерв. А вот чтоб автоматом, сразу, без дополнительных запросов - не получается
нет, клиент должен сделать еще один реквест - на первый он уже получил 503
The HTTP protocol is transaction-driven. This means that each request will lead to one and only one response
и второй, немного иной по своей сути
Можно ли с помощью хапрокси, сделать так, чтобы тот же запрос на котором ответ 503, автоматически перенаправлялся на резервный без полного переключения траффика на резерв?
Немного непонятно, ваш способ который вы упомянули работает без полного переключения трафика? Если нет - можно попробовать балансировку куками https://www.haproxy.com/documentation/haproxy-conf...
То есть работать без настройки "бэкап" сервера, а просто в случае ошибки сетить куку server2 и снимать ее на стороне сервера, а без куки направлять на server1
Возможно плохо объяснил. Такое у меня бывает.
Есть два хоста. Один работает в режиме праймори (то есть на него идет весь траффик) и есть резерв. Они работают исходя из настройки check. Если после 3-ех ретраев хапрокси получает ошибки, то траффик автоматом переключается на резерв. Бывают случаи, что на праймори выходит ошибка 500 (но я тестирую пока на 503), после чего клиент теряет запрос, а хапрокси неуспев достучаться до праймори, наинает сыпать на резерв хост весь трафик. 500 она не постоянная (предположим сеть маргнула на секунду).
Нужно сделать так.
Добавить какую-то дополнительную проверку, чтобы в случае 503 ошибки, хапрокси взял этот же запрос и редиректнул конкретно его на резерв без переключения трафика на него.
Надеюсь, так понятнее.
@Евгений Хлебников так же я попробовал с помощью кук, так же не получилось. Постманом отправляю запрос, возвращает 503 и все. Дальше редиректа никакого.
Хапрокси вообще поддерживает такую реализацию?
В интернетах говорят, что подобные настройки поддерживает Нжинкс.
Misha_Polutrup, я скорее всего все еще неверно понимаю стоящую перед вами задачу
Повторные запросы хапрокси делает сама, с помощью опций retry (количество) и retry-on (причина). При истечении количества ретраев, работает redispatch перекидывающий на другой сервер в бэкенде
Если же вы хотите чтобы хапрокси заставила клиента сделать запрос - напрямую никак, это дело клиента. Однако можно модифицировать 503 ответ, добавив javascript который сделает повторный запрос к тому же host, path, query (по понятным причинам работает только для веб, для какого нибудь api работать не будет)
Если URL-ов которые могут зафейлиться несколько - придется применить lua для формирования страницы 503-го ответа (правда в более новых версиях HAProxy вроде бы можно делать эт и без lua - но мне не приходилось, изучайте документацию)
Еще сначала не обратил внимания на ваш конфиг: backup сервер должен быть доступен, чтобы обслуживать реквесты, в случае недоступности основного сервера
если клиент уже получает 503 - значит в бэкенде нет серверов вообще, а значит никто не может обслужить реквест. Транзакция закрыта. Ретрай вы можете сделать на стороне клиента, как я описал в предыдущем комментарии, но смысл тогда ждать пока поднимется бэкап? К тому моменту (целых 3 секунды!) основной вполне может быть уже разгружен
Не лучше ли сделать оба сервера равноправными (в случае если бэкап слабый - поиграться maxconn) или вообще разделить эти потоки на разные бэкенд прокси, разруливая на стороне фронтенд прокси, например, считая количество доступных серверов в основном бэкенд прокси?
acl main_is_not_available nb_srv(be_main) le 0
use_backend be_back if main_is_not_available
default_backend be_main
be_main
... здесь только основной сервер
be_back
... здесь только бэкап сервер
в такой конфигурации вы сможете установить отдельные долгие таймауты на be_back. и be_back будет работать только если в be_main 0 серверов
Евгений Хлебников, Да, я думал на счет вашей идеи ранее, но к сожалению так не получится. Дело в том, что резерв находится в облаке и обращаясь к нему, компания платит дополнительные деньги.
Основная суть в том, что после 500-ки траффик полностью начинает литься на резерв. Мне нужно сделать так, чтоб резерв был задействован, но в самой наименьшей степени.
То есть, клиент выполнил обращение, схватил 500 (причины разные могут быть), тот же запрос взять, и отправить в резерв, при этом продолжая лить траффик на основной.
Вот так как-то можно сделать?
Misha_Polutrup, 500 или 503?
500 internal error - может быть единичной ошибкой и просто повтор через retry (c настроенной retry-on на определенный статус) скорее всего проблему (для клиента) решит
503 - это отсутствие серверов в балансировке, тогда конфиг как в моем примере выше должен переключить на бэкапный бэкенд пока они не появятся.
Если же, например, 500й статус от приложения постоянно - необходим правильный хелсчек, который выведет основной сервер из балансировки. чтобы отрабатывала бэкап нода
@Евгений Хлебников В данном случае, у меня нет сервисов, которые отдают 500-ки, поэтому тестирую на 503.
Да, видимо тестирование неудачное.
Хорошо, тогда вопрос, по поводу ретраев в рамках 500 ошибки.
Клиент отправляет запрос, запрос отдает 500 ретрай тот же запрос пуляет на хост или клиенту нужно выполнить новый запрос?
Misha_Polutrup, главное тут понимать получил ли клиент ответ на свой запрос (пусть даже и 500 Internal Error) или его обработку перехватил балансировщик. Как только клиент получил ответ - ретрай уже не будет работать и его надо будет инициировать на стороне клиента. Помните про http transaction (цитата кстати из документации haproxy)