Схемы балансировки нагрузки для web-серверов

Добавлено 22.11.2007 | Технологии

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

Нет денег на Cray? А зачем?

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

Многопроцессорные компьютеры уже много лет являются одним из способов наращивания мощности системы. Но является ли это решение единственным? Для некоторых приложений, пожалуй, да. Для других же, таких например, как web-приложения, конечно же - нет. Оно не только не единственное, оно еще и не самое лучшее.

С точки зрения бюджета

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

Масштабируемость

Вне зависимости от конструкции в машину можно установить определенный максимум процессоров. Многие дешевые сервера позволяют установить лишь два процессора. Многие высококлассные дорогие сервера имеют предел в 16 процессоров. Сравните: в спарке серверов может участвовать до 255 машин.

Производительность

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

Технологическое отставание

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

Гибкость

Во многопроцессорных машинах работает один тип операционной системы, один тип процессора, один тип памяти и так далее. Не так уж много пространства для маневра. Используя спарку серверов, вы можете смешивать машины с различными операционками, процессорами и объемами памяти. Если пожелаете, в спарку можно добавить и многопроцессорную машину. Различным машинам в спарке можно присвоить свои весовые коэффициенты, так что на более быстрые машины ляжет большая нагрузка, чем на более медленные.

Web-сайты из нескольких серверов

Типичный web-сайт состоит из одного web-севрера, которые обрабатывает HTTP-запросы. Этот сервер может динамически генерировать HTML-страницы, используя ASP, или просто отдавать статические страницы. Сервер может быть также взаимодействовать с базой данных, работающей на той же самой машине, либо на соседней. Эта конфигурация представлена на следующей схеме:

По мере увеличения числа пользователей производительность сервера начнет падать. Что в таком случае делать? Как правило, сначала анализируют всю систему программного обеспечения на сервере и удаляют узкие места и упрощают алгоритмы. Web-сервер можно усилить, увеличив число процессоров, объем оперативной памяти, и установив более быстрые жесткие диски. Однако в конце концов вы достигните точки, когда в значительной улучшить работу системы уже будет не возможно. Для интернет-приложений такая ситуация может возникнуть буквально за несколько дней. Очевидным решением этой проблемы является распределение или балансировка нагрузки между несколькими web-серверами.

Даже если вы не имеете дело с большими объемами данных, существуют и другие причины, по которым конфигурации с одним сервером не надежны. Основное предположение любого IT-специалиста заключается в том, что любая машина может выйти из строя. И если этой машиной является web-сервер, в лучшем случае пользователи не смогут получить доступ к сайту. В худшем случае, они могут потерять данные прямо в процессе совершения транзакции. Для коммерческого сайта это может иметь катастрофические последствия. Представьте себе, например, web-систему торговли акциями какой-нибудь брокерской конторы. Когда web-сайт недоступен, клиенты брокерской конторы могут потерять большие деньги в ожидании, пока система опять вернется в строй.

Кроме того, не забывайте, что остановка оборудования на обслуживание является обычным делом. Систематически публикуются множество бюллетеней, требующих в целях безопасности установить на приложение "заплаты" или обновления на операционную систему или какое-либо системное приложение. Регулярно требуется менять оборудование. Если у вас только один единственный сервер, для всех этих изменений вам придется полностью отключать сервер. Либо проводить обслуживание в "тихие" нерабочие часы, чем IT-персонал будет не сильно доволен.

И наконец, вопрос тестирования. Процесс разработки Web-приложений связан практически с постоянным внесение исправлений в сайт. Очень неплохо было бы сначала выложить новый вариант на отдельный сервер и дать внутренним пользователям проверить правильность его работы на сайте. Таким образом можно предотвратить ненужные вопросы и звонки от пользователей.

На следующем рисунке представлена конфигурация web-сайта из нескольких машин.

Запросы поступают на один из нескольких серверов. Этот сервер обрабатывает запрос и, если требуется, считывает данные из базы данных, или пишет в нее. Если какой-либо из web-серверов "падает", другие web-сервера просто принимают на себя дополнительные запросы. Эта конфигурация обеспечивает распределение нагрузки (load balancing) в том смысле, что нагрузка по обработке запросов распределяется между несколькими серверами. Такая конфигурация также обеспечивает отказоустойчивость системы (fault tolerance) в том смысле, что при выходе из строя одной машины сам web-сайт не выходит из строя.

