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