Асинхронная обработка запросов Servlet

Я столкнулся с асинхронной обработкой запросов сервлетами, поскольку я изучал, как приложение NodeJS и приложение Java обрабатывают запрос.

Из того, что я читал в разных местах:

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

Отнимающая много времени операция блокировки теперь будет занята рабочим из Threadpool.

Если я правильно понял, у меня есть следующий вопрос:

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

В чем именно выигрыш здесь при использовании асинхронной обработки?

Если нет, просветите меня, пожалуйста.

Ответ 1

Да, в этом случае операция блокировки будет выполняться в нем собственным потоком и будет блокировать некоторые ресурсы, но ваш HTTP-поток теперь может обрабатывать некоторые другие операции, которые могут быть не столь трудоемкими.

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

Ответ 2

Я могу объяснить преимущества в терминах Node.js(одинаково применимые в других местах).

Проблема. Блокировка сети IO.

Предположим, вы хотите создать соединение с вашим сервером, чтобы читать с вам понадобится поток T1, который будет считывать данные по сети для этого соединения, этот метод чтения блокирует то, что ваш поток будет ждать бесконечно, пока не будут прочитаны данные. Теперь предположим, что у вас есть другое соединение в то время, теперь для обработки этого соединения вам нужно создать еще один Thread T2. Вполне возможно, что этот поток снова может быть заблокирован для чтения данных во втором соединении, поэтому это означает, что вы можете обрабатывать столько подключений, сколько сможете обрабатывать потоки в своей системе. Это называется моделью Thread for Request. Создание множества потоков приведет к ухудшению производительности вашей системы из-за большого количества переключения контекста и планирования. Эта модель плохо масштабируется.

Решение:

Немного фона, есть метод в FreeBSD/Linux, называемый kqueue/epoll. Оба этих метода принимают список socketfd (как параметры функции), вызывающий поток блокируется до тех пор, пока один или несколько сокетов не будут готовы к чтению данных, и эти методы возвращают подсписку этих готовых подключений. Ссылка http://austingwalters.com/io-multiplexing/

Теперь предположим, что у вас появилось чувство этих методов. Представьте, что существует тема, называемая EventLoop, которая вызывает вышеупомянутый метод epoll/kqueue.

Итак, в java ваш код будет выглядеть примерно так.

 /*Called by Event Loop Thread*/

while(true) {

   /**
     * socketFD socket on which your server is listening
     * returns connection which are ready 
     */ 
    List<Connection> readyConnections = epoll( socketFd );

   /** 
     * Workers thread will read data from connection
     * which would be very fast as data is already ready for read
     * So they don't need to wait.
     */ 
     submitToWorkerThreads(readyConnections); 

   /**
     * callback methods are queued by worker threads with data
     * event loop threads call this methods
     * this is where the main bottleneck is in case of Node.js
     * if your callback have any consuming task lets say loop 
     * of 1M then you Event loop will be busy and you can't 
     * accept new connection. In practice in memory computation 
     * are very fast as compared to network io.
     */
     executeCallBackMethodsfromQueue();     
   }

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

Приведенный выше подход имеет два недостатка.

  • Невозможно правильно использовать все ядра мультипроцессора.
  • Длинные вычисления в памяти значительно ухудшат производительность.

В первую очередь можно позаботиться о кластерном Node.js i.e kind one Node.js процессе, соответствующем каждому ядру процессора.

Anyways Посмотрите на vert.x, это похоже на аналогичный Node.js, но в java. Также изучите Netty.