Модуль ngx_http_upstream_module

Пример конфигурации
Директивы
     upstream
     server
     zone
     state
     hash
     ip_hash
     keepalive
     ntlm
     least_conn
     least_time
     health_check
     match
     queue
     sticky
     sticky_cookie_insert
Встроенные переменные

Модуль ngx_http_upstream_module позволяет описывать группы серверов, которые могут использоваться в директивах proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass и memcached_pass.

Пример конфигурации

upstream backend {
    server backend1.example.com       weight=5;
    server backend2.example.com:8080;
    server unix:/tmp/backend3;

    server backup1.example.com:8080   backup;
    server backup2.example.com:8080   backup;
}

server {
    location / {
        proxy_pass http://backend;
    }
}

Динамически настраиваемая группа, доступна как часть коммерческой подписки:

resolver 10.0.0.1;

upstream dynamic {
    zone upstream_dynamic 64k;

    server backend1.example.com      weight=5;
    server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
    server 192.0.2.1                 max_fails=3;
    server backend3.example.com      resolve;

    server backup1.example.com:8080  backup;
    server backup2.example.com:8080  backup;
}

server {
    location / {
        proxy_pass http://dynamic;
        health_check;
    }
}

Директивы

Синтаксис: upstream название { ... }
Умолчание:
Контекст: http

Описывает группу серверов. Серверы могут слушать на разных портах. Кроме того, можно одновременно использовать серверы, слушающие на TCP- и UNIX-сокетах.

Пример:

upstream backend {
    server backend1.example.com weight=5;
    server 127.0.0.1:8080       max_fails=3 fail_timeout=30s;
    server unix:/tmp/backend3;

    server backup1.example.com  backup;
}

По умолчанию запросы распределяются по серверам циклически (в режиме round-robin) с учётом весов серверов. В вышеприведённом примере каждые 7 запросов будут распределены так: 5 запросов на backend1.example.com и по одному запросу на второй и третий серверы. Если при попытке работы с сервером происходит ошибка, то запрос передаётся следующему серверу, и так далее до тех пор, пока не будут опробованы все работающие серверы. Если не удастся получить успешный ответ ни от одного из серверов, то клиенту будет возвращён результат работы с последним сервером.

Синтаксис: server адрес [параметры];
Умолчание:
Контекст: upstream

Задаёт адрес и другие параметры сервера. Адрес может быть указан в виде доменного имени или IP-адреса, и необязательного порта, или в виде пути UNIX-сокета, который указывается после префикса “unix:”. Если порт не указан, используется порт 80. Доменное имя, которому соответствует несколько IP-адресов, задаёт сразу несколько серверов.

Могут быть заданы следующие параметры:

weight=число
задаёт вес сервера, по умолчанию 1.
max_fails=число
задаёт число неудачных попыток работы с сервером, которые должны произойти в течение времени, заданного параметром fail_timeout, чтобы сервер считался недоступным на период времени, также заданный параметром fail_timeout. По умолчанию число попыток устанавливается равным 1. Нулевое значение отключает учёт попыток. Что считается неудачной попыткой, определяется директивами proxy_next_upstream, fastcgi_next_upstream, uwsgi_next_upstream, scgi_next_upstream и memcached_next_upstream.
fail_timeout=время
задаёт
  • время, в течение которого должно произойти заданное число неудачных попыток работы с сервером для того, чтобы сервер считался недоступным;
  • и время, в течение которого сервер будет считаться недоступным.
По умолчанию параметр равен 10 секундам.
backup
помечает сервер как запасной сервер. На него будут передаваться запросы в случае, если не работают основные серверы.
down
помечает сервер как постоянно недоступный.

Кроме того, следующие параметры доступны как часть коммерческой подписки:

max_conns=число
ограничивает максимальное число одновременных активных соединений к проксируемому серверу (1.5.9). Значение по умолчанию равно 0 и означает, что ограничения нет.
При включённых постоянных соединениях и нескольких рабочих процессах общее число соединений с проксируемым сервером может превышать значение max_conns.
resolve
отслеживает изменения IP-адресов, соответствующих доменному имени сервера, и автоматически изменяет конфигурацию группы без необходимости перезапуска nginx (1.5.12). Группа должна находиться в зоне разделяемой памяти.

