Глава 3. Управление обменом

Введение

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

Тестирование A/B

Задача

Вам требуется расщеплять клиентов между двумя или более версиями некого файла или приложения для проверки приемлемости.

Решение

Воспользуйтесь модулем split_clients для предписания процентного соотношения вашим клиентам на различные восходящие пулы:


split_clients "${remote_addr}AAA" $variant {
    20.0% "backendv2";
    * "backendv1";
}
 	   

Эта директива split_clients хэширует значение передаваемого вами первым параметром строки и проводит деление этого хэша в заданном процентном соотношении для установления соответствия со значением второго параметра. Значением третьего параметра является некий содержащий пару ключ- значение объект, в котором ключ выступает процентным весом, а его значение это назначаемое значение. Значением ключа может быть либо процентное соотношение, либо сивмол звёздочки. Передаваемая звёздочка означает что передаётся вся остающаяся после всех процентных соотношений часть. Задаваемым значением для нашей переменной $variant будет backendv2 для 20% адресов клиентов, а для остающихся 80% остаётся backendv1.

В нашем примере backendv1 и backendv2 представляют пулы серверов восходящего потока и могут применяться с директивой proxy_pass, подобной следующей:


location / {
    proxy_pass http://$variant
}
 	   

При помощи переменной $variant наш обмен будет расщепляться на два различных пула серверов.

Обсуждение

Данный вид проверки A/B полезен при тестировании различных видов свойств торговли и интерфейса для пересмотра соотношений в сайтах электронной коммерции. Для прикладных задач распространено применение типа разработки с названием канареечного выпуска. При таком типе разработки обмен слегка отключается для данной новой версии. Расщепление ваших клиентов между различными версиями вашего приложения может оказаться полезным при раскрутке новой версии кода для для ограничения радиуса поражения в случае некой ошибки. Всякий раз когда возникает причина для разделения клиентов между двумя различными наборами приложений NGINX запросто делает это при помощи рассмотренного модуля split_clients.

Также ознакомьтесь

split_client Documentation

Применение модуля GeoIP и базы данных

Задача

Вам требуется установить базу данных GeoIP и разрешить её встроенные переменные внутри NGINX для регистрации и определения в вашем приложении значения местоположения ваших клиентов.

Решение

Официальный репозиторий пакета Открытого исходного кода NGINX, который вы настраивали при установке NGINX в Главе 1, предоставляет пакет с названием nginx-module-geoip. При применении репозитория пакетов NGINX Plus, такой пакет именуется nginx-plus-module-geoip. Эти пактеы устанавливают имеющуюся динамическую версию модуля GeoIP.

Открытый исходный код NGINX RHEL/ CentOS:


# yum install nginx-module-geoip
		

Открытый исходный код NGINX Debian/ Ubuntu:


# apt-get install nginx-module-geoip
		

Открытый исходный код NGINX Plus RHEL/ CentOS:


# yum install nginx-plus-module-geoip
		

Открытый исходный код NGINX Plus Debian/ Ubuntu:


# apt-get install nginx-plus-module-geoip
		

Выгрузите базу данных стран и городов GeoIP и разархивируйте её:


# mkdir /etc/nginx/geoip
# cd /etc/nginx/geoip
# wget "http://geolite.maxmind.com/\
download/geoip/database/GeoLiteCountry/GeoIP.dat.gz"
# gunzip GeoIP.dat.gz
# wget "http://geolite.maxmind.com/\
download/geoip/database/GeoLiteCity.dat.gz"
# gunzip GeoLiteCity.dat.gz
		

Этот набор команд создаёт некий каталог geoip в уже имеющемся каталоге /etc/nginx, переходит в этот новый каталог, а таже выгружает необходимые пакеты и выполняет их разархивацию.

Имея на своём локальном диске базу данных GeoIP для стран и городов вы теперь можете выдать инструкции для модуля GeoIP NGINX на её применение для выставления встроенных переменных на основе получаемого адреса IP клиента:


