Pull to refresh

Comments 9

где-бы ещё взять столько времени чтобы каждую библиотеку оценить…
Помню, в реальном проекте (не на основе вашей библиотеки) была задача ограничить количество соединений, но не всего, а от каждого ip адреса.

Это я к тому, что довольно странно выглядит попытка реализация функциональности, которая никому не нужна. Ну ок, ладно, реализовали. Будет ли возможно расширить эту функциональность на реальные потребности, например на описанное выше?

В какой-то момент увлечение шаблонами переходит все пределы

На данный момент у нас есть возможность сделать собственный блокировщих подключений по IP-адресу. Который как раз появился в результате обсуждений в комментариях к какой-то предыдущей статье про RESTinio. Возможно, даже вы впервые об этом заговорили, я уже и не помню. Из коробки готового блокировщика, которому можно было бы сказать "максимум 5 подключений с одного IP" пока нет. Это как раз в дальнейших планах.


Это я к тому, что довольно странно выглядит попытка реализация функциональности, которая никому не нужна. Ну ок, ладно, реализовали.

Она не то, чтобы никому не нужна. Насколько я могу судить, пока RESTinio в основном используется для реализации микросервисов, когда все компоненты находятся внутри защищенной подсети и снаружи на них никак не воздействуют. В таких условиях на какой-то RESTinio-сервер 100500 подключений может прийти разве что из-за ошибки в каком-то из компонентов.


Но сама эта фича была подсмотрена в других разработках. И, на мой лично взгляд, она кажется важной для случаев, когда RESTinio-сервер будет смотреть прямо в Интернет. И когда на него реально может прийти 100500 подключений со 100500 разных IP.

И когда на него реально может прийти 100500 подключений со 100500 разных IP

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

Так пока вроде все логично развивается:


  • возникает вопрос "А как ограничить количество подключений с одного IP?"
  • мы понимаем, что пока никак;
  • спустя время мы делаем возможность ограничить количество подключений с одного IP;
  • возникает вопрос "А как ограничить общее количество подключений?"
  • мы понимаем, что пока никак;
  • спустя время мы делаем возможность ограничить общее количество подключений.

Возникнет следующий вопрос — будем смотреть на местности что к чему. Удобство же можно оценивать только по отношению к тому, что есть. Не так ли?

А как это все например конфигурировать? Вот у меня например есть конфиг, в котором указано, ограничивать или нет общее количество запросов, ограничивать или нет количество запросов на каждый ip. Как это в коде выразить?

Самый простой вариант.


Для ограничения общего количества подключений. В свойствах жестко задаете use_connection_count_limiter=true. Если в конфиге задано не ограничивать общее число подключений то либо не вызываете max_parallel_connections для settings, либо вызываете max_parallel_connections с заведомо большим значением (например, std::numeric_limits<std::size_t>::max()). Если в конфиге задано ограничивать общее количество, то вызываете max_parallel_connections с заданным в конфиге значением.


Для ограничения числа подключений с одного IP. Делаете свой IP-blocker (по типу вот такого) и указываете его тип в traits для сервера. При создании IP-blocker-а задаете в нем ограничение из конфига (опять же std::numeric_limits<std::size_t>::max() можно использовать для случая, когда ограничения нет).


Либо для IP-blocker-а можете описать у себя базовый тип:


class abstract_ip_blocker {
public:
   virtual ~abstract_ip_blocker();

   virtual restinio::ip_blocker::inspection_result_t
   inspect(const restinio::ip_blocker::incoming_info_t & info ) noexcept = 0;

   virtual void
   state_changed(const restinio::connection_state::notice_t & notice) = 0;
};

В traits сервера в качестве ip_blocker_t задаете abstract_ip_blocker.


Делаете два наследника: noop_ip_blocker_t для случая, когда ограничивать запросы с одного IP не нужно, и actual_ip_blocker_t для случая, когда ограничивать запросы нужно. При создании сервера в зависимости от настроек в конфиге создаете либо экземпляр noop_ip_blocker_t, либо экземпляр actual_ip_blocker_t.


Если же идти сложным путем, то потребуется несколько разных типов traits:


struct no_limits_traits : public restinio::default_traits_t {};

struct total_connections_limit_only_traits : public restinio::default_traits_t {
   static constexpr bool use_connection_count_limiter = true;
};

struct ip_blocker_only_traits : public restinio::default_traits_t {
   using ip_blocker_t = some_my_actual_ip_blocker_type;
};

struct all_limits_traits : public restinio::default_traits_t {
   static constexpr bool use_connection_count_limiter = true;
   using ip_blocker_t = some_my_actual_ip_blocker_type;
};

И в программе, в зависимости от того, что задано в конфиге, создаете сервер на базе разных traits.

Ну вот это все выглядит как-то сложновато, вот я о чем

Так это обратная сторона гибкости.


Если нам плевать на мелкие расходы, мы можем пойти по обычному ОО-пути, т.е. абстрактный базовый тип abstract_ip_blocker_t, от него наследники, которые делают то, что нужно.


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


RESTinio позволяет идти любым из этих путей.


И это касается не только ip_blocker-а. С логированием такая же ситуация.

Sign up to leave a comment.

Articles