Для работы этого параметра директива resolver должна быть задана в блоке http. Пример:

http {
    resolver 10.0.0.1;

    upstream u {
        zone ...;
        ...
        server example.com resolve;
    }
}

route=строка
задаёт имя маршрута к серверу.
slow_start=время
задаёт время, в течение которого вес сервера восстановится от нуля до своего номинального значения в ситуации, когда неработоспособный (unhealthy) сервер вновь становится работоспособным (healthy) или когда сервер становится доступным по прошествии времени, в течение которого он считался недоступным. Значение по умолчанию равно нулю и означает, что медленный старт выключен.

Если в группе только один сервер, параметры max_fails, fail_timeout и slow_start игнорируются и такой сервер никогда не будет считаться недоступным.

Синтаксис: zone имя [размер];
Умолчание:
Контекст: upstream

Эта директива появилась в версии 1.9.0.

Задаёт имя и размер зоны разделяемой памяти, в которой хранятся конфигурация группы и её рабочее состояние, разделяемые между рабочими процессами. В одной и той же зоне могут быть сразу несколько групп. В этом случае достаточно указать размер только один раз.

Дополнительно, как часть коммерческой подписки, в таких группах для изменения состава группы или настроек отдельных серверов нет необходимости перезапускать nginx. Конфигурация доступна через специальный location, в котором указана директива upstream_conf.

Синтаксис: state file;
Умолчание:
Контекст: upstream

Эта директива появилась в версии 1.9.7.

Задаёт файл, в котором хранится состояние динамически настраиваемой группы. В данный момент состояние ограничено списком серверов с их параметрами. Файл читается при парсинге конфигурации и обновляется каждый раз при изменении конфигурации группы. Изменение содержимого файла напрямую не рекомендуется. Директиву нельзя использовать совместно с директивой server.

Изменения, совершённые в момент перезагрузки конфигурации или обновления бинарного файла, могут быть потеряны.

Эта директива доступна как часть коммерческой подписки.

Синтаксис: hash ключ [consistent];
Умолчание:
Контекст: upstream

Эта директива появилась в версии 1.7.2.

Задаёт метод балансировки нагрузки для группы, при котором соответствие клиента серверу определяется при помощи хэшированного значения ключа. В качестве ключа может использоваться текст, переменные и их комбинации. Следует отметить, что любое добавление или удаление серверов в группе может привести к перераспределению большинства ключей на другие серверы. Метод совместим с библиотекой Perl Cache::Memcached.

Если задан параметр consistent, то вместо вышеописанного метода будет использоваться метод консистентного хэширования ketama. Метод гарантирует, что при добавлении сервера в группу или его удалении на другие серверы будет перераспределено минимальное число ключей. Применение метода для кэширующих серверов обеспечивает больший процент попаданий в кэш. Метод совместим с библиотекой Perl Cache::Memcached::Fast при значении параметра ketama_points равным 160.

Синтаксис: ip_hash;
Умолчание:
Контекст: upstream

Задаёт для группы метод балансировки нагрузки, при котором запросы распределяются по серверам на основе IP-адресов клиентов. В качестве ключа для хэширования используются первые три октета IPv4-адреса клиента или IPv6-адрес клиента целиком. Метод гарантирует, что запросы одного и того же клиента будут всегда передаваться на один и тот же сервер. Если же этот сервер будет считаться недоступным, то запросы этого клиента будут передаваться на другой сервер. С большой долей вероятности это также будет один и тот же сервер.

IPv6-адреса поддерживаются начиная с версий 1.3.2 и 1.2.2.

Если один из серверов нужно убрать на некоторое время, то для сохранения текущего хэширования IP-адресов клиентов этот сервер нужно пометить параметром down.

Пример:

