Назад | Перейти на главную страницу

Веб-сервер Apache блокирует подключение к внешнему интерфейсу при ошибке обратного прокси

У нас проблема с относительно глупым балансировщиком нагрузки, который находится перед веб-сервером Apache. Веб-сервер Apache снова является обратным прокси-сервером для сервера приложений.

Проблема начинается, когда приложение выходит из строя. Это заставляет Apache выдавать код ошибки.

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

Можно ли настроить Apache для отклонения запроса tcp при бэкэнд-ошибке?

Haproxy может отклонять TCP-соединения на основе динамических условий, включая количество серверов, доступных на бэкэнде. Ключевое слово config - это соединение tcp-request. (Ссылка на документы ниже.)

Так что, может быть, поставить haproxy перед Apache (я знаю, я знаю! Три уровня?!?!) Или, может быть, использовать haproxy вместо Apache.

Может выглядеть так (не проверено):

frontend http-in
  bind *:80
  mode http
  tcp-request connection reject if nbsrv(appfarm) lt 1
  default_backend appfarm

backend appfarm
  server appsrv01 127.0.0.1:8888 check

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

Вероятно, это не будет работать с самим apache httpd. Проблема в том, что ваше неудачное приложение заставляет apache httpd генерировать ошибку. Эта ошибка возникает только тогда, когда вы действительно запрашиваете URL-адрес из этого приложения. Apache httpd нужен URL-адрес, чтобы решить, является ли это ошибкой, и чтобы получить URL-адрес от клиента, ему необходимо TCP-соединение.

Что вы можете сделать в качестве обходного пути: вы можете написать довольно простой скрипт, который считывает поток ErrorLog на stdin, а затем блокирует запросы от ваших балансировщиков нагрузки (возможно, iptables), когда ошибки начинают происходить. Затем этот сценарий можно настроить как приемник журнала ошибок apache httpd с помощью директивы ErrorLog.

Это отключило бы внутренний сервер apache httpd, но никогда не включит его автоматически.

Я перенесу логику в балансировщик нагрузки, если нет возможности заменить существующий балансировщик нагрузки, установите небольшой nginx на каждом сервере Apache для прокси-соединения.

[Пользователь] - [Балансировщик нагрузки] - [Nginx] - [Apache]

Используя nginx как балансировщик нагрузки или обратный прокси у вас есть доступ к ответам восходящего потока (в вашем случае Apache), и вы можете создавать правила, которые оценивают код ответа, прежде чем отвечать конечному клиенту:

$ upstream_status сохраняет код состояния ответа, полученного от вышестоящего сервера. Коды состояния нескольких ответов разделяются запятыми и двоеточиями, как адреса в переменной $ upstream_addr. Если сервер не может быть выбран, переменная сохраняет код состояния 502 (Плохой шлюз).

Примеры правил Nginx

Вызовите API балансировщика нагрузки, чтобы удалить узел, если он доступен:

if ($upstream_status != 200) {
    return 301 return 301 http://loadbalance/api/remove/node;
} 

Вызов локального скрипта (пожалуйста, проверьте безопасность), чтобы убить Apache и попросить пользователя перезагрузить страницу (в следующий раз он будет использовать другой сервер). Оно использует ngx_http_lua_module.

if ($upstream_status != 200) {
   content_by_lua_block {
     os.execute("/bin/killapache.sh")
   } 
   return 301 https://$host$request_uri;
}