Показаны сообщения с ярлыком www. Показать все сообщения
Показаны сообщения с ярлыком www. Показать все сообщения

суббота, 20 апреля 2013 г.

Балансировка нагрузки с LVS

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



DNS-RR


Первым делом напрашивается вариант с использованием Round-robin DNS. Если кто не знает, это метод позволяющий размазать запросы между n-ым количеством серверов просто отдавая на каждый DNS запрос новый IP.

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


Хотя и не стоит добавлять между вводом и выводом «слишком много компьютера», хочется каких-либо методов контроля над ситуацией.

LVS


И тут на помощь к нам приходит Linux Virtual Server или LVS. Фактически, это модуль ядра (ipvs), существующий еще где-то с версии 2.0-2.2.

Что же он из себя представляет? Фактически это L4-роутер (я бы сказал что L3, но авторы настаивают на L4), позволяющий прозрачно и управляемо разруливать пакеты по заданным маршрутам.



Основная терминология следующая:
  • Director — собственно узел осуществляющий роутинг.
  • Realserver — рабочая лошадка, узел нашей фермы серверов.
  • VIP или Virtual IP — всего лишь IP нашего виртуального (собранного из кучи реальных) сервера.
  • Соответственно DIP и RIP — IP директора и реальных серверов.


На директоре включается этот самый модуль IPVS (IP Virtual Server), настраиваются правила проброса пакетов и поднимается VIP — обычно как алиас к внешнему интерфейсу. Пользователи будут ходить через VIP.

Пакеты, пришедшие на VIP пробрасываются выбранным методом до одного из Realserver'ов и там уже нормально отрабатываются. Клиенту кажется что он работает с одной машиной.

Правила


Правила проброса пакетов крайне просты: задаем виртуальный сервис, определяемый парой VIP:port. Сервис может быть TCP или UDP. Здесь же задаем метод ротации узлов (планировщик, scheduler). Далее задаем набор серверов из нашей фермы, также парой RIP:port, а также указываем метод проброса пакетов и вес, если того требует выбранный планировщик.

Выглядит это примерно следующим образом.

# ipvsadm -A -t 192.168.100.100:80 -s wlc
# ipvsadm -a -t 192.168.100.100:80 -r 192.168.100.2:80 -w 3
# ipvsadm -a -t 192.168.100.100:80 -r 192.168.100.3:80 -w 2
# ipvsadm -a -t 192.168.100.100:80 -r 127.0.0.1:80 -w 1


Да, не забудьте поставить пакет ipvsadmin, он должен быть в репозитории вашего дистрибутива. Во всяком случае в Debian и RedHat он есть.

В примере выше мы создаем виртуальный HTTP сервис 192.168.100.100 и включаем в него сервера 127.0.0.1, 192.168.100.2 и 192.168.100.3. Ключ "-w" задает вес сервера. Чем он выше, тем с бОльшей вероятностью он получит запрос. Если выставить вес в 0, то сервер будет исключен из всех операций. Очень удобно, если нужно вывести сервер из эксплуатации.

Пакеты по умолчанию пробрасываются методом DR. Вообще существуют следующие варианты роутинга:
  • Direct Routing (gatewaying) — пакет направляется напрямую на ферму, без изменений.
  • NAT (masquarading) — просто хитрый механизм NAT.
  • IPIP incapsulation (tunneling) — туннелирование.


DR является наиболее простым, но если вам, например, нужно поменять порт назначения, то придется рисовать правила в iptables. NAT же требует, чтобы маршрут по умолчанию у всей фермы был направлен на директора, что не всегда удобно, особенно если реальные сервера имеют и внешние адреса.

Планировщиков в комплекте поставки несколько, подробно можно почитать в инструкции. Рассмотрим лишь основные.
  • Round Robin — знакомая всем круговая порука.
  • Weighted Round Robin — тоже самое, но с использованием весов сервера.
  • Least Connection — отправляем пакет серверу с наименьшим количеством соединений.
  • Weighted Least Connection — тоже самое, но с учетом весов.


Ко всему прочему, можно сообщить, что сервис требует persistence, т.е. удерживание пользователя на одном из серверов в течении заданного промежутка времени — все новые запросы с одного и того же IP будут прокинуты на тот же сервер.

Подводные камни


