Как стать автором
Обновить

Не забудьте повысить шанс ответа клиенту, используя повторный запрос в L7 балансировке

Время на прочтение5 мин
Количество просмотров4.3K
Используя nginx для балансировки HTTP трафика на уровне L7 есть возможность направить запрос клиента на следующий сервер приложений, если целевой не возвращает положительный ответ. Проба механизма пассивной проверки состояния работоспособности сервера приложений показало неоднозначность документации и специфичность работы алгоритмов исключения сервера из пула рабочих серверов.

Краткие сведения о балансировке HTTP трафика


Существуют различные способы балансировки HTTP трафика. По уровням модели OSI бывают технологии балансировки на сетевом, транспортном и прикладном уровнях. В зависимости от масштабов приложения могут использоваться их комбинации.

Технология балансировки трафика дает положительные эффекты в работе приложения и его обслуживания. Вот некоторые из них. Горизонтальное масштабирование приложения, при котором нагрузка распределяется среди нескольких узлов. Плановый вывод из эксплуатации сервера приложений за счет снятия с него потока клиентских запросов. Реализация стратегии A/B тестирования измененного функционала приложения. Повышение отказоустойчивости приложения путем направления запросов на исправно функционирующие серверы приложений.

Последняя функция реализовывается в двух режимах. В пассивном режиме балансировщик в клиентском трафике оценивает ответы целевого сервера приложений и при определенных условиях исключает его из пула рабочих серверов. В активном режиме балансировщик периодически самостоятельно направляет запросы на сервер приложений по заданному URI, и по определенным признакам ответа принимает решение об исключении его из пула рабочих серверов. В дальнейшем, балансировщик, при определенных условиях, возвращает сервер приложений в пул рабочих серверов.

Пассивная проверка сервера приложений и его исключение из пула рабочих серверов


Рассмотрим подробнее пассивную проверку сервера приложений в свободно распространяемой редакции nginx/1.17.0. Серверы приложений выбираются поочередно алгоритмом Round Robin, их веса одинаковы.

На трех-шаговой схеме представлен временной участок, начинающийся с направления клиентского запроса на сервер приложений №2. Светлый индикатор характеризует запросы/ответы между клиентом и балансировщиком. Темный индикатор – запросы/ответы между nginx и серверами приложений.



На третьем шаге схеме показано как балансировщик перенаправляет запрос клиента на следующий сервер приложений, в случае, если целевой сервер дал ответ с ошибкой или вообще не ответил.

Перечень HTTP- и TCP-ошибок, при которых сервер использует следующий сервер задается в директиве proxy_next_upstream.

По умолчанию nginx повторно перенаправляет на следующий сервер приложений только запросы c идемпотентными HTTP методами.

Что же получает клиент? С одной стороны, возможность перенаправления запроса на следующий сервер приложений увеличивает шансы предоставить удовлетворительный ответ клиенту при выходе из строя целевого сервера. С другой, очевидно, что последовательное обращение сначала на целевой сервер, а затем на следующий увеличивает общее время ответа клиенту.

В конце концов, клиенту возвращается ответ сервера приложений, на котором закончился счетчик допустимых попыток proxy_next_upstream_tries.

При использовании функции перенаправления на следующий рабочий сервер нужно дополнительно гармонизировать таймауты на балансировщике и серверах приложений. Верхним ограничением времени «путешествия» запроса между серверами приложений и балансировщиком является таймаут клиента, либо время ожидания, определенное бизнесом. При расчете таймаутов, также необходимо учесть запас на сетевые события (задержки/потери при доставке пакетов). Если клиент всякий раз будет завершать сессию по таймауту пока балансировщик добывает гарантированный ответ, благое намерение сделать приложение надежным будет тщетным.



Управление пассивной проверкой работоспособности серверов приложений выполняется директивами, например, со следующими вариантами их значений:

upstream backend {
    server app01:80 weight=1 max_fails=5 fail_timeout=100s;
    server app02:80 weight=1 max_fails=5 fail_timeout=100s;
}
server {
    location / {
        proxy_pass			http://backend;
        proxy_next_upstream		timeout http_500;
        proxy_next_upstream_tries 	1;
        ...
    }
    ...
}

По состоянию на 02.07.2019 документацией установлено, что параметр max_fails задаёт число неудачных попыток работы с сервером, которые должны произойти в течение времени, заданного параметром fail_timeout.

Параметр fail_timeout задаёт время, в течение которого должно произойти заданное число неудачных попыток работы с сервером для того, чтобы сервер считался недоступным; и время, в течение которого сервер будет считаться недоступным.

В приведенном примере части конфигурационного файла балансировщик настроен на отлов 5 неудачных обращений в течение 100 секунд.

Возвращение сервера приложений в пул рабочих серверов


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

Без проведения эксперимента можно только предположить, что механизм проверки состояния аналогичен ранее описанному.

Ожидания и реальность


В представленной конфигурации от баланисровщика ожидается следующее поведение:

  1. До тех пор, пока балансировщик не исключит сервер приложений №2 из пула рабочих серверов, на него будут направляться запросы клиента.
  2. Запросы, возвращаемые с 500 ошибкой от сервера приложений №2 будут пересылаться на следующий сервер приложений, и клиент получит положительные ответы.
  3. Как только балансировщик в течении 100 секунд получит 5 ответов с кодом 500, он исключит сервер приложений №2 из пула рабочих серверов. Все запросы, следующие после 100 секундного окна, будут сразу направляться на оставшиеся рабочие серверы приложений без дополнительных затрат времени.
  4. Балансировщик по истечению 100 секунд каким-то образом должен оценить работоспособность сервера приложений и вернуть его в пул рабочих серверов.

Проведя натуральные испытания, по журналам балансировщика установлено, что утверждение №3 не работает. Балансировщик исключает неработоспособный сервер, как только исполнится условие по параметру max_fails. Таким образом, неисправный сервер исключается из обслуживания не дожидаясь истечения 100 секунд. Параметр fail_timeout играет роль только верхнего предела времени накопления ошибок.

В части утверждения №4 выясняется, что nginx проверяет работоспособность ранее исключенного из обслуживания сервера приложения только одним запросом. И если сервер по-прежнему отвечает ошибкой, то следующая проверка состоится по истечению fail_timeout.

Чего не хватает?


  1. Реализованный в nginx/1.17.0 алгоритм, возможно, не самым справедливым образом проверяет работоспособность сервера перед его возвращением в пул рабочих серверов. Как минимум, по действующей документации ожидается не 1 запрос, а количество, указанное в max_fails.
  2. Алгоритм проверки состояния не учитывает скорость запросов. Чем она больше, тем сильнее спектр с неудачными попытками сдвигается влево, и сервер приложений слишком быстро выбывает из пула рабочих серверов. Предположу, что это может негативно сказаться на приложениях, которые позволяют себе «короткими во времени сгустками» давать ошибки. Например, при сборке мусора.



Хотел у вас спросить, есть ли практическая польза от алгоритма проверки работоспособности сервера, в котором оценивается скорость неудачных попыток?
Теги:
Хабы:
Всего голосов 9: ↑9 и ↓0+9
Комментарии4

Публикации

Истории

Работа

Ближайшие события