При увеличении нагрузки или посещаемости проекта, рано или поздно вертикальное маштабирование (увеличение ресурсов сервера, таких как память, скорость диска и т.д) упирается в некий предел и не дает ощутимого прироста. В таком случае в ход идет горизонтальное масштабирование - добавление новых серверов c перераспределением нагрузки между ними.
Кроме увеличения мощности, горизонтальное масштабирование добавляет надежности системе - при выходе из строя одного из серверов, нагрузка будет сбалансирована между работающими и приложение будет жить.
Ниже рассмотрим одну из простых схем горизонтального маштабирования, состоящую из двух серверов приложений, одного сервера БД и балансировщика нагрузки. Такая схема оптимальна для приложений с большой нагрузкой на PHP и неинтенсивном использовании базы данных.
Все эксперименты с горизонтальным маштабированием можно проводить в "домашних условиях" используя виртуальные машины. Я использую VirtualBox, в котором для текущей схемы создал 4 виртуальных сервера с Ubuntu Server на борту. Схема работы системы будет выглядеть следующим образом:
Все запросы проходят через балансировщик, который определяет кому из серверов отдать на обработку. О его настройке и пойдет речь.
При получении запроса от клиента, балансировщику нужно определить, какому из веб серверов переслать запрос. Алгоритм принятия решения называется методом или стратегией балансировки, наиболее распространенные стратегии:
- Round robin. Из доступных серверов строится очередь и балансировщик выбирает первый в очереди. После выполнения запроса сервер перемещается в конец очереди.
- Меньшее количество соединений. Балансировщик ведет учет количества незакрытых соединений и выбирает тот сервер, у которого таких соединений меньше.
- Использование "веса" серверов. Каждому серверу в зависимости от мощности присваивается вес, который используется для ранжирования.
Очевидно, что стратегия, не включающая проверку состояния серверов или хотя бы работоспособности, не пригодна для использования, так как не гарантирует обработку запроса. Поэтому наш алгоритм должен уметь проверять боеспособность сервера, его загруженность и выбирать наиболее способный.
При балансировке часто возникает проблема хранения сессий, ведь сессия доступна только на создавшем ее сервере, что нужно учитывать в алгоритме перенаправления запроса. Или же хранить сессии на отдельном сервере либо в БД.
Мы не будем заниматься этим вопросом, так как он сильно зависит от конкретного приложения. Представим, что наше приложение либо не использует сессии, либо хранит их в БД.
Для реализации программного балансировщика есть много решений, например:
- Nginx
- Apache + mod_proxy_balancer
- прокси сервер
Мы остановимся на последнем. Попробуем настроить Haproxy, согласно описанной выше стратегии.
Устанавливается прокси-сервер очень просто:
sudo apt-get install haproxy
Для конфигурации, нам нужно знать ip адреса веб серверов, у моих виртуальных машин они 192.168.1.1 и 192.168.1.2 соответственно.
Настроим простую балансировку, для чего пропишем в конфигурации прокси-сервера /etc/haproxy/haproxy.cfg:
global
maxconn 4096
user haproxy
group haproxy
daemon
defaults
log global
mode http
option httplog
option dontlognull
retries 3
option redispatch
maxconn 2000
contimeout 5000
clitimeout 50000
srvtimeout 50000
listen webcluster *:80
mode http
balance leastconn
option httpchk HEAD / HTTP/1.0
option forwardfor
cookie serv insert
option httpclose
server webserver1 192.168.1.1:80 cookie serv1 check
server webserver2 192.168.1.2:80 cookie serv2 check
Последний блок наиболее интересен, так как в нем настраиваются главные параметры балансировки, рассмотрим каждую строку детально.
| режим работы прокси касающийся обработки пакетов |
| важный момент, это алгоритм выбора сервера, о котором мы говорили выше. leastconn - перенаправляем запрос серверу из наименьшим количеством соединений. |
| проверяем состояние сервера через http |
| так как прокси сервер отправляет запросы веб серверам, для них его ip адрес будет адресом клиента. Чтобы передавать адрес клиента, используем опцию forwardfor, которая добавляет в тело запроса заголовок X-Forwarded-For с адресом клиента. |
| для обеспечения работы сессий, идентификаторы которых хранятся в куки, а данные на сервере, добавляем куку serv, которая будет хранить адрес сервера, работающего с текущим клиентом. Таким образом клиент всегда будет попадать на один сервер и иметь доступ к данным сессии. |
| автоматически закрывать соединения после завершения передачи данных |
| добавляем первый веб сервер указывая адрес, значение куки для определения сервера и необходимость проверки состояния. |
| аналогично второй. |
sudo haproxy -f /etc/haproxy/haproxy.cfg
Балансировка настроена! Если открыть несколько браузеров одновременно и попробовать зайти на сайт, в куки браузеров должны установиться разные значения переменной serv, в зависимости от назначенного сервера.
Конфигурация haproxy конечно же сильно зависит от задачи, например для раздачи статического контента или работы сайта без сессий незачем привязывать конкретный сервер к клиенту. Поэтому если нужна более специфическая настройка, документация (кстати очень обширная) в помощь: http://cbonte.github.com/haproxy-dconv/configuration-1.5.html
На этом все, вопросы, замечания и пожелания приветствуются в комментариях.
В тему:
Если пост понравился - нажмите на +1 - мне будет приятно.