Итак, согласно примеру выше, мы должны были получить виртуальный сервер на VIP 192.168.100.100, о чем нам ipvsadm и радостно сообщает:

ipvsadm -L -n
IP Virtual Server version 1.0.7 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.100.100:80 wlc
-> 192.168.100.2:80 Route 3 0 0
-> 192.168.100.3:80 Route 2 0 0
-> 127.0.0.1:80 Local 1 0 0


Однако, при попытке соединения ничего не произойдет! В чем же дело? Первым делом необходимо поднять алиас.
# ifconfig eth0:0 inet 192.168.100.100 netmask 255.255.255.255

Но и тут нас ждет неудача — пакет приходит на интерфейс реального сервера немодифицированным и следовательно тупо отпинывается ядром как не предназначающийся машине. Простейшим методом разрешения этого вопроса является поднятие VIP на loopback.

# ifconfig lo:0 inet 192.168.100.100 netmask 255.255.255.255

Ни в коем случае не поднимайте его на интерфейсе, который глядит в ту же подсеть, что и внешний интерфейс директора. В противном случае внешний роутер может закэшировать mac не той машины и весь трафик пойдет не туда.

Теперь пакетики должны побежать куда надо. Кстати, директор сам может быть реальным сервером, что мы и видим в нашем примере.

Единая точка отказа


В этом решении очевидной точкой отказа, вызывающей разрушение всего сервиса, будет сам директор.

Что ж, не беда, ipvsadm поддерживает запуск в режиме демона с возможностью синхронизации таблиц и текущих соединений между несколькими директорами. Один, очевидно, станет мастером, остальные будут слейвами.

Что остается нам? Переезжать VIP между директорами в случае отказа. Тут нам помогут HA решения вроде heartbeat.

Другой задачей будет мониторинг и своевременный вывод из эксплуатации серверов из нашей фермы. Проще всего это делать весами.

Для разруливания обоих вопросов написано множество решений, заточенных под разные типы сервисов. Мне лично больше всего понравилось решение Ultramonkey, от самих же авторов LVS.

У RedHat есть родная штука под названием Piranha, она имеет свой набор демонов для мониторинга фермы и директоров и даже некий топорненький веб-интерфейс, однако она не поддерживает более чем 2 директора в HA связке. Уж не знаю почему.

Ultramonkey


Итак, Ultramonkey состоит из 2-х основных пакетов — heartbeat и ldirectord. Первый занимается обеспечением HA для директоров, в том числе поднятие и переезд VIP (и вообще говоря может использоваться не только для директоров), а второй поддерживает конфиг ipvsadm и мониторит состояние фермы.

Для heartbeat необходимо нарисовать 3 конфига. Базовые версии снабжены подробными комментариями, поэтому просто приведу примеры.

authkeys
auth 2
#1 crc
2 sha1 mysecretpass
#3 md5 Hello!

Настраиваем авторизацию демонов на разных машинах.

haresources
Здесь у нас информация о том, для какого ресурса мы создаем HA и какие сервисы дергаем при переезде.
director1.foo.com IPaddr::192.168.100.100/24/eth0 ldirectord

Т.е. поднять на интерфейсе eth0 192.168.100.100/24 и запустить ldirectord.

ha.cf
keepalive 1
deadtime 20
udpport 694
udp eth0
node director1.foo.com # <-- должно совпадать с uname -n !
node director2.foo.com #

Говорим каким образом поддерживать HA кластер и кто собственно в него входит.

У ldirectord всего один конфиг и там в общем-то тоже все понятно.
checktimeout=10
checkinterval=2
autoreload=yes
logfile="/var/log/ldirectord.log"
# Virtual Service for HTTP
virtual=192.168.100.100:80
real=192.168.100.2:80 gate
real=192.168.100.3:80 gate
service=http
request="alive.html"
receive="I'm alive!"
scheduler=wlc
protocol=tcp
checktype=negotiate


Т.е. ldirectord будет каждые 2 секунды дергать через http файл alive.html и если в нем не будет строчки «I'm alive!» или, хуже того, сервер не ответит, демон тут же поставит ему вес 0 и он будет исключен из последующих пересылок.

Веса также можно расставлять самому, например пробегаясь кроном по полю и вычисляя их в зависимости от текущего loadavg и т.п. — прямой доступ к ipvsadm у вас никто не отнимает.

