Балансировка сетевой нагрузки с помощью Nginx под Ubuntu

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

Данное руководство, не имеет привязки к версии ОС и актуально для всех версий Debian и Ubuntu, а также легко адаптируется под другие дистрибутивы Linux.
Для лучшего понимания, привожу схему работы, в которой у нас будет использоваться 3 web сервера и 1 сервер, в качестве балансировщика нагрузки. SQL сервер мы использовать не будем, вообще-то, там можно установить целую кучу различных серверов реляционных баз данных (MySQL, MSSQL, PostgreSQL,ORACLE, и многие другие, да на худой конец Sybase-будь он не ладен) или NoSQL системы, на схеме изображено исключительно для понимания процесса, т.к. это тема отдельная и не простая. Там можно поставить несколько SQL серверов с репликацией данных, но там возникают проблемы с разрешением конфликтов, в принципе проблема решаемая, но не относящаяся, в данный момент, к этой теме, короче, будет все, кроме SQL сервера!

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

Для лучшего понимания, попробую объяснить подробнее то, что я изобразил на схеме: У нас есть небольшая сеть из 4х серверов, 3 из них работают как WEB сервера и находятся внутри локальной сети, в интернет торчит только 1 сервер, на нем работает Nginx, он виден в интернет и пользователи подключаются непосредственно к нему, он, в свою очередь, передает пользовательские запросы в локальную сеть, на основные WEB сервера, которые его обрабатывают и возвращают готовый результат, который отдается пользователям. Зачастую, никаких других операций на сервере, балансирующим сетевую нагрузку, не производится и для его работы достаточно самого простого и дешевого железа или VPS. Операционную систему можно раскатывать из заранее подготовленного образа, тогда время простоя, при выходе балансировщика из строя, будет минимальным. Пользователи не будет знать-какое количество серверов скрывается за ним, а их могут быть десятки и сотни, но в сети виден всего один, можно развернуть дополнительный балансировщик и запросы к нему распределять на основе службы DNS как это реализовано например у mail.ru
Если в командной строке Windows набрать:

nslookup mail.ru

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

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

nslookup mail.ru

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

Как видно из скриншота, первым в ответе будет уже другой IP, из тех 4х, что были присланы ранее. Сколько и чего, находится за этими IP адресами, знают только в mail.ru, кстати, на досуге пробуйте пройтись по крупным сетевым сервисам, можете узнать для себя что-то новое… Алгоритм распределения запросов называется Round-robin, в нашей схеме он также будет использован и является, по сути, основой всей системы.

Где еще используются подобные схемы распределения нагрузки?! Например: Для создания непотопляемых torrent треккеров, сами сервера могут тихо стоять в дата-центре, а наружу торчит только 1 в совершенно левой стране и все запросы идут через него, который в свою очередь передает их на основные для обработки. В случае отключения данного сервера по жалобе, то ему быстро находится замена в виде покупки самого дешевого VPS в другой стране и в течении 1-2 часов треккер снова доступен, ведь основные мощности никуда не переезжали -привет правообладателям, и все работает как раньше. Можно конечно и данную схему поломать, но это отдельная песня и без административного ресурса будет довольно сложно.
Думаю что смысл понятен, если нет, то прошу в комментарии- постараюсь и на эти вопросы ответить.

Работа системы, отдаленно напоминает технологию NLB от Microsoft (кто с ней работал, тот думаю поймет о чем я), которая не отслеживает нагрузку на каждой отдельной ноде, а просто раскидывает пользовательские подключения между серверами, по заранее определенному алгоритму, например 50/50, когда все пользовательские подключения равномерно распределяются между узлам серверной фермы. Правда у NLB есть ограничение в 32 сервера, на одну серверную ферму, система построенная на Linux данного ограничения лишена, а узким местом можно рассматривать сетевую подсистему на самом балансировщике. По сути мы будем с вами стоить кластер распределения нагрузки, что такое кластер и на кой, нужна вся эта кластеризация, можно прочитать в Википедии
Для примера, буду использовать доменное имя example.org, для него мы и будем распределять нагрузку.
На этом с теорией все, переходим к практике.

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

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

Поднимаем права до root:

sudo su

Сначала нам необходимо установить необходимые компоненты для сборки+древнюю версию nginx из репозиториев:

aptitude 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 серверов

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

Собственно ее и настройкой трудно назвать, нам необходимо установить любой WEB сервер это может быть Apache, Nginx, Lighthttpd -не важно, или даже IIS если необходимо распределить нагрузку между серверами под Windows, значения даже не имеет, какая ОС будет на этом сервере! Давайте рассмотрим для примера 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, но данная конфигурация исключительно для примера, когда потребуется, поставите IP адреса той подсети которую будете использовать.

Далее, для того чтобы увидеть как происходит перенаправление запросов между серверами, нам необходимо отредактировать 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.html — это здорово сократит время создания тестовой инфраструктуры.
Допустим балансировщик мы настроили, backend сервера тоже. Необходимо все это протестировать.
Поднимать DNS для поддержки зоны example.org — все равно что стрелять из пушки по воробьям, по этому просто добавим запись в файл hosts.

Если дело происходит в Windows, то идем в:

C:\WINDOWS\system32\drivers\etc\hosts

Если в Linux

/etc/resolv.conf

Вписываем туда следующее:

000.000.000.000 example.org

Где: вместо 000.000.000.000 указываем IP адрес, сетевого интерфейса, сервера балансировки нагрузки, который должен смотреть в интернет.

Открываем броузер и переходим по адресу example.org
В ответ мы получим следующее:

Жмем F5.

Еще раз F5 и получаем ответ от третей ноды.

Если обновлять страницу и дальше, то станет понятно, что ответы от серверов идут по кругу.
В общем, видно что распределение запросов происходит нормально!
Что еще можно улучшить, в данной схеме?!
Например 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:

sudo /etc/init.b/nginx restart

Заходим на exmaple.org и обновляем страницу, нам приходят ответы от NODE 01 и NODE 02, чтобы все вернуть как было, достаточно убрать down перезапустить Nginx, на балансировщике сетевой нагрузки, третий сервер вернется в эксплуатацию и все будет как раньше.

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

Один существенный недостаток, если на сервере хранятся файлы пользовательских сессий, то в случае перенаправления пользователей на другой сервер, они будут недоступны.
Данную проблему, можно решить двумя способами:
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 директива указывающая вес сервера weight игнорируется и все запросы с одного клиентского IP, будут попадать на один и тотже сервер.

Второй способ это использование распределенных файловых систем, например-GlusterFS, но это тема для отдельной статьи, которую я планирую написать в будущем.

За более подробной информацией всегда можно обратиться на сайт разработчика.
Осталось только на backend сервера поставить Fast-CGI и можно приступать к работе. Статья о том, как установить поддержку PHP для Nginx. Естественно, поддержку PHP, необходимо установить на каждый backend сервер.

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

Источник : http://howitmake.ru/blog/ubuntu/55.html

Запись опубликована в рубрике *CentOS, *Unix,*Linux, FreeBSD. Добавьте в закладки постоянную ссылку.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Я не спамер This plugin created by Alexei91