upstream backend {
    ip_hash;

    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com down;
    server backend4.example.com;
}

До версий 1.3.1 и 1.2.2 для серверов, использующих метод балансировки нагрузки ip_hash, нельзя было задать вес.

Синтаксис: keepalive соединения;
Умолчание:
Контекст: upstream

Эта директива появилась в версии 1.1.4.

Задействует кэш соединений для группы серверов.

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

Следует особо отметить, что директива keepalive не ограничивает общее число соединений с серверами группы, которые рабочие процессы nginx могут открыть. Параметр соединения следует устанавливать достаточно консервативно, чтобы серверы группы по-прежнему могли обрабатывать новые входящие соединения.

Пример конфигурации группы серверов memcached с постоянными соединениями:

upstream memcached_backend {
    server 127.0.0.1:11211;
    server 10.0.0.2:11211;

    keepalive 32;
}

server {
    ...

    location /memcached/ {
        set $memcached_key $uri;
        memcached_pass memcached_backend;
    }

}

Для HTTP директиву proxy_http_version следует установить в “1.1”, а поле заголовка “Connection” — очистить:

upstream http_backend {
    server 127.0.0.1:8080;

    keepalive 16;
}

server {
    ...

    location /http/ {
        proxy_pass http://http_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        ...
    }
}

Хоть это и не рекомендуется, но также возможно использование постоянных соединений с HTTP/1.0, путём передачи поля заголовка “Connection: Keep-Alive” серверу группы.

Для работы постоянных соединений с FastCGI-серверами потребуется включить директиву fastcgi_keep_conn:

upstream fastcgi_backend {
    server 127.0.0.1:9000;

    keepalive 8;
}

server {
    ...

    location /fastcgi/ {
        fastcgi_pass fastcgi_backend;
        fastcgi_keep_conn on;
        ...
    }
}

При использовании методов балансировки нагрузки, отличных от стандартного round-robin, следует активировать их до директивы keepalive.

Протоколы SCGI и uwsgi не определяют семантику постоянных соединений.

Синтаксис: ntlm;
Умолчание:
Контекст: upstream

Эта директива появилась в версии 1.9.2.

Позволяет проксировать запросы с проверкой подлинности NTLM. Соединение с сервером группы привязывается к клиентскому соединению как только клиент отправляет запрос, в заголовке которого есть поле “Authorization” со значением, начинающимся с “Negotiate” или “NTLM”. Последующие запросы клиента будут проксироваться через это же соединение с сервером группы, сохраняя контекст аутентификации.

Для работы проверки подлинности NTLM необходимо разрешить постоянные соединения с серверами группы. Директиву proxy_http_version следует установить в “1.1”, а поле заголовка “Connection” — очистить:

upstream http_backend {
    server 127.0.0.1:8080;

    ntlm;
}

server {
    ...

    location /http/ {
        proxy_pass http://http_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        ...
    }
}

При использовании методов балансировки нагрузки, отличных от стандартного round-robin, следует активировать их до директивы ntlm.

Эта директива доступна как часть коммерческой подписки.

Синтаксис: least_conn;
Умолчание:
Контекст: upstream

Эта директива появилась в версиях 1.3.1 и 1.2.2.

Задаёт для группы метод балансировки нагрузки, при котором запрос передаётся серверу с наименьшим числом активных соединений, с учётом весов серверов. Если подходит сразу несколько серверов, они выбираются циклически (в режиме round-robin) с учётом их весов.

Синтаксис: least_time header | last_byte;
Умолчание:
Контекст: upstream

Эта директива появилась в версии 1.7.10.

Задаёт для группы метод балансировки нагрузки, при котором запрос передаётся серверу с наименьшими средним временем ответа и числом активных соединений с учётом весов серверов. Если подходит сразу несколько серверов, то они выбираются циклически (в режиме round-robin) с учётом их весов.

Если указан параметр header, то учитывается время получения заголовка ответа. Если указан параметр last_byte, то учитывается время получения всего ответа.

Эта директива доступна как часть коммерческой подписки.