Применимость


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

Кстати, в качестве реальных серверов не обязательно должен выступать Linux. Это можеть быть практически любая ОС со стеком TCP/IP.

Что еще почитать?


Построение высоко доступного web кластера с балансировкой нагрузки на базе linux

1. Описание проблемы

"Мой сайт просто обязан быть доступен 24 часа в сутки, 7 дней в неделю. Система, обеспечивающая доступ к нему, должна позволять легко нарастить мощность без потери доступности." Решение - HA/LB Cluster.

Вот некоторые понятия о которых мы будем говорить в этой статье:
Cluster
некоторое количество однотипных объектов соединенных вместе, применительно к компьютерам - несколько компьютеров предоставляющих однотипные ресурсы
HA (High Availability)
система, которая при сбое одного из компонентов продолжает нормальную работу
LB (Load Balanced)
предоставляет сервис из множества точек с одинаковыми ресурсами
Значит нас интересует набор программных продуктов который позволит построить высоко доступный web сервис на кластерной основе. Но:
а) мы хотим иметь действительно балансировку нагрузки, а не просто Round Robin.
б) система должна правильно вычислять "старых" пользователей и отправлять их на "старый" сервер, если он доступен. Например мы хостим книжный интернет магазин. Приобретая книгу мы кладем ее в корзину. Сервер запомнил что находится у нас в корзине. При следующем запросе оказывается что другой сервер в этот момент времени менее загружен и LB отправляет запрос на него. Этого никак нельзя допустить. Второй сервер ничего не знает о нашей корзине.
в) web сервер должен быть доступен при крахе любой отдельной части кластера.
г) наконец, мы люди любящие халяву, а значит коммерческое решение нас не устраивает.

После всех поставленных условий выбор оказывается не велик. Я остановился на mod_backhand в качестве балансировщика нагрузки и Wackamol в качестве основы для построения отказоустойчивой системы.

2. Mod_backhand

Mod_backhand это модуль для web сервера apache 1.3.X. Он собирает информацию о загруженности каждой системы в кластере. Когда приходит запрос, mod_backhand сначала определяет какие действия он должен произвести с ним (если этот запрос попадает в так называемую зону действия). Зоны действия mod_backhand определяются директивами <Files>, <Directory> и <Location> в httpd.conf и .htaccess файлах. Если запрос входит в зону действия mod_backhand он скармливается каждой определенной для зоны функции выбора кандидата. Функция выбора кандидата может сортировать и полностью изменять список серверов-кандидатов на выполнение запроса, а так же менять способ доставки выбранному серверу запроса(HTTP Redirect или Proxy). После выполнения последней функции выбора кандидата, первый сервер в списке кандидатов получает запрос. По умолчанию он получает его методом proxy - т.е. сервер к которому пришел запрос сам просит выполнить его сервер который оказался наиболее удачным кандидатом, а потом отдает результат его выполнения клиенту. Возможен и другой метод - HTTP Redirect. Он использует стандартные средства протокола http для того чтобы сказать клиенту что ресурс нужно запросить у другого сервера.

2.1 Установка

Установить mod_backhand проще простого. Я предпочитаю делать это во время сборки apache:

# cd /var/tmp
# ls
apache_1.3.28.tar.gz
mod_backhand-1.2.2.tar.gz
# gzip -d < apache_1.3.28.tar.gz | tar xf -
# gzip -d < mod_backhand=1.2.2.tar.gz | tar xf -
# ls
apache_1.3.28
apache_1.3.28.tar.gz
mod_backhand-1.2.2
mod_backhand-1.2.2.tar.gz
# cd mod_backhand-1.2.2
# ./precompile ../apache_1.3.28/
Copying source into apache tree...
Copying sample cgi script and logo into htdocs directory...
Adding to auto mod_so inclusion to configure...
Adding libs to Apache's Configure...
Adding to Apache's Configuration.tmpl...
Nullifying extra shared libraries for Linux
Modifying httpd.conf-dist...
Updating Makefile.tmpl...

Now change to the apache source directory:
../apache_1.3.28
And do a ./configure...

Затем конфигурируем Apache с поддержкой mod_backhand, компилируем и устанавливаем. Например так:
$ cd /var/tmp/apache_1.3.28
$ ./configure --prefix=/usr/local/apache --enable-module=so \
--enable-module=rewrite --enable-shared=rewrite \
--enable-module=speling --enable-shared=speling \
--enable-module=info --enable-shared=info \
--enable-module=include --enable-shared=include \
--enable-module=status --enable-shared=status \
--enable-module=backhand --enable-shared=backhand
$ make
# make install

2.2 Информация о ресурсах

Страница на которой будет находится статистика собранная mod_backhand с других узлов кластера поределяется директивой apache SetHandler backhand-handler. Если вы устанавливали mod_backhand вкомпилированным в apache (методом описанным в этой статье), то в httpd.conf уже есть директива:
<Location "/backhand/">
    SetHandler backhand-handler
</Location>
Значит статистика будет доступна по адрессу http://имя_узла/backhand/.

mod_backhand stats

2.3 Функция выбора кандидата.

Функция выбора кандидата определяет какие серверы являются кандидатами на выполнение запроса и сортирует их в соответствии с правилами описанными в настройке mod_backhand.
Например, в файле конфигурации apache мы можем указать что все файлы заканчивающиеся на .php будут обрабатываться наиболее доступными и наименее загруженным сервером:
<Files ~ "\.php$">
    Backhand byAge
    Backhand byLoad
</Files>
Когда кто нибудь попросит apache страницу заканчивающуюся на .php, сначала функция выбора кандидата byAge отсеет все сервера которые не отвечали в течении поледних 5 секунд, затем функция byLoad отсортирует этот список от менее загруженных к более загруженным. Так как больше не определенно функций выбора кандидата, обрабатывать запрос будет доверено первому серверу из списка т.е. наименее загруженному.

Встроенные функции выбора кандидата:
off отключает использование mod_backhand для текущей "зоны покрытия"
addSelf добавляет локальный сервер в конец списка
byAge [время в секундах] выбрасывает из списка серверы, с которых мы не слышали привета в течении установленного времени. По умолчанию - 20 сек
byLoad [преимущество] сортирует список серверов от менее загруженных к более загруженным. Преимущество - величина которая позволяет завысить оценки для локального сервера. Она будет добавлена ко всем серверам кроме локального
byBusyChildren [преимущество] сортирует список кандидатов в соответствии количеством дочерних процессов Apache в состоянии SERVER_BUSY от меньшего к большему
byCPU удаляет все сервера кроме этого в соответствии с временем простоя CPU. Не используйте если вы действительно незнаете почему используете это
byLogWindow выбрасывает все сервера кроме первых log по основанию 2 от n. Если в списке 17 серверов, останется первых 4
byRandom случайно перемешивает список серверов
byCost эта функция пытается определить стоимость выполнения запроса для каждого сервера в кластере и выбирает наиболее дешевый. Метод определения стоимости обсуждается в документе "A cost-Benefit Framework for Online Managment of a Metacomputing System"
HTTPRedirectToIP заставляет mod_backhand использовать пере направление HTTP, вместо стандартного режима Proxy
bySession [идентификатор] эта функция будет пытаться найти печеньку(cookie) или переменную запроса именуемую идентификатором, декодировать первые 8 байт и получить IP адрес. Попробует найти IP адрес в списке серверов и если найдет то оставит в списке только его. Если что-то не получится список останется нетронутым. Эта функция очень полезна для скриптов исполняемых на стороне сервера и может быть использована для нормальной работы приложений использующих пользовательские сессии. По умолчанию идентификатор равен "PHPSESSID="

Можно и самому написать функцию работы с кандидатами, но здесь это обсуждать мы не будем.

2.4 Настройка mod_backhand

Все параметры настройки mod_backhand находятся в файле настроек apache httpd.conf. Их совсем немного, посему давайте остановимся на них подробней.
UnixSocketDir <dir> - директория в которой mod_backhand будет сохранять необходимую для работы информацию. Она должна быть доступна на запись для apache (nobody).
MulticastStats <IP-Addr>:<Port>[,<TTL>] - задает адрес на который сервер отправляет свое состояние. Может быть широковещательным, может уникальным. Разрешается использование нескольких адресов и/или сетей путем использования нескольких директив.
AcceptStats <IP-Addr>/<Netmask> - задает сеть из которой мы будем принимать информацию от других серверов.