load_module "/usr/lib64/nginx/modules/ngx_http_geoip_module.so";

http {
    geoip_country /etc/nginx/geoip/GeoIP.dat;
    geoip_city /etc/nginx/geoip/GeoLiteCity.dat;
...
}
 	   

Указанная директива load_module динамически загружает передаваемый ей модуль из пути вашей файловой системы. Данная директива load_module допустима только в основном контексте. Следующая директива geoip_country получает некий путь к файлу GeoIP.dat, который содержит значения соответствий IP адресов базы данных кодам стран и допустима лишь в контексте обозначенного HTTP.

Обсуждение

Рассматриваемые директивы geoip_country и geoip_city выставляют ряд доступных в этом модуле встроенных переменных. Первая директива geoip_country включает переменные, которые позволяют вам отличать значение страны происхождения вашего клиента. Эти переменные содержат в своём составе $geoip_country_code, $geoip_country_code3 и $geoip_country_name. Первая переменная кода страны возвращает значение двухбуквенного кода страны, а переменная с 3 в конце возвращает значение трёхбуквенного кода страны. Переменная названия страны возвращает полное название страны.

Директива geoip_city возвращает приличное число переменных. Эта директива geoip_city возвращает аналогичные директиве $geoip_country переменные со слегка иными названиями, такие как $geoip_city_country_code, $geoip_city_country_code3 и $geoip_city_country_name. Прочие переменные включают в свой состав $geoip_city, $geoip_city_continent_code, $geoip_latitude, $geoip_longitude и $geoip_postal_code, которые имеют достаточно описательные названия для возвращаемых ими значений. $geoip_region и $geoip_region_name описывают значения региона, территории, штата, провинции, федеральной земли и им подобное. Регион является двухбуквенным кодом, в то время как назавние региона представляет его полное название. $geoip_area_code, которая допустима лишь в пределах US, возвращает значение из трёх цифр для телефонного кода области.

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

Также ознакомьтесь

GeoIP Update

Ограничение доступа на основе страны

Задача

Вам требуется ограничить доступ для определённых стран в соответствии с требованиями контрактов или приложения.

Решение

Установите соответствие тем странам, которые вы намерены блокировать:


load_module
  "/usr/lib64/nginx/modules/ngx_http_geoip_module.so";
http {
    map $geoip_country_code $country_access {
        "US" 0;
        "RU" 0;
        default 1;
    }
    ...
}
 	   

Это соответствие устанавливает некую переменную $country_access в значение 1 или 0. Если полученный IP адрес имеет местом происходжения США или Россию, значение переменной будет установлено в 0. Для всех прочих стран значение этой переменной устанавливается равным 1.

Теперь внутри своего блока server мы будем применять оператор if для запрета всем тем, кто имеет местом происхождения США или Россию:


server {
    if ($country_access = '1') {
      return 403;
    }
    ...
}
 	   

Данный оператор if будет вычислять True когда значение переменной $country_access установлено в 1. В случае True наш сервер будет возвращать 403 без авторизации. В противном случае все операции нашего сервера будут обычными. Тем самым данный блок if присутствует только для запрета тех людей, которые происходят из США или России.

Обсуждение

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

Поиск первичного клиента

Задача

Вам требуется выяснить IP адрес первоначального клиента, поскольку перед самим сервером NGINX имеется ряд посредников (прокси).

Решение

Воспользуйтесь директивой geoip_proxy для выявления диапазона IP адреса вашего посредника и соответствующей директивой geoip_proxy_recursive для поиска значения первоначального IP:


load_module "/usr/lib64/nginx/modules/ngx_http_geoip_module.so";
  
http {
    geoip_country /etc/nginx/geoip/GeoIP.dat;
    geoip_city /etc/nginx/geoip/GeoLiteCity.dat;
    geoip_proxy 10.0.16.0/26;
    geoip_proxy_recursive on;
...
}
 	   

