Вызов веб-службы из сервлета на AppEngine - PullRequest
1 голос
/ 19 сентября 2011

Вопрос: Какой лучший способ вызвать веб-службу (0,5-1,5 секунды / звонок) из сервлета в AppEngine? Являются ли блокирующие вызовы масштабируемыми в среде AppEngine?

Контекст: я разрабатываю веб-приложение с использованием AppEngine и J2EE. Приложения вызывают веб-сервис Amazon, чтобы получить некоторую информацию для пользователя. Исходя из моего опыта работы с asp.net, лучший способ сделать вызовы - это использовать асинхронный http-обработчик, чтобы предотвратить голодание в пуле потоков IIS. Эта функция недоступна для J2EE со спецификацией Servlet 2.5 (планируется 3.0 ).

Сейчас я думаю о том, чтобы сделать мои контроллеры (и сервлеты) потокобезопасными и запросить объем. Есть ли что-нибудь еще, что я могу сделать? Это даже проблема в среде J2EE + AppEngine?

РЕДАКТИРОВАТЬ: я знаю о поддержке асинхронных вызовов AppEngine и JAX-WS, но я не уверен, как она работает со средой сервлетов. Насколько я понимаю, чтобы завершить запрос сервлета, код все еще должен ждать завершения асинхронного вызова WS (обратного вызова или чего-то еще). Я предполагаю, что выполнение этого с использованием примитивов синхронизации заблокирует текущий рабочий поток.

Таким образом, поскольку поток заблокирован, для обслуживания другого контейнера сервлета запроса пользователя необходимо выделить новый поток в пуле потоков, выделить новую память для стека и тратить время на переключение контекста. Более того, запросы могут блокировать весь сервер, когда у нас заканчиваются потоки в пуле потоков. Эти предположения основаны на модели потоков ASP.Net и IIS. Применимы ли они к среде J2EE?

ОТВЕТ: После изучения документации Apache и GAE кажется, что голодание потоков в пуле потоков не является реальной проблемой. Apache по умолчанию имеет 200 потоков для пула потоков (по сравнению с 25 в asp.NET и IIS). Исходя из этого, я могу сделать вывод, что потоки в JVM довольно дешевы.

В случае, если действительно требуется асинхронная обработка, или в контейнере сервлета закончились потоки, можно изменить дизайн приложения для отправки ответа через API канала Google. Рабочий процесс будет выглядеть так:

  1. Сделать запрос на синхронизацию сервлету
  2. Сервлет создает создает канал для асинхронного ответа и ставит в очередь задачу для фон работник
  3. Сервлет возвращает ответ клиенту
  4. [Обслуживание других запросов]
  5. Фоновый рабочий выполняет обработку и передает данные клиенту через канал API

Ответы [ 3 ]

1 голос
/ 20 сентября 2011

Как вы заметили, сервлеты не поддерживают использование одного потока для обслуживания нескольких одновременных запросов - для каждого запроса требуется один поток. Лучший способ сделать ваш HTTP-вызов - это использовать асинхронный urlfetch и ждать завершения этого вызова, когда вам нужен результат. Это заблокирует поток запроса, но этого избежать нельзя - поток будет выделен для текущего запроса, пока он не завершится независимо от того, что вы делаете.

Если вам не нужен ответ от вызова API для обслуживания запроса пользователя, вместо этого вы можете использовать очередь задач для автономной работы.

0 голосов
/ 19 сентября 2011

смотрит на это, это может помочь

http://today.java.net/pub/a/today/2006/09/19/asynchronous-jax-ws-web-services.html

Я не уверен, если вы можете точно повторить то, что вы делаете в точечной сети, вот что вы можете сделать, чтобыимитировать это страница при загрузке

  1. Отправить ajax-запрос к контроллеру с помощью тела загрузки java-скрипта
  2. В контроллере запустить асинхронную задачу и отправить ответ обратно пользователю и использоватьтокен сеанса для отслеживания задачи
  3. Вы можете опрашивать контроллер (добавьте другой метод, чтобы запросить обновление задачи, так как у вас есть токен сеанса для отслеживания задачи), пока не получите ответ
  4. Вы можете сделать это либо в ожидании страницы ответа, либо в виде скрытого фрейма, который продолжает опрашивать контроллер.
  5. После получения искомого ответа удалите маркер сеанса

Есливы хотите сделать это было бы лучшим вариантом вместо опроса было бы идеально в этом случае Reverse Ajax / server push

Редактировать: Теперь я понимаю, что вы имеете в виду, я худойk вы можете заставить свой код выполнять асинхронную задачу, не ожидая ответа от самой асинхронной, просто отправив ответ обратно пользователю.У меня есть простой поток, который я начну, но дождусь его завершения, так как я отправляю ответ пользователю и одновременно использую токен сеанса для отслеживания запроса

@Controller
@RequestMapping("/asyncTest")
public class AsyncCotroller {
@RequestMapping(value = "/async.html", method = RequestMethod.GET)
public ModelAndView dialogController(Model model, HttpServletRequest request) 
{
   System.err.println("(System.currentTimeMillis()/1000) " + (System.currentTimeMillis()/1000));
   //start a thread (async simulator)
   new Thread(new MyRunnbelImpl()).start();
   //use this attribute to track response
   request.getSession().setAttribute("asyncTaskSessionAttribute", "asyncTaskSessionAttribute");
       //if you look at the print of system out, you will see that it is not waiting on //async task
   System.err.println("(System.currentTimeMillis()/1000) " + (System.currentTimeMillis()/1000));
   return new ModelAndView("test");
}

class MyRunnbelImpl implements Runnable
{

    @Override
    public void run() 
    {
        try 
        {
            Thread.sleep(5000);
        } catch (InterruptedException e) 
        {
            e.printStackTrace();
        }
    }

}
}
0 голосов
/ 19 сентября 2011

Разве не нормально использовать fetchAsync ?

...