2.5 Пример конфигурации

Давайте рассмотрим пример в котором у нас будет 5 серверов.
Один из них будет управляющим. Он не будет сам выполнять работу, а будет отдавать ее другим. Он будет иметь два интерфейса: eth0 - во внешний мир и eth1(ip - 195.5.3.183) - в сеть с кластером(ip - 192.168.10.1).
На остальные четыре сервера ложится основная нагрузка по обработке запросов. Они имеют ip адреса от 192.168.10.2 до 192.168.10.5.
Управляющий сервер будем называть Director, остальные www1 - www4.

cluster's schem

Все системы имеют одинаковые настройки mod_backhand.

<IfModule mod_backhand.c>
  UnixSocketDir /usr/local/apache/backhand
  MulticastStats 192.168.10.255:4445,1
  AcceptStats 192.168.10.0/24
                                                                              
  <Location "/backhand/">
    SetHandler backhand-handler
  </Location>
</IfModule>

Director помимо всего прочего имеет зону покрытия:
<Files ~ "*">
    backhand bySession
    backhand byAge
    backhand removeSelf
    backhand byLoad
</Files>

Все. Наш кластер с балансировкой нагрузки можно использовать.
Конечно если упадет Director то и весь наш кластер будет не доступен. Самое время рассмотреть Wackamole.

3. Wackamole

Wackamole позволяет сделать наш кластер высоко доступным.
Делается это за счет того что wackamole распределяет имеющийся пул виртуальных адресов между несколькими машинами. Таким образом если одна из машин "умрет" остальные тут же подхватят ее виртуальный IP, что позволяет быть каждому отдельному виртуальному IP быть доступным в любое время. Виртуальным IP называются потому что ни одна из машин не "владеют" этим адресом. Он может передоватся от одной к другой. В любой момент времени IP владеет не больше одной машины.

Это позволяет нам использовать множественные DNS RR записи, не беспокоясь о том что серверы могут быть недоступны. Если одна из машин "упадет" виртуальные IP адреса, которыми она владела, распределятся между другими машинами кластера.

3.1 Установка

Wackamole работает используя Spread toolkit. Взять его можно на http://www.pread.org/.
Собираем сначала Spread:

$ cd spread-src-3.17.1
$ ./configure --prefix=/usr/local/spread
$ make
# make install
Следует помнить, что для старта демона spread необходимо наличие пользователя и группы spread т.к. после старта он делает setuid, а также каталог /var/run/spread для chroot в целях безопасности.

А теперь wackamole:

$ cd ../wackamole-2.0.0
$ ./configure --prefix=/usr/local/wackamole --with-cppflags=-I/usr/local/spread/include \
  --with-ldflags=-L/usr/local/spread/lib
$ make all
# make install

Не забудьте, что вы должны обеспечить вызов динамических библиотек из /usr/local/spread/lib.

3.2 Настройка wackamole.conf

Spread - указывает где искать Spread демон. Значение 4803 означает что он будет искаться на локальной машине, на порту по умолчанию для spread.
SpreadRetryInterval - временной промежуток через который wackamole будет пытаться установить связь с Spread если она разорвалась.
Group - указывает Spread группу к которой wackamole присоединится. Эта группа должна быть своя для каждого кластера.
Control - указывает путь к Unix Domain сокету, используемый wackamole.
Arp-cache - указывает время через которое происходит обновление информации в ARP кэше.

Секция balance:
Interval - указывает длину раунда балансировки.
AcquisitionsPerRound - указывает количество виртуальных интерфейсов задействованных в раунде балансировки.

Секция VirtualInterfaces определяет все виртуальные интерфейсы, относящиеся к кластеру. Виртуальный интерфейс может иметь три вида:
1. ifname:ipaddr/mask
2. { ifname:ipaddr/mask }
3. {
    ifname:ipaddr/mask
    ifname:ipaddr/mask
    ...
   }
ifname - имя интерфейса из ifconfig -a, без каких либо виртуальных номеров.

Директива Prefer позволяет указать ip адреса предпочитаемые для этой машины.

Секция Notify описывает каким машинам должны посылаться arp-spoof'ы когда IP адрес передается машине. IP адреса в секции задаются подобно секции VirtualInterfaces.

3.2 Пример настройки

