Pull to refresh

Организация High-Load cluster с несколькими нодами

Reading time 8 min
Views 20K
В ответ на этот этот топик решил написать свои соображения по тому, как стоит строить кластер для высоко нагруженных проектов.

Топик очень хорош. Очень приятно почитать подобное с точки зрения разработчика.

По роду деятельности я занимаюсь предоставлением хостинг услуг. 90% моей работы составляет настройка и администрирование серверов для тяжеленных магазинов, написанных на движке magento. Поэтому производительности уделяю очень много внимания.

За время работы у меня выработалось некое виденье идеального кластера для тяжеловесных проектов. Это:

— 2 WEB сервера

— 1 DB сервер

— 1 балансировщик нагрузки.

Совсем не ново, но соображения связаны именно с балансировщиком нагрузки

Сколько бы кто не плевался кислотой в сторону апача, но достойной замены ему я не обнаружил. В каждом продукте, который доводилось пробовать были свои недоработки. Возникали разного рода проблемы, которые всякими силами я пытался решить, но в конце концов отправлял все инсталляции, типа lighthttp или nginx+php-fcgi на свалку, и возвращал апач с милым набором модулей.

Собственно он и будет крутить php приложение на двух web-серверах. Там же, по вкусу, включаем нужные модули и отключаем ненужные.

Web servers:


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

Меняем стандартные настройки mod_prefork. Директивы ServerLimit и MaxClients ставим равными 100. Директивы StartServers и MinSpareServers устанавливаем на одинаковые значения, например 50. MaxSpareServers можем игнорировать (коментируем). Скорее всего, наш сервер не сможет столько запросов обрабатывать, а возможно сможет обрабатывать и больше — все зависит от приложения. Именно поэтому после запуска кластера в жизнь эти значения прийдется менять. MaxRequestsPerChild можно поставить на 2000-3000.

Включаем keepallive и ставим его на очень маленькое значение. 3-ки будет достаточно. Это нужно для того, что бы контент, выдаваемый вэб сервером, одтавался в рамках одного get запроса.

Добавляем в apache.conf или httpd.conf строку «ServerTokens Prod», что бы спрятать версию нашего вэб сервера. Нужно это на всякий случай. Наш балансировщик нагрузки эту информацию от посторонних скроет. Но об это дальше.

На этих серверах будет храниться исключительно код. Статический контент (всякие картинки, шрифты, иконки) мы положим на балансировщик нагрузки. Для синхронизации контента я не рекомендовал бы смотреть в сторону DRBD, поскольку в режиме Primary-Primary его настраивают только юные натуралисты и то на лабораторных занятиях по медицине. Для синхронизации контента лучше использовать rsync. Маленькое задание крона или небольшой скрипт, который будет запускаться каждые 2-3 минуты will do the trick. Если приложение пишет какие-то файлы (например логи) в свои каталоги, то эти файлы нужно исключить из синхронизации.

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

Лучше сделать несколько разделов. Отдельно boot, /var/log, /(root), SWAP и /var/www. При чем лучше, если они (кроме /boot) будут в lvm. Это позволит с легкостью добавлять место, в случае необходимости.

Разбивка на Ваше усмотрение. На пример: boot = 0.2Gb, /var/log=5Gb, /=5Gb, swap=1Gb и /var/www = столько, сколько нужно вашему приложению.

Рекомендую логи приложения хранить в /var/log. Если приложение не поддерживает настройку места расположения логов, то можно сделать кастомные папки, и настроить bind-mounts в нужное место.

пример из fstab:

/var/log/app_logs /var/www/app_html/log none rw,bind 0 0


DataBase server:


Здесь будет жить наша бд. Рассказывать много не буду. Обычный себе ДБ сервер. В зависимости от того, какое ПО используете, так и настраивайте. В плане разбивки винта — то, же что и для Web Серверов, только вместо /var/www, на пример, нужно будет смонтировать раздел в /var/lib/mysql, в случае если Ваши базы вертятся на mysql. Собственно такая же логика монтирования и для других движков.

Преимущество отдельного ДБ сервера в том, что его работа не будет грузить сервер, на котором выполняется php. И на оборот. При работе два Web сервера будут использовать одну и ту же базу.

Опять же использование lvm позволит с легкостью добавить места «на лету» в нужный раздел, при необходимости.

Load Balancer:


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

Для начала нужно определиться с накопителем, так как здесь будет храниться весь статический контент. Логика та же — отдельный раздел для логов, свапа и для корня файловой системы. Для медиа контента тоже отдельный раздел. Все в lvm'е.

