Что такое HAProxy и как он работает
Название «HAProxy» обозначает продукт, а «haproxy» — исполняемую программу, программный пакет или процесс. Однако оба варианта часто используются в обоих значениях и произносятся как H-A-Proxy. На раннем этапе «haproxy» расшифровывалось как «прокси высокой доступности», а название писалось в два отдельных слова, хотя сейчас оно означает только «HAProxy».
3.1. Чем является и чем не является HAProxy
HAProxy — это:
TCP-прокси: он может принять TCP-соединение на прослушивающем сокете, подключиться к серверу и связать эти сокеты, обеспечивая передачу трафика в обоих направлениях; с обеих сторон поддерживаются IPv4, IPv6 и даже сокеты UNIX, что даёт простой способ преобразовывать адреса между разными семействами.
обратный HTTP-прокси (в терминологии HTTP — «шлюз»): он выступает в качестве сервера, получает HTTP-запросы по соединениям, принятым на прослушивающем TCP-сокете, и передаёт запросы из этих соединений серверам по другим соединениям. Он может использовать любую комбинацию HTTP/1.x и HTTP/2 с любой стороны и даже автоматически определяет протокол каждой стороны при использовании ALPN поверх TLS.
средство завершения, инициирования и разгрузки SSL: SSL/TLS можно использовать на соединении от клиента, на соединении к серверу или даже на обоих соединениях. Многие параметры можно задавать для отдельных имён (SNI) и обновлять во время выполнения без перезапуска. Такие конфигурации прекрасно масштабируются: сообщалось о развёртываниях, использующих от десятков до сотен тысяч сертификатов.
нормализатор TCP: поскольку соединения локально завершаются операционной системой, их стороны не связаны между собой, поэтому аномальный трафик, например некорректные пакеты, сочетания флагов, объявления окон, номера последовательности, незавершённые соединения (SYN-флуд) и тому подобное, не передаётся на другую сторону. Это защищает уязвимые стеки TCP от атак на протокол, а также позволяет оптимизировать параметры соединения с клиентом без изменения настроек стеков TCP на серверах.
нормализатор HTTP: при настройке обработки HTTP-трафика передаются только корректные полные запросы. Это защищает от множества атак на протокол. Кроме того, отклонения от протокола, допустимые по спецификации, исправляются, чтобы не вызывать проблем на серверах (например, многострочные заголовки).
инструмент исправления HTTP: он может изменять, исправлять, добавлять, удалять и переписывать URL или любой заголовок запроса либо ответа. Это помогает устранять проблемы совместимости в сложных средах.
коммутатор на основе содержимого: он может учитывать любой элемент запроса, решая, какому серверу передать запрос или соединение. Поэтому через один порт можно обслуживать несколько протоколов (например, HTTP, HTTPS, SSH).
балансировщик серверной нагрузки: он может распределять TCP-соединения и HTTP-запросы. В режиме TCP решение о балансировке принимается для всего соединения. В режиме HTTP решение принимается для каждого запроса.
регулятор трафика: он может ограничивать интенсивность в различных точках, защищать серверы от перегрузки, менять приоритеты трафика в зависимости от содержимого и даже передавать эту информацию нижним уровням и внешним сетевым компонентам с помощью маркировки пакетов.
средство защиты от DDoS и злоупотребления сервисом: он может вести обширную статистику по IP-адресам, URL, файлам cookie и другим признакам, выявлять злоупотребления и принимать меры (замедлять нарушителей, блокировать их, перенаправлять к устаревшему содержимому и т. д.).
точка наблюдения для устранения сетевых неполадок: благодаря точности информации, записываемой в журналы, он часто используется для сужения круга причин сетевых проблем.
средство разгрузки HTTP-сжатия: он может сжимать ответы, которые сервер не сжал, сокращая время загрузки страниц для клиентов с плохим подключением или использующих мобильные сети с высокой задержкой.
кэширующий прокси: он может кэшировать ответы в оперативной памяти, чтобы последующие запросы того же объекта не требовали повторной передачи по сети с сервера, пока объект остаётся в кэше и сохраняет актуальность. При этом объекты не сохраняются в постоянном хранилище. Учтите, что эта функция кэширования не требует обслуживания и направлена исключительно на экономию ценных ресурсов haproxy, а не ресурсов сервера. Кэши, предназначенные для оптимизации серверов, требуют гораздо более тонкой настройки и гибкости. Если нужен такой расширенный кэш, используйте Varnish Cache, который прекрасно интегрируется с haproxy, особенно когда SSL/TLS требуется с любой из сторон.
шлюз FastCGI: FastCGI можно рассматривать как другое представление HTTP, и поэтому HAProxy может непосредственно распределять нагрузку по группе серверов приложений FastCGI в любых сочетаниях, без дополнительного уровня шлюза между ними. Это экономит ресурсы и снижает затраты на обслуживание.
HAProxy не является:
явным HTTP-прокси, то есть прокси, через который браузеры выходят в Интернет. Для этой задачи есть отличное специализированное ПО с открытым исходным кодом, например Squid. Однако HAProxy можно установить перед таким прокси для балансировки нагрузки и обеспечения высокой доступности.
средством очистки данных: он не изменяет тела запросов или ответов.
статическим веб-сервером: при запуске он изолирует себя в окружении chroot и сбрасывает привилегии, поэтому после запуска вообще не обращается к файловой системе. По этой причине его невозможно превратить в статический веб-сервер (однако динамические серверы поддерживаются через FastCGI). Для этого есть отличное ПО с открытым исходным кодом, например Apache и Nginx, а HAProxy можно легко установить перед ними для балансировки нагрузки, обеспечения высокой доступности и ускорения.
балансировщиком нагрузки на уровне пакетов: он не видит IP-пакеты или UDP-дейтаграммы, не выполняет NAT и тем более DSR. Эти задачи относятся к нижним уровням. Некоторые компоненты на уровне ядра, например IPVS (Linux Virtual Server), уже прекрасно с ними справляются и отлично дополняют HAProxy.
3.2. Как работает HAProxy
HAProxy — это неблокирующий движок с событийной архитектурой, сочетающий очень быстрый уровень ввода-вывода с многопоточным планировщиком на основе приоритетов. Поскольку он изначально предназначен для пересылки данных, его архитектура оптимизирована для максимально быстрой передачи данных с минимальным числом операций. Особое внимание уделяется эффективному использованию кэша CPU: соединения закрепляются за одним CPU как можно дольше. Для этого реализована многоуровневая модель с механизмами обхода на каждом уровне, которые гарантируют, что данные не попадут на более высокие уровни без необходимости. Основная обработка происходит в ядре, а HAProxy старается помочь ядру выполнить работу как можно быстрее, передавая подсказки или избегая определённых операций, если предполагает, что их можно будет сгруппировать позже. В результате типичное распределение времени обработки составляет 15% в HAProxy и 85% в ядре в режиме TCP или HTTP close и около 30% в HAProxy и 70% в ядре в режиме HTTP keep-alive.
Один процесс может запускать множество экземпляров прокси; сообщалось об успешной работе конфигураций с 300000 отдельными прокси в одном процессе. Системы с одним процессором и одним ядром более чем достаточно для более чем 99% пользователей, поэтому пользователям контейнеров и виртуальных машин рекомендуется выбирать самые маленькие доступные образы, чтобы снизить эксплуатационные затраты и упростить устранение неполадок. Однако машина, на которой работает HAProxy, ни при каких обстоятельствах не должна использовать подкачку, а её CPU нельзя искусственно ограничивать (выделяя долю CPU в гипервизоре) или делить с ресурсоёмкими вычислительными процессами, которые создавали бы очень большую задержку переключения контекста.
Многопоточность позволяет задействовать всю доступную вычислительную мощность, используя один поток на ядро CPU. Это особенно полезно для SSL или когда требуется скорость пересылки данных выше 40 Гбит/с. В таких случаях критически важно избегать взаимодействия между несколькими физическими CPU: оно может создавать серьёзные узкие места в сетевом стеке и в самом HAProxy. Хотя некоторым это кажется нелогичным, при возникновении проблем с производительностью первым действием часто должно быть уменьшение числа CPU, на которых работает HAProxy.
Для работы HAProxy нужны только исполняемый файл haproxy и файл конфигурации. Для ведения журнала настоятельно рекомендуется настроить демон syslog и ротацию журналов. Журналы также можно отправлять в stdout/stderr, что бывает полезно внутри контейнеров. Файлы конфигурации разбираются до запуска, затем HAProxy пытается привязать все прослушивающие сокеты и отказывается запускаться, если что-либо не удалось. После этого сбои уже невозможны. Это означает, что ошибок во время выполнения не возникает и, если запуск прошёл успешно, программа будет работать до остановки.
После запуска HAProxy выполняет ровно 3 действия:
обрабатывает входящие соединения;
периодически проверяет состояние серверов (проверки работоспособности);
обменивается информацией с другими узлами haproxy.
Обработка входящих соединений — безусловно, самая сложная задача, поскольку зависит от множества вариантов конфигурации, однако её можно свести к следующим 9 шагам:
принять входящие соединения с прослушивающих сокетов, принадлежащих сущности конфигурации «frontend», которая ссылается на один или несколько прослушиваемых адресов;
применить к этим соединениям правила обработки фронтенда, которые могут привести к их блокировке, изменению некоторых заголовков или перехвату для выполнения внутренних апплетов, таких как страница статистики или CLI;
передать эти входящие соединения другой сущности конфигурации, представляющей группу серверов «backend», которая содержит список серверов и стратегию балансировки нагрузки для этой группы серверов;
применить к этим соединениям правила обработки бэкенда;
выбрать сервер для передачи соединения в соответствии со стратегией балансировки нагрузки;
применить к данным ответа правила обработки бэкенда;
применить к данным ответа правила обработки фронтенда;
создать запись в журнале с подробным описанием произошедшего;
в случае HTTP вернуться ко второму шагу и ждать нового запроса, иначе закрыть соединение.
Фронтенды и бэкенды иногда считают половинами прокси, поскольку каждый из них работает только с одной стороной сквозного соединения: фронтенд — только с клиентами, а бэкенд — только с серверами. HAProxy также поддерживает полные прокси, которые представляют собой точное объединение фронтенда и бэкенда. Когда нужна обработка HTTP, конфигурацию обычно разделяют на фронтенды и бэкенды: это открывает много возможностей, поскольку любой фронтенд может передать соединение любому бэкенду. Для прокси, работающих только с TCP, разделение на фронтенды и бэкенды редко даёт преимущество, а конфигурация с полными прокси может быть удобнее для чтения.