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

в 21:20, , рубрики: haproxy, linux, nginx, Varnish, Песочница, Серверное администрирование, метки: , , ,

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

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

За время работы у меня выработалось некое виденье идеального кластера для тяжеловесных проэктов.
это:
— 2 WEB сервера
— 1 DB сервер
— 1 балансировщик нагрузки.

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

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

Web servers:

Дальше чистая абстрактная полемика по настройке вэб серверов. После запуска их в жизнь и наблюдения за нагрузкой прийдется все менять и перенастраивать, ну а пока нужно с чего-то начинать.
Меняем стандартные настройки mod_prefork. Директивый ServerLimit и MaxClients ставим равными 100. Это позволит нашим серверам одновременно обрабатывать по 100 соединений в секунду. Директивы StartServers и MinSperServers устанавливаем на одинаковые значения, например 50. MaxSperServers можем игнорировать (коментируем). Скорее всего, наш сервер не сможет столько запросов обрабатывать, а возможно сможет обрабатывать и больше — все зависит от приложения. Именно поэтому после запуска кластера в жизнь эти значения прийдется менять. 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.1rnHost: 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 адрес в настройки баллансровщика и вуаля — наш кластер стал мощнее. Не хватает где-то места? Тоже не проблема — лвм наш друг :)
Небольшой проблемой может стать миграция, в плане длительного планирования.
Не могу гарантировать, что предложеные конфиги будут работать для Вас. Они очень приблизительные. Я пытался описать саму идею.

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

Если кому-то хватит мудрости подобное настраивать — обращайтесь — мне самому интересно как оно заработает

Автор: tryvia

Источник


  1. adre:

    Добрый день, данные мысли это для 1 сайта?

    а как сделать под shared hosting?

  2. Аноним:

    спасибо всем чуть не купился на это разводилово

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js