Синтаксис: health_check [параметры];
Умолчание:
Контекст: location

Активирует периодические проверки работоспособности серверов в группе, указанной в содержащем location.

Могут быть заданы следующие необязательные параметры:

interval=время
задаёт интервал между двумя последовательными проверками, по умолчанию 5 секунд;
fails=число
задаёт число последовательных неуспешных проверок для определённого сервера, после которых сервер будет считаться неработоспособным, по умолчанию 1;
passes=число
задаёт число последовательных успешных проверок для определённого сервера, после которых сервер будет считаться работоспособным, по умолчанию 1;
uri=uri
задаёт URI, используемый в запросах, проверяющих работоспособность, по умолчанию “/”;
match=имя
указывает на блок match с условиями, которым должен удовлетворять ответ, чтобы результат проверки считался успешным; по умолчанию код ответа должен быть 2xx или 3xx;
port=число
задаёт порт, используемый при подключении к серверу для проверки его работоспособности (1.9.7); по умолчанию совпадает с портом сервера.

В примере

location / {
    proxy_pass http://backend;
    health_check;
}

каждому серверу группы backend с интервалом в 5 секунд посылаются запросы “/”. Если происходит ошибка или таймаут при работе с сервером, или код ответа проксируемого сервера не равен 2xx или 3xx, проверка считается неуспешной и сервер признаётся неработоспособным. На неработоспособные серверы клиентские запросы передаваться не будут.

Проверки работоспособности могут тестировать код ответа, наличие или отсутствие определённых полей заголовка и их значений, а также содержимое тела ответа. Тесты настраиваются отдельно при помощи директивы match и указываются в параметре match. Например:

http {
    server {
    ...
        location / {
            proxy_pass http://backend;
            health_check match=welcome;
        }
    }

    match welcome {
        status 200;
        header Content-Type = text/html;
        body ~ "Welcome to nginx!";
    }
}

В такой конфигурации успешный ответ на проверочный запрос должен иметь код 200, тип содержимого “text/html” и “Welcome to nginx!” в теле ответа.

Группа должна находиться в зоне разделяемой памяти.

Если для группы задано несколько проверок, то при любой неуспешной проверке соответствующий сервер будет считаться неработоспособным.

Обратите внимание, что при использовании проверок большинство переменных имеют пустые значения.

Эта директива доступна как часть коммерческой подписки.

Синтаксис: match имя { ... }
Умолчание:
Контекст: http

Задаёт именованный набор тестов для анализа ответов на запросы проверки работоспособности.

В ответе могут быть протестированы следующие объекты:

status 200;
код ответа равен 200
status ! 500;
код ответа не равен 500
status 200 204;
код ответа равен 200 или 204
status ! 301 302;
код ответа не равен ни 301, ни 302
status 200-399;
код ответа находится в диапазоне от 200 до 399
status ! 400-599;
код ответа находится вне диапазона от 400 до 599
status 301-303 307;
код ответа равен 301, 302, 303 или 307

header Content-Type = text/html;
заголовок содержит “Content-Type” со значением text/html
header Content-Type != text/html;
заголовок содержит “Content-Type” со значением, отличным от text/html
header Connection ~ close;
заголовок содержит “Connection” со значением, совпадающим с регулярным выражением close
header Connection !~ close;
заголовок содержит “Connection” со значением, не совпадающим с регулярным выражением close
header Host;
заголовок содержит “Host”
header ! X-Accel-Redirect;
заголовок не содержит “X-Accel-Redirect”

body ~ "Welcome to nginx!";
тело ответа совпадает с регулярным выражением “Welcome to nginx!
body !~ "Welcome to nginx!";
тело ответа не совпадает с регулярным выражением “Welcome to nginx!

Если задано несколько тестов, то ответ должен удовлетворять всем тестам.

Проверяются только первые 256 Кбайт тела ответа.

Примеры:

# код ответа 200, тип содержимого "text/html"
# и тело ответа содержит "Welcome to nginx!"
match welcome {
    status 200;
    header Content-Type = text/html;
    body ~ "Welcome to nginx!";
}