У нас есть четыре Linux сервера с запущенным Apache, содержащим картинки для большого web сайта. У них ip от 192.168.100.183 до 192.168.100.186. Для них выделены 4 виртуальных IP, по которым и будет происходить доступ к картинкам - 192.168.100.200 - 192.168.100.203. Все они должны откликаться на images.example.com. Spread установлен на всех машинах и висит на порту 4803. Каждая машина имеет по одному интерфейсу - eth0. Default route для всех - 192.168.100.1
Wackamole.conf на каждой машине должен выглядеть следующим образом:
Spread = 4803
SpreadRetryInterval = 5s
Group = wack1
Control = /var/run/wack.it

Mature = 5s
Balance {
    AcquisitionsPerRound = all
    Interval = 4s
}
Arp-Cache = 90s
Prefer none
VirtualInterfaces {
    { eth0:192.168.100.200/24 }
    { eth0:192.168.100.201/24 }
    { eth0:192.168.100.202/24 }
    { eth0:192.168.100.203/24 }
}

Notify {
    eth0:192.168.100.1/32
    arp-cache
}

4. А теперь все вместе

В заключение рассмотрим пример который объединяет все выше сказанное.
В нашем кластере будет участвовать 7 машин. Две из них будут:
1) распределять пул из четырех виртуальных IP (195.5.3.180 - 195.5.3.183) откликающихся на www.samplesite.com.
2) балансировать нагрузку между остальными пятью машинами, сами не выполняя запросов.
Остальные пять машин будут заниматься непосредственно предоставлением web ресурсов.

web cluster example scheme

На первых двух машинах установлен и wackamole и apache+mod_backhand, шлюз по умалчанию 192.168.100.1, постоянные IP(привязанные к интерфейсу) - 192.168.100.101, 192.168.100.102. Файлы настроек для них выглядят следующим образом:
wackamole.conf:
Spread = 4803
SpreadRetryInterval = 5s
Group = wack1
Control = /var/run/wack.it

Mature = 5s
Balance {
    AcquisitionsPerRound = all
    Interval = 4s
}
Arp-Cache = 90s
Prefer none
VirtualInterfaces {
    { eth0:195.5.3.180/24 }
    { eth0:195.5.3.181/24 }
    { eth0:195.5.3.182/24 }
    { eth0:195.5.3.183/24 }
}

Notify {
    eth0:192.168.100.1/32
    arp-cache
}

mod_backhand (httpd.conf):

<IfModule mod_backhand.c>
  UnixSocketDir /usr/local/apache/backhand
  MulticastStats 192.168.100.255:4445,1
  AcceptStats 192.168.100.0/24

  <Location "/backhand/">
    SetHandler backhand-handler
  </Location>
</IfModule>

<Files ~ "*">
    backhand bySession
    backhand byAge
    backhand removeSelf
    backhand byLoad
</Files>

Остальные пять машин умеют ip 192.168.100.50 - 192.168.100.55. На них установлен только apache+mod_backhand cо следующими настройками:

mod_backhand (httpd.conf):

<IfModule mod_backhand.c>
  UnixSocketDir /usr/local/apache/backhand
  MulticastStats 192.168.100.255:4445,1
  AcceptStats 192.168.100.0/24

  <Location "/backhand/">
    SetHandler backhand-handler
  </Location>
</IfModule>

Естественно все 5 машин должны предоставлять схожие web-ресурсы.

Все. Вам осталось, для проверки, только пощелкать кнопками выключения питания у некоторых компьютеров и посмотреть на результаты web-benchmark'а.

Балансировка нагрузки на веб-сайт

DNS