Отклоняясь от темы, обратите внимание, что у нас web-серверов больше, чем серверов базы данных. Обычно, один сервер базы данных может справиться с нагрузкой, создаваемой несколькими web-серверами. Но и этот узел можно развязать, для чего потребуется несколько распределение нагрузки между несколькими серверами базы данных. С этой целью мы конфигурируем сервера баз данных в систему избыточной надежности (redundant configuration). То есть, у нас будет дополнительная (или избыточная) машина, чьей единственной задачей будет взять на себя нагрузку в том случае, когда "упадет" основная машина. Такая система также называется "противоотказная" (fail-over), так как все операции переносятся с одной машины на другую только в случае в случае отказа первой.

Схемы распределения нагрузки во многомашинной системе

Оставляя в стороне все "за" и "против" использования многомашинной системы (или как ее еще называют - server farm), давайте зададимся вопросом: "поскольку в Интернете каждому IP-адресу соответствует одна машина, каким же образом можно распределять нагрузку между несколькими машинами так, чтобы они извне выглядели как один единственный web-сайт?"

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

Существует несколько распространенных подходов в организации распределения нагрузки. Это:

- круговой DNS, когда для распределения нагрузки используется DNS-сервер

- аппаратное распределение нагрузки, когда используется прибор, схожий по своим функциям с маршрутизатором

- программное распределение нагрузки. Например программа "TCP/IP Network Load Balancing" от Microsoft.

- смешанные схемы, когда используется комбинация аппаратных и программных средств

Круговой DNS

Круговой DNS - это самый простой способ перенаправления HTTP-запросов на несколько серверов. Как вы знаете, любой DNS-сервер хранит пару "имя хоста/IP-адрес" для каждой машины в определенном домене. Этот список выглядит примерно так:

wrox.com		xxx.xxx.xxx.2
www.wrox.com	xxx.xxx.xxx.3

Помимо этого любому имени можно назначить несколько IP-адресов. В результате чего список будет выглядеть так:

wrox.com		xxx.xxx.xxx.2
www.wrox.com	xxx.xxx.xxx.3
www.wrox.com	xxx.xxx.xxx.4
www.wrox.com	xxx.xxx.xxx.5
www.wrox.com	xxx.xxx.xxx.6

DNS-сервер будет по кругу проходить по всем записям в таблице и отдавать на каждый новый запрос следующий IP-адрес. Так, на первый запрос DNS-сервер выдаст адрес "xxx.xxx.xxx.3", на второй - "xxx.xxx.xxx.4", а на третий - "xxx.xxx.xxx.4" и так далее. В результате все запросы будут поровну разделены между всеми web-серверами.

Балансировка

На первый взгляд это решение кажется неплохим и очень дешевым. Однако балансировка нагрузки здесь заключается лишь в том, что каждый из серверов получит равное количество запросов. Это подразумевает, что у каждого сервера в наличие имеется одинаковый объем ресурсов (вполне реальное предположение), и что им для выполнения всех операций необходимо одинаковое количество этих ресурсов (гораздо менее реальное предположение). В этом решении совершенно не учитывается, насколько сильно загружен процессор той или иной машины. Хоть в определенной степени мы здесь и добиваемся распределения нагрузки, этот способ чрезвычайно неэффективен для серьезных приложений.

Представим себе сцепку из двух серверов:

Например использование процессора на сервере А уже достигло пика в 100% из-за характера выполняемого HTTP-запроса. В это же время сервер В загружен, скажем, лишь на 10-15%. Схема кругового DNS по-прежнему будет направлять половину всех запросов на сервер А, который уже и так перегружен. Это не только неэффективно, но и приводит к тому, что пользователи будут нажимать кнопку "Refresh" снова и снова, видя что ваш сайт медленно отвечает, а значит, что они будут генерировать все больше и больше запросов. Продолжаться это будет до тех пор, пока пользователь не получит сообщение веселенькое "Server too busy".

Отказоустойчивость

Кроме того, эта схема никак не поможет в случае выхода какой-либо из машин из строя. Обратимся опять к примеру выше. Если сервер А выработает свой ресурс и "свалится", половина HTTP-запросов все равно будет перенаправляться на уже недоступную машину. В результате пользователь получит еще более веселенькое сообщение "Server Unavailable".

Многие DNS-сервера кэшируют у себя таблицы соответствий. Кэширование таблиц DNS может привести к тому, что схема кругового DNS вообще теряет всякий смысл. Так как локальный DNS-сервер клиента запишет у себя только одно соответствие "доменное имя/IP-адрес", все клиенты этого локального DNS-сервера будут все время обращаться на один и тот же IP-адрес. С течением времени нагрузка на те машины, что были запущены раньше, будет увеличиваться до тех пор, пока они не "упадут".

