Балансировка нагрузки на web с помощью Nginx на Debian\Ubuntu

Jun 04, 2012 23:01


Данное руководство не имеет привязки к версии ОС и актуально для всех версий Debian и Ubuntu, а также легко адаптируется под другие дистрибутивы Linux. У нас будет использоваться 3 web сервера и 1 сервер, в качестве балансировщика нагрузки. SQL сервер мы использовать не будем. Вообще можно установить целую кучу различных серверов реляционных баз данных (MySQL, MSSQL, PostgreSQL, ORACLE и многие другие. Да и на худой конец Sybase - будь он не ладен) или NoSQL системы. У нас есть небольшая сеть из 4х серверов, 3 из них работают как WEB сервера и находятся внутри локальной сети, в интернет торчит только 1 сервер, на нем работает Nginx. Nginx виден в интернет и пользователи подключаются непосредственно к нему. Он же, в свою очередь, передает пользовательские запросы в локальную сеть, на основные WEB сервера, которые его обрабатывают и возвращают готовый результат, который отдается пользователям. Зачастую, никаких других операций на сервере, балансирующим сетевую нагрузку, не производится и для его работы достаточно самого простого и дешевого железа или VPS. Операционную систему можно раскатывать из заранее подготовленного образа. Тогда время простоя, при выходе балансировщика из строя, будет минимальным. Пользователи не будет знать-какое количество серверов скрывается за ним, а их могут быть десятки и сотни, но в сети виден всего один. Можно развернуть дополнительный балансировщик и запросы к нему распределять на основе службы DNS, как это реализовано, например, у mail.ru. Если в командной строке Windows набрать:



nslookup mail.ru

В ответ мы получим нечто подобное:

Addresses: 94.100.191.203
94.100.191.204
94.100.191.201
94.100.191.202

Из чего можно сделать вывод, что в интернет у них торчит только 4 сервера или маршрутизатора. Там конечно много нюансов, думаю что там используется GeoIP и многое другое. Для определения местоположения пользователя и предоставления ему ближайшего сервера, скорость соединения с которым, будет максимально быстрой. Если набрать повторно:

nslookup mail.ru

В ответ мы получим:

Addresses: 94.100.191.202
94.100.191.203
94.100.191.204
94.100.191.201

Как видно, первым в ответе будет уже другой IP, из тех 4х, что были присланы ранее. Сколько и чего находится за этими IP адресами, знают только в mail.ru. Кстати, на досуге пробуйте пройтись по крупным сетевым сервисам, можете узнать для себя что-то новое… Алгоритм распределения запросов называется Round-robin, в нашей схеме он также будет использован и является, по сути, основой всей системы. Где еще используются подобные схемы распределения нагрузки?! Например для создания непотопляемых torrent треккеров. Сами сервера могут тихо стоять в дата-центре, а наружу торчит только один в совершенно левой стране и все запросы идут через него, который в свою очередь передает их на основные для обработки. В случае отключения данного сервера по жалобе, то ему быстро находится замена в виде покупки самого дешевого VPS в другой стране и в течении 1-2 часов трекер снова доступен, ведь основные мощности никуда не переезжали (привет правообладателям). Можно конечно и данную схему поломать, но это отдельная песня и без административного ресурса будет довольно сложно. Думаю что смысл понятен. Сама работа системы, отдаленно напоминает технологию NLB от Microsoft (кто с ней работал, тот думаю поймет о чем я), которая не отслеживает нагрузку на каждой отдельной ноде, а просто раскидывает пользовательские подключения между серверами по заранее определенному алгоритму. Например 50/50, когда все пользовательские подключения равномерно распределяются между узлам серверной фермы. Правда у NLB есть ограничение в 32 сервера на одну серверную ферму. Система, построенная на Linux, данного ограничения лишена. Узким местом можно рассматривать сетевую подсистему на самом балансировщике. По сути мы будем с вами строить кластер распределения нагрузки. Для примера, буду использовать доменное имя example.org, для него мы и будем распределять нагрузку.На этом с теорией все, переходим к практике.

Настраиваем сервер балансировки нагрузки.

Предполагается что на сервере установлено 2 сетевых интерфейса, один будет смотреть в интернет, другой в локальную сеть. Нам понадобится собрать Nginx и установить его, поверх более старой версии. Сама сборка из исходников стандартна и не изменилась ни капли. Сначала нам необходимо установить необходимые компоненты для сборки+древнюю версию nginx из репозиториев:

apt-get install libpcre3-dev libcurl4-openssl-dev gcc nginx

Качаем свежие исходники стабильного релиза Nginx, на момент написания была доступна версия 1.0.10:

wget http://nginx.org/download/nginx-1.0.10.tar.gz
tar -zxvf nginx-1.0.10.tar.gz
cd nginx-1.0.10

Сборка и установка:

./configure \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--pid-path=/var/run/nginx.pid \
--user=www-data \
--group=www-data \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_gzip_static_module \
--with-mail --with-mail_ssl_module
make
make install

Запускаем собранное:

/etc/init.d/nginx start

Теперь нам необходимо создать виртуальный хост example.org, запросы которого мы и будем распределять.

nano /etc/nginx/site-avelible/example.org

Добавим в него следующее:

