Мой Servler проводит некоторое время при чтении request.getInputStream()
и записи на response.getOutputStream()
. В конечном итоге это может быть проблемой, поскольку она блокирует поток ни для чего, кроме как чтение/запись буквально нескольких байтов в секунду. (*)
Мне никогда не интересны данные частичного запроса, обработка не должна запускаться до того, как запрос будет полностью доступен. Аналогично для ответа.
Я предполагаю, что асинхронный IO решил бы это, но мне интересно, какой правильный путь. Возможно, сервлет Filter
заменил ServletInputStream
на обернутый ByteArrayInputStream
, используя request.startAsync
и вызывая цепочку сервлетов после того, как собрал весь вход?
- Есть ли такой фильтр?
- Должен ли я написать один или использовать другой подход?
Обратите внимание, что я имею в виду - не тратить потоки на медленные потоки сервлета. Это не то же самое, что startAsync
, которое позволяет избежать потоков, ожидающих только какого-либо события.
И да, на данный момент это будет преждевременная оптимизация.
Мой цикл чтения по запросу
В моем текущем методе ввода потока нет ничего интересного, но здесь вы:
private byte[] getInputBytes() throws IOException {
ServletInputStream inputStream = request.getInputStream();
final int len = request.getContentLength();
if (len >= 0) {
final byte[] result = new byte[len];
ByteStreams.readFully(inputStream, result);
return result;
} else {
return ByteStreams.toByteArray(inputStream);
}
}
Это все и блокируется, когда данные недоступны; ByteStreams
- из Гуавы.
Резюме моего понимания до сих пор
Как четко говорится в ответах, невозможно работать с потоками сервлетов, не тратя нити на них. Ни архитектура сервлета, ни общая реализация не раскрывают ничего, что позволяет сказать "буферизировать все данные и называть меня только тогда, когда вы собрали все", хотя они используют NIO и могут это сделать.
Причина может заключаться в том, что обычно используется обратный прокси, например nginx, который может это сделать. nginx делает эту буферизацию по умолчанию, и ее нельзя было даже отключить до два года назад.
Фактически поддерживаемый случай
Учитывая, что многие отрицательные ответы, я не уверен, но это выглядит как моя цель
чтобы избежать траты потоков на медленных потоках сервлетов
на самом деле полностью поддерживается: начиная с версии 3.1, ServletInputStream.html#setReadListener, который, как представляется, предназначен именно для этого. Поток, выделенный для обработки Servlet#Service
изначально вызывает request.startAsync()
, присоединяет слушателя и возвращается в пул, просто возвращаясь из service
. Слушатель реализует onDataAvailable()
, который вызывается, когда его можно читать без блокировки, добавляет кусок данных и возвращает. В onAllDataRead()
я могу выполнить всю обработку собранных данных.
Здесь пример, как это можно сделать с Jetty. Он также охватывает неблокирующий выход.
(*) В лог файлах я могу видеть запросы, занимающие до восьми секунд, которые тратятся на чтение ввода (100-байтовый заголовок + 100 байт данных). Такие случаи встречаются редко, но они происходят, хотя сервер в основном бездействует. Поэтому я предполагаю, что это мобильный клиент с очень плохим соединением (некоторые из наших пользователей подключаются из мест с такой плохой связностью).