Директива geoip_proxy определяет некий диапазон CIDR, в котором обитают наши серверы посредников и указывают NGINX на необходимость применять для поиска требуемых адресов своего клиента заголовка X-Forwarded-For. Последняя директива geoip_proxy_recursive иструктирует NGINX о необходимости рекурсивного поиска через все заголовки X-Forwarded-For на предмет самого последнего известного IP клиента.

Обсуждение

Вы можете обнаружить, что когда вы применяете перед NGINX некого посредника (прокси), NGINX будет подхватывать вместо IP адреса такого клиента адрес применяемого посредника. По этой причине вы можете применять директиву geoip_proxy для того чтобы указывать NGINX на применение имеющегося заголовка X-Forwarded-For когда подключения открываются из заданного диапазона. Эта директива geoip_proxy принимает некий адрес либо диапазон CIDR. Когда перед NGINX присутствует множество передающих обмен посредников, вы можете применять для рекурсивного поиска через адреса X-Forwarded-For необходимого клиента директиву geoip_proxy_recursive. Вы можете пожелать применять нечто подобное этому при использовании перед NGINX такого балансировщика нагрузки, как AWS ELB, балансировщик нагрузки Google или Azure.

Ограничение подключений

Задача

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

Решение

Для удержания замеров подключений постройте некую зону совместной памяти и воспользуйтесь директивой limit_conn для ограничения открытых подключений:


http {
    limit_conn_zone $binary_remote_addr zone=limitbyaddr:10m;
    limit_conn_status 429;
    ...
    server {
        ...
        limit_conn limitbyaddr 40;
        ...
    }
}
 	   

Эта конфигурация создаёт некую зону совместной памяти с названием limitbyaddr. Применяемым предварительно определённым ключом является значение IP адреса клиента в двичной форме. Величина размера зоны совместной памяти установлена в значение 10 Мегабайт. Последняя директива limit_conn получает два параметра: некое название limit_conn_zone и общее число допускаемых подключений. Параметр limit_conn_status устанавливает значение отклика при достижении предела имеющихся подключений в состояние 429, что указывает на слишком большое число подключений. Обсуждаемые директивы limit_conn и limit_conn_status допустимы в соотвествующих контекстах HTTP, сервера и местоположения.

Обсуждение

Ограничение общего числа подключений основывается на неком ключе, который может применяться для определения злоупотреблений и разделения ваших ресурсов справедливым образом по всем вашим клиентам. Важно быть осмотрительным в выборе вашего предварительно заданного ключа. Может быть опасным применение некого IP адреса, как мы это длали в своём предыдущем примере, когда многие пользователи применяют одну и ту же сетевую среду, которая происходит из одного и того же IP, например когда они расположены за Network Address Translation (NAT). Мы способны ограничить определённую группу клиентов целиком. Директива limit_conn_zone допустима лишь в соответствующем контексте HTTP. Вы можете применять любое число доступных NGINX переменных внутри своего контекста HTTP для определения конкретного пользователя на уровне своего приложения , например куки сеанса, может быть более чётким решением в зависимости от варианта применения. Значением по умолчанию для limit_conn_status является 503, то есть данная служба недоступна, а отклик уровня 500 указывает на ошибку сервера, в то время как отклики уровня 400 указывают на ошибку клиента.

Ограничение скорости

Задача

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

Решение

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


http {
    limit_req_zone $binary_remote_addr
        zone=limitbyaddr:10m rate=1r/s;
    limit_req_status 429;
    ...
    server {
        ...
        limit_req zone=limitbyaddr burst=10 nodelay;
        ...
    }
}
 	   