upstream backend {
server 192.168.10.11:8080;
server 192.168.10.12:8080;
server 192.168.10.13:8080;
}
server {
listen 80;
server_name example.org;
location ~* \.()$ {root /var/www/example.org;}
location / {
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 16 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_connect_timeout 30s;
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~* /.(jpg|jpeg|gif|png|css|mp3|avi|mpg|txt|js|jar|rar|zip|tar|wav|wmv)$ {root /var/www/example.org;}

Также необходимо добавить символическую ссылку в sites-enabled.

ln -s /etc/nginx/sites-available/example.org /etc/nginx/sites-enabled/

Если мы попробуем перезапустить nginx, то он отвалится с ошибкой, т.к. отсутствует директория по пути /var/www/example.org, создадим ее:

mkdir -p -m 754 /var/www/example.org

Предоставим права пользователю www-data

chown -R www-data: /var/www/example.org

На этом можно считать основную работу, по настройке балансировщика, завершенной. Переходим к настройке непосредственно WEB серверов

Настройка backend сервера

Собственно ее и настройкой трудно назвать, нам необходимо установить любой WEB сервер. Это может быть Apache, Nginx, Lighthttpd - не важно. Давайте рассмотрим для примера Ubuntu с уставленным из репозитория Nginx.

Настройка ноды №1

Ставим Nginx.

sudo apt-get install nginx

Для опытов, нам будет достаточно и стандартного виртуального хоста Nginx, для того чтобы увидеть работу системы распределения нагрузки и все что нам требуется это перевести этот сервер на другой порт, отличный от 80го, для этого слегка подправим дефолтный виртуальный хост:

sudo nano /etc/nginx/sites-available/default

В секции server { находим строку:

listen 80 default;

и меняем порт на тот, что мы указали в конфигурационном файле, виртуального хоста example.org на балансировщике, для забывчивых, напоминаю, это порт 8080. Его и вписываем, чтобы выглядело.

listen 8080 default;

Сохраняем изменения и перезапускаем Nginx:

sudo /etc/init.d/nginx

Да, и меняем IP этого сервера на 192.168.10.11. Данная конфигурация исключительно для примера. Далее, для того чтобы увидеть как происходит перенаправление запросов между серверами, нам необходимо отредактировать index.html, который лежит в корневой директории этого сервера:

sudo nano /var/www/nginx-default/index.html

Находим там строку:

Welcome to nginx!

Вписываем туда NODE 01 чтобы выглядело:

Welcome to nginx! (NODE 01)

Делается это для того, чтобы было видно, какой сервер прислал ответ в данный момент.

Настройка ноды №2 и №3

Настройка производится аналогичным образом как и у ноды №1 только IP адреса подставляем другие.
Для ноды №2 192.168.10.12
Для ноды №3 192.168.10.13
В файлы index.html на второй ноде вписываем NODE 02, а на третьей NODE 03 соответственно. Надеюсь что смысл понятен?! Если эти сервера будут ставиться на виртуальной машине, то можно настроить первую ноду кластера, потом её просто клонировать, заменив IP адреса на нужные и вписав номера серверов в index.htmд - это здорово сократит время создания тестовой инфраструктуры.Допустим, балансировщик мы настроили, backend сервера тоже. Необходимо все это протестировать. Поднимать DNS для поддержки зоны example.org - все равно что стрелять из пушки по воробьям, по этому просто добавим запись в файл hosts. Открываем броузер и переходим по адресу example.org. Если обновлять страницу и дальше, то станет понятно, что ответы от серверов идут по кругу. В общем, видно что распределение запросов происходит нормально. Что еще можно улучшить, в данной схеме? Например Nginx позволяет указывать вес серверов, по умолчанию, он у всех равен нулю. Делается это на балансировщике, добавляем в файл:

nano /etc/nginx/site-avelible/example.org

В секцию upstream backend

upstream backend {
server 192.168.10.11:8080 weight=1;
server 192.168.10.12:8080 weight=2;
server 192.168.10.13:8080 weight=3;
}

Чем больше вес сервера, тем больший приоритет он имеет и тем больше запросов поступает на него, все остальные будут перенаправляться по мере уменьшения веса, это можно использовать в той ситуации, когда необходимо четко определить порядок перенаправления запросов. Для того чтобы вывести из эксплуатации один сервер, например, для обслуживания, достачно в секцию upstream backend добавить down. Сделаем это на примере ноды №3

upstream backend {
server 192.168.10.11:8080;
server 192.168.10.12:8080;
server 192.168.10.13:8080 down;
}

Перезапустим Nginx:

/etc/init.b/nginx restart

Заходим на exmaple.org и обновляем страницу. Нам приходят ответы от NODE 01 и NODE 02.

Недостатки данной системы

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

1)Перенаправлением пользователя на определенный сервер, используя в качестве идентификатора IP клиента.
2)Использованием распределенной файловой системы, с репликацией файлов между узлами. Первый способ выполнить довольно просто, используя ip_hash. Делается это путем добавления директивы в

upstream backend {
ip_hash
server 192.168.10.11:8080;
server 192.168.10.12:8080;
server 192.168.10.13:8080;
}

В случае использования ip_hash директива, указывающая вес сервера игнорируется и все запросы с одного клиентского IP, будут попадать на один и тотже сервер. Второй способ это использование распределенных файловых систем, например-GlusterFS, но это тема для отдельной статьи, которую я планирую написать в будущем. За более подробной информацией всегда можно обратиться на сайт разработчика. В целом данная схема позволяет распределять нагрузку уже работающих проектов, убирая основной (боевой) сервер за балансировщик, параллельно добавляя к нему дополнительные сервера. В конце всего этого просто меняются DNS записи, которые начинают указывать на IP сетевого интерфейса нового балансировщика, который торчит в интернет. Если все делается именно так, то зачастую, пользователи даже ничего не заметят, а сервис тихо масштабируется без приостановки обслуживания. На этом можно и завершить эту эпопею…

Источник: блог {cyberFuntik}

балансировка nginx, linux, nginx

Previous post Next post
Up