# код ответа не равен 301, 302, 303 и 307 и заголовок не содержит "Refresh:"
match not_redirect {
    status ! 301-303 307;
    header ! Refresh;
}

# код ответа успешный и сервер не в сервисном режиме
match server_ok {
    status 200-399;
    body !~ "maintenance mode";
}

Эта директива доступна как часть коммерческой подписки.

Синтаксис: queue число [timeout=время];
Умолчание:
Контекст: upstream

Эта директива появилась в версии 1.5.12.

Если при обработке запроса невозможно сразу выбрать сервер группы и в группе есть серверы, у которых число соединений достигло ограничения max_conns, запрос будет помещён в очередь. Директива задаёт максимальное число запросов, которые могут одновременно находиться в очереди. Если очередь переполнена или за время, задаваемое параметром timeout, так и не удастся выбрать сервер для передачи ему запроса, клиенту будет возвращена ошибка 502 (Bad Gateway).

По умолчанию параметр timeout равен 60 секундам.

Эта директива доступна как часть коммерческой подписки.

Синтаксис: sticky cookie имя [expires=время] [domain=домен] [httponly] [secure] [path=путь];
sticky route переменная ...;
sticky learn create=$переменная lookup=$переменная zone=имя:размер [timeout=время];
Умолчание:
Контекст: upstream

Эта директива появилась в версии 1.5.7.

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

При использовании метода cookie информация о назначенном сервере передаётся в HTTP-куке:

upstream backend {
    server backend1.example.com;
    server backend2.example.com;

    sticky cookie srv_id expires=1h domain=.example.com path=/;
}

Запрос от клиента, ещё не привязанного к определённому серверу, передаётся на сервер, выбранный согласно настроенному методу балансировки. Дальнейшие запросы от этого клиента передаются на тот же сервер. Если назначенный сервер не может обработать запрос, выбирается новый сервер как если бы клиент не имел привязки к серверу.

Первый параметр задаёт имя куки, которую необходимо установить или проверить. Дополнительные параметры могут быть следующими:

expires=время
Задаёт время, в течение которого браузеру необходимо хранить куку. Специальное значение max устанавливает срок хранения куки до 31 декабря 2037 года 23:55:55 GMT. Если параметр не указан, то время действия куки ограничивается сессией браузера.
domain=домен
Задаёт домен, для которого устанавливается кука.
httponly
Добавляет атрибут HttpOnly к куке (1.7.11).
secure
Добавляет атрибут Secure к куке (1.7.11).
path=путь
Задаёт путь, для которого устанавливается кука.

Если пропущен тот или иной параметр, то соответствующего поля в куке не будет.

route

При использовании метода route проксируемый сервер назначает клиенту маршрут по получении первого запроса. Все последующие запросы от этого клиента будут содержать информацию о маршруте в куке или URI. Эта информация сравнивается с параметром “route” директивы server для идентификации сервера, на который следует проксировать запрос. Если назначенный сервер не может обработать запрос, выбирается новый сервер согласно настроенному методу балансировки как если бы в запросе не было информации о маршруте.

Параметры метода route задают переменные, которые могут содержать информацию о маршруте. Первая непустая переменная используется для поиска соответствующего сервера.

Пример:

map $cookie_jsessionid $route_cookie {
    ~.+\.(?P<route>\w+)$ $route;
}

map $request_uri $route_uri {
    ~jsessionid=.+\.(?P<route>\w+)$ $route;
}

upstream backend {
    server backend1.example.com route=a;
    server backend2.example.com route=b;

    sticky route $route_cookie $route_uri;
}

В этом примере маршрут берётся из куки “JSESSIONID”, если она присутствует в запросе. В противном случае используется маршрут из URI.

learn

При использовании метода learn (1.7.1) nginx анализирует ответы от вышестоящего сервера и запоминает начатые им сессии, которые обычно передаются в HTTP-куке.

