Как отклонить запрос от клиента с помощью конфигурации Jetty в kairosdb
Я использую последнюю версию kairosdb. Я попытался включить пул потоков. Я ожидал, что если размер очереди будет заполнен запросом, то все последующие запросы будут немедленно отклонены. Но запрос обслуживается через некоторое время, хотя я вижу
java.util.concurrent.RejectedExecutionException
Запрос клиента должен быть отклонен, если очередь заполнена. Как добиться того же?
Для тестирования я добавил эти параметры.
kairosdb.jetty.threads.queue_size=2 #queue
kairosdb.jetty.threads.min=2 # minThread
kairosdb.jetty.threads.max=4 #maxThread
kairosdb.jetty.threads.keep_alive_ms=1000
Соответствующий код пула потоков причала
new ExecutorThreadPool(minThreads, maxThreads, keepAliveMs, TimeUnit.MILLISECONDS, queue);
Версия причала, используемая в kairosdb, 8.1.16
1 ответ
Пристань 8.1.16
был выпущен в сентябре 2014 года, теперь это EOL (End of Life), подумайте об использовании версии Jetty, которая является актуальной, стабильной и поддерживаемой. (например, пристань 9.4.12.20180830
)
Тот факт, что вы получаете java.util.concurrent.RejectedExecutionException
кричит, что у вас недостаточно конфигурации пула потоков.
Конфигурация вашего пула потоков крайне мала.
Это подходит только для конфигурации с одним ядром, одним процессором и одним потоком. Зачем? ну, это потому, что конфигурация вашего процессора / ядра / потока определяет ваше поведение NIO и диктует минимальные требования к вашему пулу потоков.
На ноутбуке MacOS с 2009 года (почти 10 лет назад!) Вам потребовалось бы минимум 9 потоков только для поддержки одного соединения, выполняющего один блокирующий REST-запрос на этом оборудовании.
В современной системе Ryzen Threadripper часто требуется минимальное число потоков 69, чтобы поддерживать одно соединение, выполняющее один блокирующий REST-запрос на этом оборудовании.
С другой стороны, ваша конфигурация вполне подходит для Raspberry Pi Zero и может поддерживать около 3-х соединений, при этом 1 активный запрос на соединение.
С такой конфигурацией вы сможете обрабатывать только простые запросы последовательно, а ваше приложение не будет использовать асинхронную обработку или асинхронное поведение ввода-вывода. Зачем? это потому, что даже типичная современная веб-страница требует минимального количества потоков около 40, из-за того, как браузеры используют ваш сервер.
ExecutorThreadPool
это также ужасный выбор для вашей ситуации (он подходит только для сред с высокой степенью одновременности, например, 24+ процессоров / ядер и с минимальной конфигурацией потоков более 500, часто тысячами).
Вам лучше использовать стандарт QueuedThreadPool
он гораздо более производительный для нижнего уровня и способен расти, чтобы справляться со спросом (и со временем сокращать его, чтобы снизить использование ресурсов при снижении спроса).
QueuedThreadPool
(в Jetty 9.4.x) также имеет защиту от неправильных конфигураций и предупредит вас, если конфигурации недостаточно для вашей конфигурации оборудования, выбранного вами набора функций в Jetty или вашей конкретной конфигурации в Jetty.
Если вы хотите отклонить соединения, когда ресурсы невелики, то подумайте об использовании DoSFilter
(или если вы хотите быть более нежным, подумайте QoSFilter
).
Попытка ограничить использование через ThreadPool никогда не будет работать, так как для отклонения соединения необходим поток, чтобы принять его (поток-получатель, по одному на каждый соединитель сервера), другой для обработки событий NIO (поток селектора, общий ресурс, обработка нескольких соединения), а другой - для обработки запроса (для возврата кода состояния http 503).
Если вам нужна реализация в вашем собственном коде (не в Jetty), вы можете написать Filter
это подсчитывает активные обмены (запрос и ответ) и выдает статус ответа 503, если счет превышает некоторое настраиваемое число.
Но если вы сделаете это, вам, вероятно, следует закрыть все ответы. ака Connection: close
Заголовок ответа и не разрешать постоянные соединения.