Балансировка нагрузки и
отказоустойчивость Nginx, реализуется с помощью специального модуля
ngx_http_upstream. Директива
upstream позволяют организовывать группы серверов (
upstream ), распределяя между ними запросы для проксирования в директивах
proxy_pass и
fastcgi_pass. Кроме того, это дает
Nginx возможность, реагировать на нештатные ситуации в апстриме, например, в случае выхода из строя одного или нескольких серверов из группы, запрос будет отправлен на следующий, работающий сервер апстрима.
Итак, как это все организовано. Модуль
веб сервера Nginx -
ngx_http_upstream поддерживает следующие директивы конфигурационного файла:
- upstream название { .... }
- Работает в контексте http
Директива определяет группу серверов, между которыми будут распределяться запросы. Сервера, в свою очередь, задаются с помощью директивы server с соответствующими параметрами ( см. ниже ). В случае возникновения ошибки, в процессе работы с сервером, запрос отправляется на следующий сервер группы и так далее, по списку. Если не будет найден, ни один работающий сервер, клиенту будет отдан результат работы последнего сервера.
- server название [ необязательные параметры ]
- работает в контексте upstream
Данная директива определяет один сервер группы. В качестве имен серверов можно использовать: домен, IP адрес, порт или путь до файла unix-сокета. Имеет следующие параметры:
weight = число, так называемый вес сервера, на основании которого идет распределение запросов. Если параметр не указан, вес равен 1.
max_fails = число, задает число неудачных попыток обращения к серверу, в промежуток времени, установленный параметром fail_timeout, после которых, сервер считается неработающим, в течении времени, опять-же установленного параметром fail_timeout. Если параметр не указан, число попыток равно 1. Какую ситуацию считать ошибкой, в процессе работы с сервером из группы, определяют директивы proxy_next_upstream и fastcgi_next_upstream, в соответствующих блоках Location.
fail_timeout = время, интервал времени, в течение которого должно произойти, указанное параметром max_fails, число неудачных попыток обращения к серверу группы, а так-же, время, в течение которого, данный сервер, будет считаться неработающим. Если ничего не задано, данное время равно 10 секундам.
backup, определяет сервер как запасной. Будет использован в случае, отказа всех остальных серверов группы.
down , определяет сервер как всегда неработающий, используется с директивой ip_hash.
Группа серверов может представлять собой любую комбинацию из приведенного списка:
upstream test_upstream {
server 127.0.0.1:8080 weight=3;
server test.domail.ru max_fails=5 fail_timeout=60s;
server unix:/tmp/fastcgi_socket fail_timeout=30s;
server backup.server.com backup;
}
В данном примере, 3 запроса будут отправлены на первый сервер, 1 на второй и 1 на третий, затем снова 3 на первый. Сервер backup.server.com, будет использоваться только в случае отказа всех серверов.
- ip_hash
- работает в контексте upstream
Директива определяет метод распределения запросов по серверам группы, на основании IP адреса клиента. Такой способ распределения запросов, гарантируется, что запросы клиента, будет обслуживать один и тот-же сервер. В случае отказа данного сервера, запросы перенаправлены на другой сервер группы и тоже с большой долей вероятности, будут обслужены одним и тем-же сервером. Обратите внимание, при данном методе распределения запросов, нельзя задать вес ( параметр weight ), сервера.
Теперь как это выглядит на практике. Операционная
система FreeBSD 7.1 STABLE, фронтендом на внешнем IP адресе стоит
Nginx/0.7.61, в качестве первого бакэнда,
FastCGI сервер, работающий по TCP( локальный адрес
127.0.0.1, порт
9000 ), второй и третий бакэнды,
FastCGI сервера
PHP ( на
unix-сокетах ).
Конфигурационный файл
Nginx выглядит следующим образом:
http {
include mime.types;
default_type application/octet-stream;
log_format upstream '$upstream_addr | $request - [ $upstream_response_time ]';
Настройка формата логов. Здесь мы используем переменные модуля upstream, что-бы увидеть работу апстрима в лог файлах.
$upstream_addr - данная переменная содержит адрес и порт сервера или путь к файлу unix-сокета. Если в процессе обработки запроса, будет сделано обращение к нескольким сервера, они будут перечислены через запятую.
$upstream_status - содержит статус ответа сервера, если больше одного, так-же перечисляются через запятую.
$upstream_response_time - время ответа сервера с точностью до миллисекунд. От самого начала соединения с сервером-бакэндом до закрытия с ним соединения. Очень полезная переменная, для проверки скорости ответов бакэндов.
Кроме того, существуют переменные, $upstream_http_строка заголовка, содержащие строки заголовка, ответа сервера.
sendfile on;
tcp_nopush on;
keepalive_timeout 0;
gzip on;
upstream fastcgi {
server unix:/tmp/fastcgi_sock weight=4;
server unix:/tmp/fastcgi2_sock max_fails=2 fail_timeout=30s;
server 127.0.0.1:9000 backup;
}
Блок директивы upstream. Запросы в данном случае будут распределяться следующим образом, 4 запроса уйдут на первый сервер, 1 запрос на второй, снова 4 на первый и т.д.. Если вторым сервером, в течении 30 секунд, будет выдано 2 ошибки ( какие ситуации будут считаться ошибками, смотрите ниже ), он будет считаться неработающим в течении 30 секунд. Если оба сервера перестанут отвечать, будет задействован резервный сервер с пометкой backup.
server {
listen 192.168.50.20:80;
server_name nginx;
access_log logs/nginx_upstream_access.log upstream; # Пишем логи в настроенном нами формате.
root /usr/home/test/public_html;
location / {
index index.php index.html index.htm;
}
location ~ \.php$ {
fastcgi_pass fastcgi; # Передача запросов на нашу группу серверов
fastcgi_next_upstream error timeout http_500 http_404;
Какую ситуацию считать ошибкой бакэнд-сервера и отправлять запрос на следующий сервер группы. Возможные значения:
error - ошибка соединения, чтения заголовка или передачи ответа.
timeout - таймаут во время соединения, чтения заголовка или передачи ответа.
invalid_header - возврат пустого или неправильного заголовка.
http_500 - ответ с кодом 500.
http_503 - ответ с кодом 503.
http_404 - ответ с кодом 404.
off - не передавать запрос следующему серверу.
Передача запроса следующему серверу, возможна только в случае, если клиенту еще ничего не отдано.
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
location ~ /\.ht {
deny all;
}
}
}
Теперь можно проверить работоспособность, как мы делали в предыдущих статьях, то есть запрашиваем через строку браузера простенький PHP файл и смотрим в логе
logs/nginx_upstream_access.log, куда идут запросы. Для большего понимания работы данной схемы, можно поиграть с параметрами серверов апстрима, поотключать некоторые из них, что-бы увидеть, что происходит в случае сбоев.