upstream backend {
   server backend1.example.com:8080;
   server backend2.example.com:8081;

   sticky learn
          create=$upstream_cookie_examplecookie
          lookup=$cookie_examplecookie
          zone=client_sessions:1m;
}

В примере выше сервер группы создаёт сессию путём установки куки “EXAMPLECOOKIE” в своём ответе. Последующие запросы с этой кукой будут передаваться на этот же сервер. Если сервер не может обработать запрос, выбирается новый сервер как если бы клиент не имел привязки к серверу.

Параметры create и lookup задают переменные, в которых соответственно указывается способ создания новых и поиска существующих сессий. Оба параметра могут быть указаны больше одного раза (в этом случае используется первая непустая переменная).

Сессии хранятся в зоне разделяемой памяти, имя и размер которой задаются параметром zone. Зоны размером в 1 мегабайт достаточно для хранения около 8 тысяч сессий на 64-битной платформе. Сессии, к которым не было обращений в течение времени, заданного параметром timeout, удаляются из зоны. По умолчанию timeout равен 10 минутам.

Эта директива доступна как часть коммерческой подписки.

Синтаксис: sticky_cookie_insert имя [expires=время] [domain=домен] [path=путь];
Умолчание:
Контекст: upstream

Эта директива устарела начиная с версии 1.5.7. Вместо неё следует использовать аналогичную директиву sticky с изменённым синтаксисом:

sticky cookie имя [expires=время] [domain=домен] [path=путь];

Встроенные переменные

Модуль ngx_http_upstream_module поддерживает следующие встроенные переменные:

$upstream_addr
хранит IP-адрес и порт или путь к UNIX-сокету сервера группы. Если при обработке запроса были сделаны обращения к нескольким серверам, то их адреса разделяются запятой, например, “192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock”. Если произошло внутреннее перенаправление от одной группы серверов на другую с помощью “X-Accel-Redirect” или error_page, то адреса, соответствующие разным группам серверов, разделяются двоеточием, например, “192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock : 192.168.10.1:80, 192.168.10.2:80”.
$upstream_cache_status
хранит статус доступа к кэшу ответов (0.8.3). Статус может быть одним из “MISS”, “BYPASS”, “EXPIRED”, “STALE”, “UPDATING”, “REVALIDATED” или “HIT”.
$upstream_connect_time
хранит время, затраченное на установление соединения с сервером группы (1.9.1); время хранится в секундах с точностью до миллисекунд. В случае SSL, включает в себя время, потраченное на handshake. Времена нескольких соединений разделяются запятыми и двоеточиями подобно адресам в переменной $upstream_addr.
кука с указанным именем, переданная сервером группы в поле “Set-Cookie” заголовка ответа (1.7.1). Необходимо иметь в виду, что куки запоминаются только из ответа последнего сервера.
$upstream_header_time
хранит время, затраченное на получение заголовка ответа от сервера группы (1.7.10); время хранится в секундах с точностью до миллисекунд. Времена нескольких ответов разделяются запятыми и двоеточиями подобно адресам в переменной $upstream_addr.
$upstream_http_имя
хранят поля заголовка ответа сервера. Например, поле заголовка ответа “Server” доступно в переменной $upstream_http_server. Правила преобразования имён полей заголовка ответа в имена переменных такие же, как для переменных с префиксом “$http_”. Необходимо иметь в виду, что поля заголовка запоминаются только из ответа последнего сервера.
$upstream_response_length
хранит длину ответа, полученного от сервера группы (0.7.27); длина хранится в байтах. Длины нескольких ответов разделяются запятыми и двоеточиями подобно адресам в переменной $upstream_addr.
$upstream_response_time
хранит время, затраченное на получение ответа от сервера группы; время хранится в секундах с точностью до миллисекунд. Времена нескольких ответов разделяются запятыми и двоеточиями подобно адресам в переменной $upstream_addr.
$upstream_status
хранит статус ответа, полученного от сервера группы. Статусы нескольких ответов разделяются запятыми и двоеточиями подобно адресам в переменной $upstream_addr.