В самом радикальном случае, при выходе из строя всего лишь одной машины у тысяч клиентов, из-за кэширования завязанных на IP-адрес упавшей машины, создастся впечатление что web-сайт упал, хотя при этом десять других машин будут прекрасно работать и простаивать.

Всякую машину нужно остановить на профилактику, но для этого потребуется внести изменения в таблицу DNS, а изменения в таблице DNS распространяются крайне медленно. Обновление во всей сети может произойти лишь через несколько дней. А это значит, что до этих пор вы не можете выключить машину, не повлияв на работу web-сайта.

Кроме того, при такой схеме у вас возникнут проблемы:

- с Java-апплетами, так как Java-апплеты в принципе могут общаться только с той машиной, с которой они были загружены.
- с SSL-соединениями
- с поддержкой сессий

Список можно продолжить.

Администрирование

С точки зрения администратора же эта схема идеальна. Для ее работы не требуется дополнительное оборудование и переустройство сети и серверов. На внесение изменений в таблицу DNS не требуется много времени и сил.

Схемы распределения нагрузки во многомашинной системе

Смешанные решения

Существуют также смешанные схемы, когда работают вместе аппаратные и программные распределители нагрузки. Рассмотрим следующую конфигурацию:

В системе используется один аппаратный распределитель нагрузки (и еще один запасной) и два кластера серверов, в которых используются программные распределители нагрузки. Аппаратный распределитель понятия не имеет о том, что за двумя IP-адресами скрывается целый отряд машин. Точно также, каждый из кластеров понятия не имеет о существовании своего соседа.

Балансировка

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

Отказоустойчивость

Благодаря такой схеме мы можем строить связки серверов, полностью изолированные друг от друга не только через сеть, но и географически. Таким образом вы получаете дополнительное средство защиты от различных прихотей природы (наводнений, пожаров и проч.) Если безопасность какого-либо из серверов будет нарушена, вы всегда его сможете отключить от сети, не повлияв на работу web-сайта.

Администрирование

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

Пару слов о "привязке"

Несмотря на то, что HTTP это stateless протокол, уже изобретено множество хитростей и уловок, что бы сохранять состояние приложения между запросами одного и того же клиента. Например с помощью сессий можно сохранить все переменные и их значения для данного клиента и потом восстановить их при следующем запросе. При использовании одной машины под web-сервер никаких проблем нет, разве что при пиковой нагрузке она может упасть, о чем мы уже рассуждали выше.

А вот при использовании простых переключателей нагрузки возникает проблема. Соединения равномерно распределяются между машинами, значит, что соединение определенного клиента с определенным сервером просто не гарантируется. Для статических web-серверов этот тип соединений вполне удовлетворителен. К сожалению, эта простая схема не срабатывает при использовании в е-коммерции SSL и апплетов. Для всех систем е-коммерции и информационных приложений требуется постоянное соединение между клиентом и определенной машиной пока не будет завершена определенная операция.

Для устранения этого недостатка была придумана технология, которая называется "привязка" (affinity). Она отсутствует в переключателях нагрузки (load director), но есть в распределителях (load balancer) как в аппаратных, так и в программных. "Привязка" означает, что по началу сессии клиент направляется на любую машину, и на протяжении всей сессии поддерживает соединение только с ней.

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

Рассмотрим следующий пример. Предположим, что четыре пользователя (A-D) подключатся к Web-сайту, и их запросы равномерно раскладываются между двумя машинами. Теперь предположим, что пользователи C и D тут же отключились, а пользователи A и B продолжают работать в течение длительного времени и выполняют сложные операции. Если мы будем использовать "привязку", все HTTP-запросы сделанные пользователями A и B, будут направляться на сервер А. для пользователей A и B сервер будет работать медленно, в то время как сервер B будет простаивать в ожидании работы.

Другая проблема, возникающая при привязке - это отказоустойчивость. Если вы привязываете пользователя к определенной машине, то теряет смысл наличие дополнительных машин. Представьте тот же самый случай. Если сервер А "упадет", все операции и данные пользователей A и B будут потеряны.

Большинство аппаратных и программных распределителей нагрузки предлагают решение этой проблемы. Они позволяют делать привязку для всего пространства адресов класса С, или 256 различных IP-адресов. Предполагается что большинство клиентов работают через прокси-сервера, у которых адреса располагаются в одном и том же адресном пространстве. Но и здесь есть недостаток: если к вам на web-сайт пожалует группа пользователей из одного сегмента сети, они все будут направлены (из-за привязки к пространству адресов) на одну машину, которая может из-за высокой нагрузки рухнуть.