Re: переменный limit req zone с приоритетами

Валентин Бартенев vbart at nginx.com
Thu Apr 10 22:04:24 UTC 2014


On Thursday 10 April 2014 16:55:00 cat wrote:
> Приветствую. Развивая эту недавнюю тему
> http://forum.nginx.org/read.php?21,237662  хочу немного доработать логику. 
> Вместо раздачи каждому пользователю определённого ограничения сделать общее
> ограничение и раздать пользователям приоритеты. Итак:
> 
> Пусть есть простой запрос:
> 
> http://127.0.0.1/api?username=testuser
> 
> Допустим, сервер способен выдержать не более 1000 соединений в секунду,
> остальные будут отбиваться.
> Эти самые 1000 разрешенных соединений распределяются между обычными
> пользователи и несколькими "избранными" с учётом приоритета. Т.е. если
> пользователь с высоким приоритетом занял всё ограничение - остальные ничего
> не получат. Как только он перестал слать запросы или уменьшил скорость
> соединений, освободившееся место занял мользователь с приоритетом меньше.
> 
> Вот примерный конфиг как это (теоретически) должно было работать:
> 
> ####################################
> map $arg_username $is_default {
>     default 1;
>     bob "";
>     alice "";
> }
> 
> map $arg_username $is_bob {bob 1;}
> map $arg_username $is_alice {alice 1;}
> 
> # у всех пользователей одинаковый (как бы 'глобальный') rate=1000r/s
> limit_req_zone $is_bob zone=user_bob:32k rate=1000r/s;
> limit_req_zone $is_alice zone=user_alice:32k rate=1000r/s;
> limit_req_zone $is_default zone=default_limit:32k rate=1000r/s;
> 
> 
> # пользователь 'bob' с наивысшим приоритетом - вытесняет 'alice' и всех
> остальных
> # (поднимает флаг для всех зон "забирая" у них соединения)
> if ($is_bob = 1){
>     set $is_alice 1;
>     set $is_default 1;
> }
> # пользователь 'alice' с меньшим приоритетом - вытесняет только всех
> остальных
> # (поднимает флаг для всех зон кроме user_bob т.к. приоритет у alice ниже)
> if ($is_alice = 1){
>     set $is_default 1;
> }
> 
> location = /test {
>   limit_req zone=user_bob;
>   limit_req zone=user_alice;
>   limit_req zone=default_limit;
>   ...
> 
> }
> ##########
> 
> Под нагрузкой получается что-то похожее на одну [limit_req_zone
> rate=1000r/s] для всех. Я вижу в отбитых соединениях и bob и alice, хотя
> суммарная скорость соединений всех пользователей чуть более 1000 в секунду,
> а суммарная скорость bob и alice 500 соединений в секунду, т.е.
> блокироваться они не должны.
> 

Так работать разумеется не будет.

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

Но это не самая большая проблема.

Вы пишете: "пользователь 'bob' с наивысшим приоритетом - вытесняет
'alice' и всех остальных (поднимает флаг для всех зон "забирая" у
них соединения)".

Это не так, подняв флаг у всех - означает, что он будет проверен
на ограничение по всем зонам, т.е. эффект достигается ровно обратный.

В таком виде, как вы сформулировали, задача модулем limit_req не
решается в принципе, поскольку модуль в настоящий момент не умеет
увеличивать счетчик без проверки при этом на лимит.

--
Валентин Бартенев


Подробная информация о списке рассылки nginx-ru