Java — асинхронность в сервлете 3.0 против NIO в сервлете 3.1

#java #servlets #servlet-3.0 #servlet-3.1

#java #сервлеты #сервлет-3.0 #сервлет-3.1

Вопрос:

До сих пор, когда это применимо к обслуживанию http-запросов, я думал, что термины — asynchronous и non-blocking i/o означали одно и то же. Но, по-видимому, они были реализованы отдельно в servlet 3.0 и 3.1 соответственно. Я изо всех сил пытаюсь понять разницу здесь…

Может кто-нибудь пролить больше света на эту тему, пожалуйста? В частности, я ищу пример того, как реализация сервера servlet 3.0 может быть асинхронной, но блокировать поток? Я думаю, может быть, если я это пойму, может быть легче понять точную проблему, которую пытается решить неблокирующий ввод-вывод в сервлете 3.1.

Ответ №1:

Я попытаюсь обобщить то, что я узнал. Чтобы понять проблему, которую решают Servlet 3.0 и Servlet 3.1, давайте посмотрим на это следующим образом:

До сервлета 3.0:
Проблема с синхронной обработкой запросов заключается в том, что это привело к тому, что потоки (выполняющие тяжелую работу) выполнялись в течение длительного времени, прежде чем ответ вышел. Если это происходит в масштабе, в контейнере сервлета в конечном итоге заканчиваются потоки — длительные потоки приводят к голоданию потоков.

До Servlet 3.0 существовали специфические для контейнеров решения для этих длительных потоков, в которых мы могли создавать отдельный рабочий поток для выполнения тяжелой задачи, а затем возвращать ответ клиенту. Поток сервлета возвращается в пул сервлетов после запуска рабочего потока. Comet от Tomcat, FutureResponseServlet от WebLogic и диспетчер асинхронных запросов WebSphere являются некоторыми примерами реализации асинхронной обработки.
(Смотрите Ссылку 1 для получения дополнительной информации.)

Сервлет 3.0 асинхронный:
Фактическая работа может быть делегирована реализации пула потоков (независимо от решений, специфичных для контейнера). Runnable Реализация выполнит фактическую обработку и будет использовать AsyncContext либо для отправки запроса на другой ресурс, либо для записи ответа. Мы также можем добавить реализацию AsyncListener к объекту AsyncContext для реализации методов обратного вызова.
(Смотрите Ссылку 1 для получения дополнительной информации.)

Сервлет 3.1 NIO:
Как описано выше, Servlet 3.0 допускал асинхронную обработку запросов, но разрешался только традиционный ввод-вывод (в отличие от NIO). Почему традиционный ввод-вывод является проблемой?

При традиционном вводе-выводе необходимо учитывать два сценария:

  • Если данные, поступающие на сервер (ввод-вывод), блокируются или передаются медленнее, чем сервер может прочитать, тогда поток сервера, который пытается прочитать эти данные, должен ждать этих данных.
  • С другой стороны, если данные ответа с сервера, записанные на ServletOutputStream медленный, клиентский поток должен ждать. В обоих случаях серверный поток, выполняющий традиционный ввод-вывод (для запросов / ответов), блокируется.

Другими словами, с Servlet 3.0 асинхронной стала только часть обработки запросов, но не ввод-вывод для обслуживания запросов и ответов. Если блокируется достаточное количество потоков, это приводит к остановке потоков и влияет на производительность.

С Servlet 3.1 NIO эта проблема решается с помощью ReadListener WriteListener интерфейсов и. Они зарегистрированы в ServletInputStream и ServletOutputStream . У слушателей есть методы обратного вызова, которые вызываются, когда содержимое доступно для чтения или может быть записано без блокировки контейнера сервлета в потоках ввода-вывода. Таким образом, эти потоки ввода-вывода освобождаются и теперь могут обслуживать другие запросы, повышающие производительность. (Смотрите Ссылку 2 для получения дополнительной информации.)

Реквизиты

Комментарии:

1. Но в обычных приложениях реального мира я не могу представить, что сервер медленно пишет ответ. Он либо имеет полный ответ от контроллера (например, строку ответа json), либо нет. И медленные клиенты смягчаются путем размещения NGINX перед сервером приложений. Итак, почему мы заботимся об этом 3.1? Также я сомневаюсь, что медленные клиенты являются истинным аргументом — если вы используете неблокирующие сокеты (например, неблокирующий соединитель Tomcat), вы будете читать с каждого клиента как можно больше без блокировки. Итак, опять же, почему 3.1?

2. К сожалению, все ссылки не работают