Самый простой способ балансирования нагрузки и распределения запросов между веб-серверами - использование механизма round robin DNS.
Спецификация стандарта DNS позволяет указать несколько разных IN A записей для одного имени. Например:
www  IN A  10.0.0.1 
www  IN A  10.0.0.2
В этом случае DNS-сервер в ответ на запрос разрешения имени в IP-адрес будет выдавать не один адрес, а весь список:
# host www.domain.local 
www.domain.local has address 10.0.0.1 
www.domain.local has address 10.0.0.2
При этом с каждым новым запросом последовательность адресов в списке в ответе будет меняться. Таким образом клиентские запросы будут распределяться между разными адресами и будут попадать на разные серверы.
Использование round robin DNS - самый простой способ балансировки нагрузки, не требующий никаких дополнительных средств, однако он обладает целым рядом недостатков, поэтому мы рекомендуем использовать его только в том случае, если нет возможности применить какой-либо иной балансировщик.
Минусы применения round robin DNS:
  • нет четкого критерия выбора IP из списка клиентом (может выбираться первый элемент, может кэшироваться последнее выбранное значение, возможны иные варианты): все зависит от реализации конкретного клиента;
  • нет механизмов определения доступности узлов и возможности задания их "весов": в случае аварии на одном или нескольких узлах кластера нагрузка будет продолжать распределяться между рабочими и вышедшими из строя нодами;
  • длительное время кэширования ответов DNS: в случае аварии и изменении тех или иных записей в DNS потребуется некоторое время (зависит от настроек DNS) для обновления данных на всех клиентах.

nginx

Рассмотрим пример использования в качестве балансировщика http-сервера nginx. Для этих целей используется модуль ngx_http_upstream.
При использовании "1С-Битрикс: Веб-окружения" nginx уже установлен на серверах веб-кластера. И для распределения нагрузки можно использовать непосредственно один из серверов кластера. Однако для более простого, гибкого и удобного конфигурирования лучше использовать отдельный сервер с установленным nginx в качестве балансировщика.
В простейшем примере фрагмент конфигурационного файла nginx (/etc/nginx/nginx.conf), обеспечивающего распределение нагрузки между серверами, будет выглядеть так (помимо стандартных директив, определяющих, например, пути и формат log-файлов и т.п.):
http { 
    upstream backend { 
        server node1.demo-cluster.ru; 
        server node2.demo-cluster.ru; 
    } 

    server { 
        listen   80; 
        server_name  load_balancer; 

        location / { 
            proxy_set_header X-Real-IP $remote_addr; 
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
            proxy_set_header Host $host:80; 

            proxy_pass  http://backend; 
        } 

    } 
}
В секции upstream задаются адреса серверов, между которыми будет распределяться нагрузка.
В DNS имя сайта указывается на тот IP, на котором работает сервер с nginx, распределяющем нагрузку.
Если не указаны какие-либо дополнительные параметры, запросы распределяются между серверами по принципу round robin.
Однако с помощью модуля ngx_http_upstream можно реализовать и более сложные конфигурации.
  • В некоторых случаях бывает удобно передавать все запросы от одного клиента на один и тот же сервер, а между серверами распределять только запросы разных клиентов. Для реализации подобного функционала служит директива ip_hash. Пример:
    upstream backend 
    { 
        ip_hash; 
    
        server node1.demo-cluster.ru; 
        server node2.demo-cluster.ru; 
    }
    
    В этом случае распределение запросов основано на IP-адресах клиентов.
  • Если для узлов кластера используются серверы разной конфигурации (разной мощности), бывает полезно задать "вес" для тех или иных хостов, направляя на них больше или меньше запросов. Для этого служит параметр weight директивы server. Пример:
    upstream backend 
    { 
        server node1.demo-cluster.ru weight=3; 
        server node2.demo-cluster.ru; 
        server node3.demo-cluster.ru; 
    }
    
    В такой конфигурации каждые 5 запросов будут распределяться следующим образом:
    • 3 - на node1.demo-cluster.ru;
    • 1 - на node2.demo-cluster.ru;
    • 1 - на node3.demo-cluster.ru.
    Обратите внимание: для серверов, использующих метод распределения ip_hash, нельзя задать вес.
  • Можно настроить параметры, по которым будут определяться неработающие серверы. max_fails = число - задает число неудачных запросов к серверу в течение времени, заданного параметром fail_timeout, после которых он считается неработающим также в течение времени заданного параметром fail_timeout;
    fail_timeout = время Пример:
    upstream backend 
    { 
        server node1.demo-cluster.ru max_fails=3 fail_timeout=30s; 
        server node2.demo-cluster.ru max_fails=3 fail_timeout=30s; 
    }
    
    Если при запросе к серверу произошла ошибка, запрос будет передан на следующий сервер. Если произошло 3 ошибки в течение 30 секунд, то на 30 секунд сервер будет помечен неработающим, и в течение этого времени новые запросы не будут на него отправляться.