Я новичок в использовании HAProxy для балансировки нагрузки моего приложения, которое в настоящее время запускает пять экземпляров серверного приложения. Моя установка относительно проста. У меня есть приложение Ruby, которое использует волокна, EventMachine и thin, чтобы попытаться сохранить его как можно более неблокирующим. Таким образом, большинство запросов будут возвращаться быстро или, по крайней мере, они не будут блокировать сервер приложений, поэтому он может обслуживать несколько запросов одновременно.
Однако есть некоторые запросы (например, загрузка изображений, которые требуют доступа к командам оболочки), которые могут быть медленными и блокировать сервер приложений.
Я обнаружил, что прямой циклический стиль балансировки здесь не имеет смысла, поскольку запросы, которые можно обрабатывать одновременно и быстро возвращать, остаются позади медленных запросов. Как лучше всего с этим справиться?
Я рассмотрел:
Наличие проверки работоспособности, которая выполняется часто (скажем, каждые 250 мс), чтобы проверить, отвечает ли сервер. Если это не так, предположим, что он «не работает» (скорее всего, блокируется длинный запрос), что заставит HAProxy маршрутизировать запросы вокруг него. Однако в этом сценарии есть вероятность, что все 5 экземпляров могут быть заблокированы.
Имейте заранее определенный список URL-адресов медленных запросов, назначьте 2 или 3 серверных модуля приложения для обработки только медленных запросов и перенаправьте все остальные на «быстрые» серверы. Теоретически быстрые запросы никогда не будут заблокированы, но этот подход кажется немного более хрупким, поскольку мне нужно будет убедиться, что если URL-адрес когда-либо изменится, я не забуду обновить свою конфигурацию HAProxy.
Я думаю, что последний подход, вероятно, лучше всего, но поскольку DevOps не является моей сильной стороной, я подумал, что проверю и посмотрю, что лучше всего подходит для этого сценария.
Конечно, «лучшая практика» - это, вероятно, перенести все длительные запросы в фоновые задачи, но в этом случае предположим, что у меня сейчас нет на это времени, если этого можно избежать :-)
Немного из столбца A, немного из столбца B :)
Ради бесперебойной работы вам обязательно следует использовать проверки работоспособности в HAProxy независимо от чего-либо еще. Если один из ваших внутренних узлов выходит из строя, вы хотите, чтобы HAProxy перестал отправлять ему запросы. Ошибка не обязательно должна быть в вашем приложении, это может быть аппаратное обеспечение, сеть или что угодно. Это довольно просто настроить:
option httpchk GET /test HTTP/1.0\r\n
250 мс звучат как очень частая проверка. В таком случае ваши серверные серверы могут тратить много времени только на обработку проверок работоспособности. Вам нужно найти компромисс между стоимостью проверок работоспособности с точки зрения накладных расходов приложения и тем, насколько быстро вы хотите, чтобы мертвые узлы были отключены.
Вторую стратегию я использовал раньше. Выясните общее количество одновременных подключений, которое может обработать ваше приложение. Затем в HAProxy разделите запросы на медленные и быстрые и выделите каждому из них долю от общего числа подключений. Например.,
frontend myfrontend
bind *:80
acl url-slow path /some-long-running-request
use_backend slow-backend if url-slow
default_backend regular-backend
backend slow-backend
...
server backend1 1.2.3.4:80 maxconn 10
backend regular-backend
...
server backend1 1.2.3.4.:80 maxconn 90
Так, скажем, backend1 может обрабатывать 100 одновременных подключений. Выше мы выделяем 90 подключений для «обычных» запросов и 10 подключений для медленных запросов. Даже если вы израсходуете все свои медленные соединения, «обычные» запросы все равно будут обрабатываться.
Удачи!