2011-09-19 58 views
1

問:從AppEngine的Servlet調用Web服務(每秒0.5-1.5秒)的最佳方式是什麼?阻止呼叫在AppEngine環境中是否可擴展?從AppEngine的Servlet調用Web服務

上下文:我正在開發一個使用AppEngine和J2EE的Web應用程序。這些應用程序調用Amazon Web服務來爲用戶獲取一些信息。從我的asp.net經驗來看,完成這些調用的最好方法是使用異步http處理程序來防止在IIS線程池中出現飢餓。對於Servlet 2.5規範的J2EE(3.0 is planned),此功能不適用。

現在我正在考慮讓我的控制器(和servlets)線程安全並請求作用域。我還能做些什麼嗎?這是J2EE + AppEngine環境中的問題嗎?編輯:我知道AppEngine和JAX-WS的異步調用支持,但我不確定它如何與servlet環境一起玩。編輯:我知道AppEngine和JAX-WS的異步調用支持,但我不確定它如何與servlet環境一起玩。據我瞭解,要完成servlet請求,代碼仍然應該等待異步WS調用完成(回調或其他)。 我假設使用同步原語做它會阻塞當前工作線程。

因此,就線程被阻塞而言,爲了服務另一個用戶請求,servlet容器需要在線程池中分配新線程,爲堆棧分配新內存並浪費時間進行上下文切換。而且,當線程池中的線程用完時,請求可能會阻塞整個服務器。這個假設基於ASP.Net和IIS線程模型。它們適用於J2EE環境嗎?

回答:在研究Apache和GAE文檔後,線程池中線程的匱乏似乎不是真正的問題。 Apache默認情況下有200個線程池的線程(與asp.net和IIS中的25個線程相比)。基於此,我可以推斷出線程在JVM中相當便宜。

如果真的需要異步處理,或者servlet容器將耗盡線程,可以重新設計應用程序以通過google channel API發送響應。 的工作流程是這樣的:

  1. 使同步請求與Servlet
  2. 的Servlet使得對background工人創造了異步回覆和隊列任務通道
  3. 的Servlet返回響應客戶
  4. [服務其他請求]
  5. 後臺工作人員通過處理並將數據推送到客戶端channel api
+1

Web服務結果是否需要顯示給用戶?你不能將ws調用轉移到後臺任務隊列嗎? – systempuntoout

+0

是的。用戶調用搜索請求,並且WS執行實際搜索。但爲此實施一種共享方案是一個好主意! –

回答

1

當你觀察,servlets的不要」 t支持使用單個線程來服務多個併發請求 - 每個請求需要一個線程。執行HTTP調用的最佳方式是使用異步urlfetch,並在需要結果時等待該調用完成。這將阻止請求的線程,但是不能避免 - 線程專用於當前請求,直到它終止,無論您做什麼。

如果您不需要來自API調用的響應來滿足用戶的請求,則可以使用任務隊列離線執行工作。

0

使用fetchAsync不行嗎?

+0

我不太明白,如何將它整合到servlet執行中。爲了完成請求,servlet應該等待完成異步操作,佔用工作者線程。 –

+0

我想你希望異步調用的結果在響應中,我加入到Nick Johnsons的答案中。我認爲一個可能的問題可能是,當你有兩種類型的請求時:等待和提示。假設您池中的線程數量有限,並且您會遇到很多等待請求。這會使提示請求也等待,因爲不會有空閒的線程來爲它們服務。所以我建議爲等待請求設置一個單獨的池,就是這樣。 – bpgergo

0

着眼於這一點,這可能幫助

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

我不知道,如果你能準確地複製你點網做什麼,這是你可以做什麼可能是模擬它頁負載

  1. 提交一個Ajax請求使用Java腳本體的onload
  2. 在控制器控制器啓動異步任務,併發送回響應用戶,並使用一個會話令牌,以保持跟蹤任務的
  3. 您可以查詢控制器(添加另一種方法,以請求任務的更新,因爲你有會話令牌來跟蹤任務),直到你得到的迴應
  4. 你可以做到這一點無論在等待響應,保持輪詢控制器頁面或隱框
  5. 一旦你有你正在尋找如果你想這樣做,這將是最好的選擇,而不是投票將是理想的去除會話令牌

響應這種情況下Reverse Ajax /服務器推送

編輯:現在我明白你的意思了,我認爲你可以讓你的代碼執行異步任務,而不是等待異步本身的響應,只是將響應發回給用戶。我有簡單的線程,我將啓動,但會等待它完成,因爲我發送響應返回給用戶,並同時使用會話令牌來跟蹤請求

@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

Prasanna,謝謝你的建議。我意識到對JAX和內部GAE fetchAsync的異步支持。問題是 - 我不明白如何將其整合到sevlet生命週期中。請參閱我的原始問題的編輯。 –

+0

感謝您的完整示例,但我需要將WS調用的結果返回給用戶。 以下是來自.net的示例:http://msdn.microsoft.com/en-us/magazine/cc163725。aspx來澄清我在說什麼: 異步請求在Page_Load方法中啓動。之後,工作線程可以自由地提供另一個請求。只有當異步操作完成時,線程纔會回到處理頁/ servlet生命週期的其餘部分(預渲染等)。 –

+0

我編輯我的答案與控制器的例子。 –