Сюда же ставим memcached, и настраиваем приложения на соединение с этим сервером.

Дальше стоит определиться с балансировщиком нагрузки. Я бы смотрел в сторону nginxa, так как он поддерживает ssl. Но можно повесить перед ним haproxy. Тогда получится 2 схемы движения пакетов:

1. Client -> web_varnish:80 -> haproxy:80 -> web_backend

Client -> static_varnish:80 -> nginx

2. Client -> haproxy:443 -> nginx -> upstream_backend

Логика такая, что https трафик проходит через haproxy и идет на отдельный web-host nginxa, в котором описаны бэкэнд сервера. Это позволяет делать ssl handshake на уровне nginxa. Статику отдает nginx, a динамический контент nginx запрашивает с backend серверов, описанных через upstream module.

Http контент будет кэшироваться с помощью varnish, в зависимости от настроек последнего. В настройках varnish контент разруливается по логике:

если запросили что-то из css, js, ico, gif, jpeg, jpg, png, eot, ttf, swf, woff {

используем бэкэнд nginx }

если что-то другое {

используем бэкэнд haproxy}



Схема и так не проста. Почему я хочу использовать haproxy? Просто дурачок? Нет. Именно haproxy позволит нам контролировать количество соединений, которое мы будем пускать на наши бэкэнд сервера. Но все по порядку.

Сначала настроим varnish. Редактируем конфигурационный файл варниша: в debian/ubuntu это /etc/default/varnish; в redhat/centos это /etc/sysconfig/varnish.

INSTANCE=$(uname -n)

DAEMON_OPTS="-a %external_ip%:80 \

-T %external_ip%:6082 \

-u varnish -g varnish \

-p thread_pools=1 \

-f /etc/varnish/config.vcl \

-s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G"



Дальше опишем мои соображения в /etc/varnish/config.vcl



backend haproxy {  .host = "127.0.0.1";  .port = "80";}

backend nginx {  .host = "127.0.0.1";  .port = "802";}

sub vcl_recv {

 remove req.http.X-Forwarded-For;

 set    req.http.X-Forwarded-For = client.ip;

# Remove unneaded request cookies:

 if (req.http.Cookie) {

    set req.http.Cookie = regsub(req.http.Cookie, "^(.*)$", "; \1");

    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");

    set req.http.Cookie = regsuball(req.http.Cookie, ";(SESS[a-z0-9]|xyz+)=", "; \1=");

    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");

    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

    if (req.http.Cookie == "") {

       unset req.http.Cookie;

    }

     else {

       return (pass);

    }

 }

       # Set backend for static content...

       if (req.url ~ "*\.(css|js|ico|gif|jpeg|jpg|png|eot|ttf|swf|woff)$") {

           unset req.http.Cookie;

           set req.backend = nginx;

       }

       # Use apache as backend for dinamic content.

       else{

           set req.backend = haproxy;}

}

sub vcl_fetch {

 set obj.ttl = 10m;

 set beresp.http.X-Backend = req.backend;

 if (beresp.status == 200 || beresp.status == 301 || beresp.status == 302) {

    if (req.url ~ "*\.(png|jpg|jpeg|gif|css|js|swf|ico)$") {

    unset req.http.Https;

    unset req.http.Cookie;

    unset beresp.http.set-cookie;

    return (deliver);

 }

 if (beresp.http.Content-Type ~ "text/html" || beresp.http.Content-Type ~ "text/xml") {

    if (req.http.Cookie ~ "frontend=") {

     return (hit_for_pass);.

    }

    }

 }

}



Дальше настраиваем схему для http:

1. Nginx Http configuration:



server {

listen 127.0.0.1:802;

location ~* \.(ico|gif|jpeg|jpg|png|eot|ttf|swf|woff)$ {

       root /var/www/media;

       expires 30d;

}

location ~* \.(css|js)$ {

       root /var/www/media;

       expires 7d;

}

}



2. Nginx High load page:



server {

listen 127.0.0.1:4433;

ssl on;

ssl_protocols SSLv3 TLSv1;

ssl_certificate /etc/nginx/SSL/cert.pem;

ssl_certificate_key /etc/nginx/SSL/server.key;

location / {

    root /var/www/hl_page/;

}

}

server {

listen 127.0.0.1:803;

location / {

    root /var/www/hl_page/;

}

}



Осталось настроить haproxy (файл /etc/haproxy/haproxy.cfg).



