Балансировка нагрузки с помощью NginX
Приветствую тебя, дорогой читатель. В этой статье я хочу описать настройку NginX
для балансировки нагрузки на несколько back-end серверов, допустим Apache.
Итак предлагается следующая схема (картинка кликабельна):
В этом довольно простом деле нам помогут две директивы NginX:
- upstream - директива, которая поставляется с модулем HttpUpstream и позволяет балансировать нагрузку на несколько серверов.
- proxypass - директива, которая поставляется с модулем HttpProxy. Она позволяет корректно отправлять/проксировать запросы на сервера за балансировщиком.
Итак рассмотрим пример. Имеются 3 вэб-головы, на которых крутится один и тот же сайт. :
Apapche#1:
ip: 192.168.10.10
Apapche#2
ip: 192.168.10.20
Apapche#3
ip: 192.168.10.30
В любимом текстовом редакторе создаем конфигурационный файл nginx и вносим в него следующие строки. Лично я люблю, когда настройки сайтов хранятся в отдельных файлах.
upstream http {
server 192.168.10.10 weight=2 max_fails=2 fail_timeout=2s;
server 192.168.10.20 weight=2 max_fails=2 fail_timeout=2s;
server 192.168.10.30 weight=2 max_fails=2 fail_timeout=2s;
}
- weight - определяет значимость сервера в кластере. В данном примере все сервера - одинаковы и могут обслужить одинаковое количество запросов. Если в кластере 1 сервер значительно мощнее остальных - можно указать для него высшее значение этого параметра и NginX будет слать ему больше запросов, чем другим.
- max_fails - определяет количество неудачных попыток соединения с backend сервером.
- fail_timeout - промежуток между неудачными соединениями.
В данном примере после 2-х неудачных соединений на протяжении 4-х секунд, сервер будет помечен как недоступный и запросы к нему не будут отправляться, пока NginX не удостоверится, что с сервером все в порядке.
Методы балансировки нагрузки (описываются в начале секции upstream):
- ip_hash - согласно этому методу запросы от одного и того же клиента будут всегда отправляться на один и тот же backend сервер на основе информации об ip адресе клиента. Не совместим с параметром weight.
- least_conn - запросы будут отправляться на сервер с наименьшим количеством активных соединений.
- round-robin - режим по умолчанию. То есть если вы не задали ни один из вышеупомянутых способов балансировки - запросы будут доставляться по очереди на все сервера в равной степени.
Итак сервера с сайтом описали. Дальше нужно сказать NginX’у что с ними делать. Для этого описываем секцию location с параметрами проксирования запросов:
location / {
proxy_read_timeout 1200;
proxy_connect_timeout 1200;
proxy_pass http://http/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Итак полный конфиг для кластера выглядит следующим образом:
upstream http {
server 192.168.10.10:80 weight=2 max_fails=2 fail_timeout=2s;
server 192.168.10.20:80 weight=2 max_fails=2 fail_timeout=2s;
server 192.168.10.30:80 weight=2 max_fails=2 fail_timeout=2s;
}
server {
servername mywebsite.com www.mywebsite.com;
listen 80;
location / {
proxy_read_timeout 1200;
proxy_connect_timeout 1200;
proxy_pass http://http/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Большой прелестью балансировки нагрузки с помощью NginX является поддержка SSL Termination. То есть защищенные сессии устанавливаются с самим балансировщиком, и от него же клиенты получают ответ. Есть два варианта настройки:
- По аналогии с предыдущим примером настраиваем балансировку https сессий. При этом ssl хосты должны быть описаны и на Apache серверах. В этом случае https соединения будут устанавливаться с NginX’ом, дальше он будет формировать новый пакет, устанавливать защищенное соединение с Apache серверами, получать такой же защищенный пакет в ответ, распаковывать его, формировать новый и отправлять конечный результат клиенту в защищенном виде. Довольно трудоемкий процесс, согласитесь. В отношении производительности ооочень ресурсо-затратный.
В этом случае наш конфиг будет выглядеть следующим образом:
upstream https {
server 192.168.10.10:443 weight=2 max_fails=2 fail_timeout=2s;
server 192.168.10.20:443 weight=2 max_fails=2 fail_timeout=2s;
server 192.168.10.30:443 weight=2 max_fails=2 fail_timeout=2s;
}
server {
servername mywebsite.com www.mywebsite.com;
listen 443;
ssl on;
ssl_certificate /etc/nginx/SSL/hostname.pem;
ssl_certificate_key /etc/nginx/SSL/server.key;
location / {
proxy_read_timeout 1200;
proxy_connect_timeout 1200;
proxy_pass https://https/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
- Настраиваем https хост в NginX’e, описываем http (без
S
) соединения в upstream списке. Немного лирики: многие CMS системы имеют встроенные проверки наличия безопасных сессий и принудительно переадресовывают клиентов на безопасное соединение на страницах ввода конфиденциальной информации (авторизации пользователей, страницы оплаты услуг). Как правило это производится на основе наличия HTTPS хэдэра со значениемon
в переменном окружении SERVER. Можно просто добавлять этот хэдэр в запросы к серверам Apache и не создавать лишней нагрузки. Если этот способ не срабатывает - смотрите пункт 1.
В этом случае наш конфиг будет выглядеть следующим образом:
upstream https {
server 192.168.10.10:80 weight=2 max_fails=2 fail_timeout=2s;
server 192.168.10.20:80 weight=2 max_fails=2 fail_timeout=2s;
server 192.168.10.30:80 weight=2 max_fails=2 fail_timeout=2s;
}
server {
servername mywebsite.com www.mywebsite.com;
listen 443;
ssl on;
ssl_certificate /etc/nginx/SSL/hostname.pem;
ssl_certificate_key /etc/nginx/SSL/server.key;
location / {
proxy_read_timeout 1200;
proxy_connect_timeout 1200;
proxy_pass http://https/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
<strong>proxy_set_header HTTPS on;</strong>
}
Еще больше можно помочь нашим Apache серверами и снять с них ненужную нагрузку, раздавая статические файлы с помощью NginX. Для этого все папки со статическим контентом нужно скопировать (сохраняя дерево каталогов) на сам балансировщик нагрузки (я бы разместил в /var/www/html) и описать раздачу из с помощью NginX прямо перед секцией location /
в описании каждого хоста:
location ~* \.(ico|gif|jpeg|jpg|png|eot|ttf|swf|woff)$ {
root /var/www/html;
expires 30d;
access_log off;
}
location ~* \.(css|js)$ {
root /var/www/html;
expires 1d;
access_log off;
}
Для того чтобы статический контент нормально обновлялся при загрузке через web, можно примонтировать соответствующие папки на сервера с помощью NFS.
Как-то так.