Количество посетителей интернет-магазинов, пользователей SaaS, развлекательных и образовательных порталов растет быстрыми темпами, что требует от разработчиков новых подходов к созданию масштабируемых высоконагруженных систем, предоставляющих веб-сервисы множеству одновременно работающих пользователей.
Большинство веб-приложений сегодня создается с использованием трехзвенного распределенного подхода (рис. 1). При доступе к ресурсам веб-приложения запрос пользователя сначала обрабатывается DNS-сервером, который выдает пользователю IP-адрес одного из интерфейсных серверов переднего плана (front-end). Пользователь взаимодействует с одним из таких серверов, обеспечивающих обработку статического содержания и формирование визуального результата выполнения запроса, а также создание защищенного соединения. При обработке динамических запросов, требующих вычислительных действий или запроса к динамически формируемым данным, выполняется переадресация запроса на сервер приложений среднего плана (middle-end). Сервер приложений, в свою очередь, взаимодействует с серверами заднего плана, отвечающими за хранение данных (back-end).
Рис. 1. Архитектура распределенного приложения |
Для построения высоконагруженных систем в качестве внешних серверов чаще всего используются серверы nginx, HAProxy, в качестве серверов среднего плана — Apache, Microsoft IIS и т. п., а в качестве внутренних серверов — решения на основе MySQL, PostgreSQL Oracle, Microsoft SQL Server, и т. д.
Для достижения максимальной производительности серверов приложений и серверов переднего плана на них могут разворачиваться программные средства кэширования и оптимизации хранения статических и часто используемых данных (Varnish Cache, Memcached). Для повышения производительности и внедрения механизмов нагруженного резервирования на каждом уровне выполняется горизонтальное масштабирование аппаратных ресурсов за счет использования дополнительного оборудования вплоть до создания инфраструктур на географически разнесенных площадках. Основная проблема, которая при этом возникает, — это организация эффективного распределения нагрузки между всеми аппаратными платформами, на которых функционирует распределенное приложение. Однако, несмотря на распределение вычислительной нагрузки между серверными платформами и внедрение средств кэширования, производительность приложения будет ограничена неким предельным значением, зависящим от ресурсов аппаратной платформы. Кроме того, при увеличении числа элементов в любой информационной системе с последовательной обработкой возрастает вероятность отказов любого из них, что в конечном счете приводит к снижению общей надежности приложения.
Методы распределения нагрузки
Балансировка в облаках
При построении облачных инфраструктур важной задачей является распределение нагрузки между компонентами, однако существующие решения по балансировке обладают рядом ограничений. Александр Пономарев, Владислав Носков, Кирилл Криницын |
На сегодняшний день самые популярные методы распределения нагрузки — это циклический (алгоритм round robin) и взвешенное обслуживание (алгоритм Weighted Fair Queuing). Циклический метод чаще всего используется для организации равномерного распределения нагрузки между адресатами, входящими в один список. Каждый новый запрос поступает к следующему получателю по списку. При достижении конца списка происходит возвращение к первой позиции. Взвешенное обслуживание предполагает распределение поступающей нагрузки пропорционально заданным «весам» получателей. Эти алгоритмы применяются сейчас почти на всех уровнях распределенной архитектуры; например, на уровне front-end балансировка выполняется сервером DNS, содержащим таблицу соответствия конкретного адреса (имени) сайта и IP-адреса. При указании нескольких IP-адресов для одного имени между ними будет выполняться балансировка по алгоритму round robin с равномерным распределением нагрузки. Для того чтобы DNS-сервер реализовывал алгоритм взвешенного обслуживания в рамках циклического перебора, можно несколько раз вписать одно и то же имя с одинаковым IP-адресом, и тогда в пределах одного цикла DNS-сервер будет выдавать несколько раз одинаковый IP-адрес. Таким образом, пользователи будут попадать на разные front-end серверы пропорционально количеству упоминаний IP-адреса данного сервера в конфигурации DNS.
На уровне middle-end за балансировку нагрузки, как правило, отвечает прокси-сервер, установленный на уровне front-end и позволяющий не только кэшировать часть контента и создавать еще один уровень безопасности системы, но и распределить пользователей по серверам приложений. Например, прокси-сервер nginx имеет в своем арсенале модуль upstream, который при помощи алгоритма взвешенного обслуживания распределяет запросы пользователей по разным серверам приложений. Помимо встроенных средств DNS и nginx распределение нагрузки между серверными платформами кэширующих серверов переднего плана, серверов бизнес-логики (middle-end) может производиться также с использованием специализированных аппаратно-программных комплексов, подобных продуктам NetScaler ADC от компании Citrix, BIG-IP от компании F5 Networks и т.п.
На уровне back-end, как правило, балансировка нагрузки выполняется средствами кластеров баз данных и ОС.
Большинство из имеющихся решений балансировки (в том числе и встроенные средства DNS/nginx) имеют либо статические фиксированные пропорции распределения нагрузки, либо, как специализированные аппаратно-программные комплексы, анализируют косвенные показатели загрузки серверных платформ, что может приводить к перекосам в загрузке серверных платформ и, как следствие, к неэффективному использованию имеющихся ресурсов. Такие перекосы возникают при использовании разнородных аппаратных платформ в пределах одного уровня, выходе из строя платформ, появлении задач, дополнительно нагружающих процессор (архивирование данных резервного копировании) и т. п. Данные задачи не могут эффективно отслеживаться системами балансировки и корректироваться имеющимися инструментами в автоматическом режиме.
На рис. 2 приведены графики загрузки процессоров серверных платформ среднего уровня при росте числа сессий приложения для серверов с различными процессорными ресурсами (А — с процессором 1,2 ГГц, Б — двухпроцессорная система 2,4 ГГц, В — с процессором 1,6 ГГц) при равномерном распределении нагрузки между ними.
Рис. 2. Зависимость загрузки процессоров серверов от количества сессий при равномерном распределении |
По оси X отложено суммарное количество сессий, которые устанавливаются с приложением. По оси Y — загрузка процессоров для отдельных серверов среднего уровня. Из графика видно, что уже на 177 сессиях серверная платформа А выходит на уровень загрузки выше 80%, что при последующем росте запросов приводит к деградации сервиса, однако при этом ресурсы двух оставшихся серверных платформ остаются невостребованными.
Оптимизация распределения нагрузки
В рамках проводимых в Уральском федеральном университете работ по созданию оптимальных средств балансировки для облачных платформ был разработан алгоритм установления оптимальных пропорций распределения нагрузки между вычислительными платформами на основании определения относительного рейтинга аппаратной платформы. Относительный рейтинг может быть рассчитан исходя из оценки доли запросов (Ni/∑N), которые были отправлены на аппаратную платформу, и загрузки процессора (Li), которая возникает в результате обработки данной доли запросов. По своему смыслу относительный рейтинг указывает на долю от общего числа запросов, которые обрабатываются аппаратной платформой в расчете на один процент загрузки процессора. Формула для вычисления относительного рейтинга имеет следующий вид: ,
где Ri — относительный рейтинг аппаратной платформы, Ni — доля от общего числа обращений к приложению, Li — значение загрузки процессора на аппаратной платформе, m — общее количество аппаратных платформ, между которыми возможна балансировка нагрузки. Зная относительный рейтинг, определяющий возможности платформ относительно друг друга, можно рассчитать такие значения доли запросов, отправляемых на каждую платформу, при которых значения загрузки процессора различных аппаратных платформ будут приблизительно равны. Иначе говоря, можно рассчитать долю отправляемых запросов пропорционально вычисленному относительному рейтингу платформы.
В приведенном ранее примере (рис. 2) оптимальным будет распределение запросов в долях А — 0,2, Б — 0,53, В — 0,27 соответственно (рис. 3).
Рис. 3. Зависимость загрузки серверов при оптимальном распределении |
Применение алгоритма позволяет на тех же аппаратных ресурсах почти в полтора раза увеличить количество одновременно обслуживаемых пользовательских сессий без деградации сервиса (287 сессий против 177 при равномерном распределении).
Данный алгоритм также отрабатывает ситуации увеличения загрузки процессора на отдельных серверных платформах (периодически корректируя пропорции распределения нагрузки) или фатальных нарушений в работе серверов (устанавливая долю запросов, направляемых на сервер, равной нулю). Подобные ситуации могут иметь как долгосрочный характер (организация на аппаратной платформе дополнительной роли или дополнительного приложения, вывод сервера из эксплуатации), так и кратковременный характер (создание резервной копии данных на серверной платформе, профилактика). К примеру, при размещении дополнительного приложения на сервере А, на которое тратится такая же часть ресурсов процессора, как и на основное приложение, пропорции распределения загрузки будут изменены: вместо значений распределения А — 0,2, Б — 0,53, В — 0,27 установленные пропорции составят А — 0,13, Б — 0,57, В — 0,3. Достигаемое при этих условиях количество обслуживаемых приложением сессий будет в 2,6 раза выше, чем при равномерном распределении загрузки (231 относительно 89 при равномерном распределении).
Основной параметр, на основании которого выполняется распределение нагрузки и который используется в алгоритме, — текущая загрузка процессора сервера, которую можно получить с помощью протокола SNMP. Изначально протокол SNMP был разработан для контроля функционирования сетевого коммутационного оборудования, но впоследствии сфера его действия охватила и другие сетевые устройства, такие как маршрутизаторы, терминальные серверы, серверы приложений, персональные компьютеры и т. д. Для большинства современных ОС написаны агенты либо доступны программные агенты от сторонних производителей, а также распространяемые под лицензиями GPL.
При помощи SNMP получить информацию о системе можно через базу управляющей информации MIB, представляющую собой совокупность объектов, доступных для операций записи/чтения для каждого конкретного клиента, в зависимости от структуры и предназначения самого клиента. Для получения сведений о текущей загруженности процессора, необходимой для определения пропорций балансировки, используются две специализированные функции snmpget и snmpwalk. Первая позволяет опросить сервер по фиксированному идентификатору Object ID для нахождения значения параметра загрузки центрального процессора, а вторая дает возможность запросить в табличной форме загрузку каждого процессора в многопроцессорной системе.
Балансировщик
Балансировщик УрФУ распространяется под лицензией GPL и в ходе своей работы с помощью функций snmpget и snmpwalk опрашивает заданные узлы с целью получения данных для вычисления относительного рейтинга каждого сервера. После формирования рейтинга балансировщик корректирует конфигурационные файлы DNS-сервера (BIND) или серверов front-end (nginx). Например, первоначальный конфигурационный фрагмент файла зон для DNS-сервера BIND9 в случае равномерного распределения нагрузки между серверами front-end выглядит следующим образом:
www.mydomain1.com IN A 192.168.0.34
www.mydomain1.com IN A 192.168.0.35
www.mydomain1.com IN A 192.168.0.36
Поскольку используется механизм циклического перебора указанных IP-адресов, а частота их встречи в файле конфигураций одинакова, то распределение нагрузки будет равномерным. В процессе вычисления и округления значения требуемых пропорций нагрузки, балансировщик может изменить конфигурационный файл BIND следующим образом:
www.mydomain1.com IN A 192.168.0.34
www.mydomain1.com IN A 192.168.0.35
www.mydomain1.com IN A 192.168.0.35
www.mydomain1.com IN A 192.168.0.35
www.mydomain1.com IN A 192.168.0.36
В результате при последующем циклическом переборе DNS-сервер вернет адрес сервера 192.168.0.35 в три раза чаще, чем остальные, это приведет к распределению запросов между серверами в пропорции 192.168.0.34 — 0,2, 192.168.0.35 — 0,6, 192.168.0.36 — 0,2.
В случае использования nginx, за адреса серверов в зоне отвечает модуль upstream, и для задания аналогичного распределения нагрузки достаточно в конфигурации указать пропорции распределения:
server 192.168.0.34 weight=1;
server 192.168.0.35 weight=3;
server 192.168.0.36 weight=1;
После изменения конфигурационного файла происходит перезагрузка конфигураций без перезагрузки самого сервиса — для сервера BIND9 это реализуется с помощью вызова команды rndc reload, а для nginx используется команда nginx reload. После перезагрузки конфигурационных файлов BIND, nginx для всех вновь устанавливающихся сессий будет производиться оптимальное распределение запросов между серверными платформами.
Помимо опроса параметров загрузки процессора, балансировщик выполняет дополнительный опрос следующих параметров: объем свободной памяти, объем свободного пространства на дисках, объем свободной виртуальной памяти. Данные параметры не используются для расчета пропорций распределения нагрузки, однако выполняют роль индикатора корректного функционирования серверной платформы.
Балансировщик запускается на платформе либо DNS-сервера или сервера nginx, либо на выделенном сервере, сбои в работе которого не приведут к нарушению в функционировании приложения в целом, а только ухудшат оптимальность распределения нагрузки в рамках отдельного уровня.
На рис. 4 приведена общая архитектура распределенного Web-приложения, построенного с использованием средств распределения нагрузки. Между серверами переднего плана распределение нагрузки выполняется средствами балансировки DNS, между серверами среднего плана — средствами nginx.
Рис. 4. Распределение нагрузки на уровнях Web-приложения |
Предложенный механизм балансировки может использоваться как в составе отдельной инфраструктуры Web-приложения, так и в составе инструментальной платформы разработки облачных приложений. В частности, сегодня система «Балансировщик» используется в составе SaaS-платформы Saanki, разрабатываемой в компании «Нау-Сервис» и УрФУ. Платформа Saanki предназначена для запуска в облаках приложений на Java или Ruby и используется как основа для построения частного облака и организации предоставления публичных сервисов.
Перспективы
Разработанный алгоритм распределения нагрузки и система на его основе в ряде случаев позволяют в несколько раз увеличить количество пользователей, обслуживаемых на уже имеющихся аппаратных платформах, что существенно упрощает процесс горизонтального масштабирования аппаратных средств. Однако текущая версия продукта еще не дает возможности распределить нагрузку на основе информации о загруженности нескольких уровней аппаратных платформ. Подобная задача возникает при разворачивании Web-приложения на нескольких географически разнесенных ЦОД, для эффективного разнесения нагрузки которых требуется учитывать не только загрузку серверов переднего плана, но и одновременно загрузку серверов среднего плана. В рамках подобной балансировки следует также принять во внимание удаленность пользователя от ЦОД и выбрать оптимальный ЦОД с точки зрения времени задержки при передаче данных. Эта функциональность будет реализована в следующих версиях «Балансировщика».
Владислав Носков (vynoskov@gmail.com) — старший преподаватель, Кирилл Криницын, Александр Пономарев — студенты Уральского федерального университета (Екатеринбург).