listen http 127.0.0.1:80

   mode http

   option httplog clf

   balance roundrobin

   option forwardfor

   option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www

   server 192.168.2.2:80 cookie SC1 maxconn 100 maxqueue 10 check inter 8000 fall 3

   server 192.168.2.3:80 cookie SC1 maxconn 100 maxqueue 10 check inter 8000 fall 3

   server backup 127.0.0.1:802 check port 803;



Haproxy будет принимать соединения на лупбэк адаптере на 80-м порту. Дальше будет отправлять соединения на вэб сервера, при этом передавая ip адресс клиента (не уверен, что он дойдет до конечного адресата). На каждый бэкэнд будет пускаться 100 соединений, если суммарное значение будет превышено для двух бэкэндов — будет показываться красивая страничка с сообщением о том, что в данный момент кластер перегружен. Содержание странички — дело рук и фантазии тех, кто размещает сайт на кластере.

Именно здесь кроется еще одна вкусняшка. (Простите, те кому не нравится, что я использую это слово). Появление сведений о том, что отображается highload page в логах haproxy, будет неким индикатором того, что посещаемость растет и нужно думать о том, что бы увеличивать мощности кластера или крутить настройки. Именно поэтому я и предлагаю использовать haproxy. Для того, что бы оно писало логи нужно сделать 2 вещи:

1. Вставить следующее в секцию global файла haproxy.cfg

log 127.0.0.1:514 local2

2. В случае использования rsyslog создать файл /etc/rsyslog.d/haproxy.conf следующего содержания:



   # Save HA-Proxy logs

   $ModLoad imudp

   $UDPServerRun 514

   $UDPServerAddress 127.0.0.1

   $FileCreateMode 0664

   local2.*        -/var/log/haproxy/haproxy_all.log

   &~



не забываем создать папку для логов и настроить logrotate. Логи будут большими.

Дополнительной плюшкой для нашего кластера может быть, на пример, cacti, которая будет рисовать красивые цветные графики о производительности нашего кластера. 3-4 хоста кактус может мониторить без особой нагрузки на сервер. Развернуть ее можно на этом же балансировщике. Инструкции читать на оффсайте cacti. Ставится за 2 минуты. Требует snmpd. При этом можно будет отследить можно ли увеличить лимиты входящих соединений на наши бэкэнды. Помните я говорил о том, что придется еще крутить значения MaxClients в настройках «prefork_module» apache2? Вот как раз тот момент. Если у нас на сервере не большая нагрузка в раёне того времени, когда отображается high load page, значит бэкэнды прекрасно справляются с нагрузкой и лимиты можно увеличить, соответственно увеличивая значение «maxconn» в конфигурации haproxy.

Следующим шагом будет настройка https. Для начала настроим haproxy:



listen https %externall_ip%:443

   mode tcp

   balance source

   option ssl-hello-chk

   server 127.0.0.1:443 maxconn 200 maxqueue 10 check port 443 inter 8000 fall 3

   server backup 127.0.0.1:443 check port 443



Nginx Https configuration

upstream apache  {

 server 192.168.2.2:443; # first backend server

 server 192.168.2.3:443; # second backend server

}

server {

listen 127.0.0.1:443;

ssl on;

ssl_protocols SSLv3 TLSv1;

ssl_certificate /etc/nginx/SSL/cert.pem;

ssl_certificate_key /etc/nginx/SSL/server.key;

location ~* \.(ico|gif|jpeg|jpg|png|eot|ttf|swf|woff)$ {

    root /var/www/media;

    expires 30d;

}

location ~* \.(css|js)$ {

    root /var/www/media;

    expires 7d;

}

location / {

    proxy_pass  https://apache;

}

}


Вместо заключения


Кажется все описал, что хотел. Спасибо тем, кто осилил сие чтиво. Еще пару слов в завершение.

Большим плюсом этой схемы является легкость в наращивании ресурсов. Не хватает мощностей? Не вопрос — клонируем вэб ноду, запускаем rsync, прописываем ее ip адрес в настройки балансировщика и вуаля — наш кластер стал мощнее. Не хватает где-то места? Тоже не проблема — лвм наш друг :)

Небольшой проблемой может стать миграция, в плане длительного планирования.

Не могу гарантировать, что предложенные конфиги будут работать для Вас. Они очень приблизительные. Я пытался описать саму идею.

Если хотим уже очень отказоустойчивый кластер — можно писать еще одну статью.

Если кому-то хватит мудрости подобное настраивать — обращайтесь — мне самому интересно как оно заработает.
Tags:
Hubs:
+11
Comments 36
Comments Comments 36

Articles