Данный пример настройки создаёт некую зону совместной памяти с названием limitbyaddr. Применяемым значением заранее определённого ключа является значение IP адреса клиента в двоичном виде. Величина размера совместной зоны памяти установлена в 10 Мегабайт. Данная зона устанавливает значение скорости при помощи некого аргумента ключевого слова. Приведённая директива limit_req получает два необязательных аргумента с ключевым словом: zone и burst. zone требуется для указания данной директиве какую именно применять зону предела запросов совместной памяти. Когда исчерпана скорость запросов для данной зоны, запросы откладываются пока не будет достигнуто их максимальный размер burst, обозначенный в аргументе ключевого слова burst. Значением по умолчанию для ключевого слова burst является ноль. limit_req также получает некий третий необязательный параметр с ключевым словом nodelay. Этот параметр позволяет конкретному клиенту применять его burst без задержки прежде чем получить ограничение. limit_req_status устанавливает значение состояния, возвращаемого определённому клиенту неким индивидуальным кодом состояния HTTP; по умолчанию он равен 503. limit_req_status и limit_req допустимы в контексте HTTP, сервера и местоположения. limit_req_zone допустим лишь в контексте HTTP. В NGINX Plus ограничение скорости осведомлено о кластере, что является новинкой в R16.

Обсуждение

Обсуждаемый модуль ограничения скорости является очень мощным для защиты против злоупотребления частотой запросов и в то же самое время предоставляет всем некий уровень качества услуг. Имеется множество причин для ограничения скорости запросов, причём одной из них является безопасность. Вы можете препятствовать силовым атакам помещая на свою страницу регистрации очень строгое ограничение. Вы можете установить некий санитарный предел для всех запросов, тем самым запрещая соответствующие планы злонамерненным пользователям, которые могут пытаться запретить обслуживание вашего приложения или впустую тратить ваши ресурсы. Настройка модуля ограничения скорости во многом аналогична предыдущему описанному в рецепте модуле ограничения подключений. Вы можете определить значение скорости в их числе в секунду или в минуту, которой ограничены запросы в обращениях. При достижении установленного предела скорости это происшествие регистрируется. Также имеется отсутствующая в нашем примере директива limit_req_log_level, которая по умолчанию установлена в значение error, но также может быть установлена в info, notice или warn. Что является новым в NGINX Plus с версии R16, так это то, что ограничение скорости теперь осведомлено о кластере (обратитесь к соответствующему рецепту за получением примера синхронизации зон).

Ограничение полосы пропускания

Задача

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

Решение

Для ограничения частоты откликов к клиенту воспользуйтесь директивами limit_rate и limit_rate_after:


location /download/ {
    limit_rate_after 10m;
    limit_rate 1m;
}
 	   

Приведённые настройки данного блока местоположения определяет что для URI со значением префикса download значение частоты с которой этот отклик будет обслуживаться для данного клиента будет ограничено после 10 Мегабайт до скорости 1 Мегабайт в секунду. Значение предела полосы пропускания устанавливается для каждого подключения, а следовательно вы можете пожелать установить некий предел подключений а также какой- то предел полосы пропускания, где это приемлемо.

Обсуждение

Ограничивая значение полосы пропускания для определённых подключений позволяет NGINX разделять его полосу пропускания по всем своим клиентам тем образом как вы его определяете. Всё это делают две директивы: limit_rate и limit_rate_after. Первая директива limit_rate_after может быть установлена практически во всех контекстах: HTTP, сервера, местоположения и if когда if расположен внутри местоположения. Следующая директива limit_rate применяется в тех же самых контекстах, что и limit_rate_after; тем не менее она может быть альтернативно настроена установкой некой переменной с именем $limit_rate. Эта директива limit_rate_after указывает что данное подключение не должно быть ограничено в скорости до тех пока не будет передан определённый объём данных. Данная директива limit_rate определяет значение ограничения скорости для данного контекста по умолчанию в байтах в секунду. Однако вы можете определять m для Мегабайт или g для Гигабайт. Обе директивы имеют по умолчанию значение 0. Значение величины 0 подразумевает что предела для скоростей выгрузки нет вовсе. Данный модуль позволяет вам программируемым образом изменять значение ограничения скорости клиентов.