limit conn счетчик переполнение

2015-04-17 Пенетрантность dwow
Добрый день.

Была задача ограничить кол-во запросов к бэкенду. Например, чтобы
одновременно не поступало более 1 запроса. Остальные запросы, пока работает
бэкенд, могли отваливаться по ошибке, это не страшно.
С помощью Perl я устанавливал переменную, которая показывала идет ли запрос
для проксирования на бэкенд или нет. И эту переменную использовал в качестве
ключа для
http://nginx.org/ru/docs/http/ngx_http_limit_conn_module.html#limit_conn_zone

perl_set $service_hit '
sub {
my $r = shift;
if($r-uri =~ m|^/services/post|){
return services;
} else {
return ;
}
}
';
limit_conn_zone $service_hit zone=perservice:10m;

Потом перед проксированием на бэкенд (в location) использовал ограничениие
http://nginx.org/ru/docs/http/ngx_http_limit_conn_module.html#limit_conn

limit_conn perservice 1;

Все отлично работает, но только первые 30-60 минут, потом nginx для всех
запросов возвращает 503 ошибку, т.е. счетчик не сбрасывается. Если
остановить-запустить nginx, то опять какое-то время все работает корректно.
В чем может быть проблема?

Спасибо.

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?21,258140,258140#msg-258140

___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Re: limit conn счетчик переполнение

2015-04-17 Пенетрантность Maxim Dounin
Hello!

On Fri, Apr 17, 2015 at 06:06:49AM -0400, dwow wrote:

 Добрый день.
 
 Была задача ограничить кол-во запросов к бэкенду. Например, чтобы
 одновременно не поступало более 1 запроса. Остальные запросы, пока работает
 бэкенд, могли отваливаться по ошибке, это не страшно.
 С помощью Perl я устанавливал переменную, которая показывала идет ли запрос
 для проксирования на бэкенд или нет. И эту переменную использовал в качестве
 ключа для
 http://nginx.org/ru/docs/http/ngx_http_limit_conn_module.html#limit_conn_zone
 
 perl_set $service_hit '
 sub {
 my $r = shift;
 if($r-uri =~ m|^/services/post|){
 return services;
 } else {
 return ;
 }
 }
 ';
 limit_conn_zone $service_hit zone=perservice:10m;

Just a side note: не надо делать так, вместо этого правильно 
написать отдельный location, в котором и задать ограничение.

 Потом перед проксированием на бэкенд (в location) использовал ограничениие
 http://nginx.org/ru/docs/http/ngx_http_limit_conn_module.html#limit_conn
 
 limit_conn perservice 1;
 
 Все отлично работает, но только первые 30-60 минут, потом nginx для всех
 запросов возвращает 503 ошибку, т.е. счетчик не сбрасывается. Если
 остановить-запустить nginx, то опять какое-то время все работает корректно.
 В чем может быть проблема?

Скорее всего проблема в том, что limit_conn органичивает не 
соединения на бекенду, а активные соединения.  Соответственно, 
если кто-то сходил на бекенд, получил оттуда достаточно большой 
ответ и неспеша забирает его у nginx'а - ограничение будет 
продолжать срабатывать.  Например, если клиент сделал запрос 
(ответ на который не помещается в буфер сокета), после чего пропал 
и на пакеты не отвечает - ограничение будет срабатывать, пока не 
случится send_timeout.

-- 
Maxim Dounin
http://nginx.org/

___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Re: limit conn счетчик переполнение

2015-04-17 Пенетрантность Maxim Dounin
Hello!

On Fri, Apr 17, 2015 at 09:15:21AM -0400, dwow wrote:

 Maxim Dounin Wrote:
 ---
  
  Just a side note: не надо делать так, вместо этого правильно 
  написать отдельный location, в котором и задать ограничение.
 
 вот это я не понял.
 
 у меня так
 location /services/post/ {
limit_conn perservice 1;
proxy_pass bakcend;
 }

Тогда зачем у вас используется perl_set?

Если limit_conn в других location'ах не включён, то для 
ограничения всех соединений в конкретном location'е - достаточно 
любого константного значения.

  Скорее всего проблема в том, что limit_conn органичивает не 
  соединения на бекенду, а активные соединения.  Соответственно, 
  если кто-то сходил на бекенд, получил оттуда достаточно большой 
  ответ и неспеша забирает его у nginx'а - ограничение будет 
  продолжать срабатывать.  Например, если клиент сделал запрос 
  (ответ на который не помещается в буфер сокета), после чего пропал 
  и на пакеты не отвечает - ограничение будет срабатывать, пока не 
  случится send_timeout.
 
 Ага, и тогда через  send_timeout (default: 60s), счетчик должен
 декрементироваться и следующий запрос пойти на бекенд, так? Но этого не
 происходит(

Если send_timeout случится - то да.  Если же вдруг какой-то клиент 
очерь медленно качает что-то большое - то процесс может занять 
бесконечное время.

Ну и да, безусловно имеет смысл заглянуть в error log, и убедится, 
что рабочие процессы не завершаются аварийно.

-- 
Maxim Dounin
http://nginx.org/

___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Re: limit conn счетчик переполнение

2015-04-17 Пенетрантность Gena Makhomed

On 17.04.2015 19:28, dwow wrote:

 Была задача ограничить кол-во запросов к бэкенду.
 Например, чтобы одновременно не поступало более 1 запроса.


Если же вдруг какой-то клиент очерь медленно качает
что-то большое - то процесс может занять бесконечное время.



и как от таких избавляться?


1) купить платную версию NGINX Plus, там есть max_conns=number
http://nginx.org/en/docs/http/ngx_http_upstream_module.html

2) поставить между клиентом [или nginx] и бэкендом
haproxy - haproxy умеет это делать прямо из коробки:
https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#5.2-maxconn

--
Best regards,
 Gena

___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Re: limit conn счетчик переполнение

2015-04-17 Пенетрантность Maxim Dounin
Hello!

On Fri, Apr 17, 2015 at 12:28:03PM -0400, dwow wrote:

 Maxim Dounin Wrote:
 ---
  Если limit_conn в других location'ах не включён, то для 
  ограничения всех соединений в конкретном location'е - достаточно 
  любого константного значения.
 
 Если не используется в др. локейшенах, то можно сделать вот так:
 limit_conn_zone service zone=perservice:10m;
 location /services/post/ {
limit_conn perservice 1;
proxy_pass bakcend;
 }
 
 и будет работать?

Да.  В старых версиях (до nginx 1.7.6), возможно, потребуется 
какая-нибудь константная переменная (например, $nginx_version), а 
не просто строка.

  Если send_timeout случится - то да.  Если же вдруг какой-то клиент 
  очерь медленно качает что-то большое - то процесс может занять 
  бесконечное время.
 и как от таких избавляться? 

В общем случае - никак, это обычные клиенты, которые просто 
получают ответ.  Собственно, как раз одно из преимуществ nginx'а 
состоит в том, что он умеет таких клиентов эффективно 
обслуживать, тратя на это минимум ресурсов.  Ну и ограничивать с 
помощью директивы limit_conn, не давая захватить слишком много 
ресурсов сервера.

В вашем случае - проблема в том, что вы пытаетесь limit_conn 
применить не по назначению, и такое использование приводит к тому, 
что один медленный пользователь может легко заблокировать доступ 
всем остальным.

-- 
Maxim Dounin
http://nginx.org/

___
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru