Руководство по URL преобразованиям
Управление содержанием
Балансировка нагрузки
Описание:
Предположим что мы хотим сделать балансировку нагрузки для траффика www.foo.com на www[0-5].foo.com (всего 6 серверов). Как это возможно сделать?
Решение:
Есть масса возможных решений этой проблемы. Мы обсудим сначала общеизвестный основанный на DNS вариант и специфический с помощью mod_rewrite:
Циклический DNS
Самый простой способ для балансировки нагрузки это использование функции циклического DNS в DNS сервере BIND. Просто сконфигурируйте www[0-9].foo.com как обычно в своем DNS сервере с использованием записей типа A(address) т.е.
www0 IN A 1.2.3.1
www1 IN A 1.2.3.2
www2 IN A 1.2.3.3
www3 IN A 1.2.3.4
www4 IN A 1.2.3.5
www5 IN A 1.2.3.6
Затем, дополнительно добавьте следующую запись:
www IN CNAME www0.foo.com.
IN CNAME www1.foo.com.
IN CNAME www2.foo.com.
IN CNAME www3.foo.com.
IN CNAME www4.foo.com.
IN CNAME www5.foo.com.
IN CNAME www6.foo.com.
Заметьте что это кажется неправильным, однако в действительности это характерная особенность BIND и может быть использована таким способом. Однако, теперь, когда происходит разрешение www.foo.com, BIND выдает www0-www6 — однако слегка меняя/перемещая каждый раз порядок. Таким образом клиенты распределяются по разным серверам. Однако заметьте что это не блестящая схема балансировки нагрузки, потому что информация о разрешении имен DNS кэшируется другими серверами имен в сети, поэтому при первом разрешении имени www.foo.com клиентом на конкретный wwwN.foo.com, все последующие запросы также пойдут на это конкретное доменное имя wwwN.foo.com. Однако конечный результат хороший, потому что общая сумма запросов действительно распределяется на разные веб-серверы.
Балансировка нагрузки с помощью DNS
Научный метод балансировки нагрузки основанный на DNS это использование программы lbnamed которая может быть найдена по http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html. Эта программа на Perl 5 в связке с вспомогательными средствами, представляет настоящую балансировку нагрузки с использованием DNS.
Циклический Proxy
В этом варианте мы используем mod_rewrite и его proxy функцию. Сначала мы сопоставим www0.foo.com реальному www.foo.com при помощи простой
www IN CNAME www0.foo.com.
записи в DNS. Затем мы направляем www0.foo.com только на proxy сервер, т.е. мы настраиваем эту машину так чтобы все входные URL просто пропускались через внутренний proxy на один из 5-ти других серверов (www1-www5). Для этого мы сначала введем набор директив которые взаимодействуют со скриптом lb.pl балансировки нагрузки для всех URL.
RewriteEngine on
RewriteMap lb prg:/path/to/lb.pl
RewriteRule ^/(.+)$ ${lb:$1} [P,L]
Затем мы пишем lb.pl:
#!/path/to/perl
##
## lb.pl -- скрипт балансировки нагрузки
##
$| = 1;
$name = "www"; # база для имени хоста
$first = 1; # первый сервер (здесь не 0, потому что 0 это и есть этот сервер)
$last = 5; # последний сервер в цикле
$domain = "foo.dom"; # доменное имя
$cnt = 0;
while (<STDIN>) {
$cnt = (($cnt+1) % ($last+1-$first));
$server = sprintf("%s%d.%s", $name, $cnt+$first, $domain);
print "http://$server/$_";
}
##EOF##
Последнее замечание: Почему это полезно? Кажется что www0.foo.com все-ещё перегружен? Ответ положительный, — он перегружен, однако только простыми proxy запросами! Все SSI, CGI, ePerl, и т.д. запросы, полностью выполняются другими машинами. Это основная идея.
Аппаратный/TCP Round-Robin
Для этой задачи есть также доступные аппратные решения. Cisco имеет устройство называемое LocalDirector которое производит балансировку нагрузки на уровне TCP/IP. В действительности это некоторый вид циклического шлюза стоящего перед веб-кластером. Если у вас есть достаточно денег и вас действительно нужно высокопроизводительное решение, используйте этот вариант.