日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

servlet异步_如何使用异步Servlet来提高性能

發布時間:2023/12/3 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 servlet异步_如何使用异步Servlet来提高性能 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

servlet異步

這篇文章將描述一種性能優化技術,該技術適用于與現代Web應用程序相關的常見問題。 如今的應用程序不再只是被動地等待瀏覽器發起請求,而是希望自己開始通信。 一個典型的示例可能涉及聊天應用程序,拍賣行等–共同點是這樣一個事實,即大多數時候與瀏覽器的連接處于空閑狀態并等待某個事件被觸發。

這類應用程序已經開發出自己的問題類別,尤其是在面對重負載時。 癥狀包括線程不足,用戶交互受苦,陳舊性問題等。

根據最近在加載此類應用程序方面的經驗,我認為現在是演示簡單解決方案的好時機。 在Servlet API 3.0實現成為主流之后,該解決方案就變得真正簡單,標準化和優雅。

但是在進入演示解決方案之前,我們應該更詳細地了解問題。 對于我們的讀者–在某些源代碼的幫助下,比解釋問題更容易的是:

@WebServlet(urlPatterns = "/BlockingServlet") public class BlockingServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {try {long start = System.currentTimeMillis();Thread.sleep(2000);String name = Thread.currentThread().getName();long duration = System.currentTimeMillis() - start;response.getWriter().printf("Thread %s completed the task in %d ms.", name, duration);} catch (Exception e) {throw new RuntimeException(e.getMessage(), e);}}

上面的servlet是上面描述的應用程序的外觀示例:

  • 請求到達,宣布有興趣監視某些事件
  • 線程被阻塞,直到事件到達
  • 收到事件后,響應將被編譯并發送回客戶端

為了簡單起見,我們將等待部分替換為對Thread.sleep()的調用。

現在,您可能會認為這是一個完全正常的servlet。 在許多情況下,您是完全正確的–在應用程序面臨大量負載之前,代碼沒有錯。

為了模擬此負載,我在JMeter的幫助下創建了一個相當簡單的測試,在該測試中,我啟動了2,000個線程,每個線程運行10次迭代,以對/ BlockedServlet的請求轟炸應用程序。 在現成的Tomcat 7.0.42上使用已部署的servlet運行測試,我得到以下結果:

  • 平均響應時間:19,324毫秒
  • 最小響應時間:2,000毫秒
  • 最大響應時間:21,869 ms
  • 吞吐量:97個請求/秒

Tomcat的默認配置有200個工作線程,再加上將模擬工作替換為2,000ms睡眠周期這一事實很好地說明了最小和最大響應時間– 200秒中的每個線程應該能夠完成100個睡眠周期,每個2秒。 最重要的是,加上上下文切換成本,達到的97個請求/秒的吞吐量非常接近我們的預期。

對于99.9%的應用程序而言,吞吐量本身看起來不會太差。 但是,從最大響應時間(尤其是平均響應時間)來看,問題開始變得更加嚴重。 在20秒(而不是預期的2秒)內獲得響應是確定惹惱用戶的肯定方法。

現在讓我們看一下利用Servlet API 3.0異步支持的替代實現:

@WebServlet(asyncSupported = true, value = "/AsyncServlet") public class AsyncServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {Work.add(request.startAsync());} }public class Work implements ServletContextListener {private static final BlockingQueue queue = new LinkedBlockingQueue();private volatile Thread thread;public static void add(AsyncContext c) {queue.add(c);}@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {thread = new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {Thread.sleep(2000);AsyncContext context;while ((context = queue.poll()) != null) {try {ServletResponse response = context.getResponse();response.setContentType("text/plain");PrintWriter out = response.getWriter();out.printf("Thread %s completed the task", Thread.currentThread().getName());out.flush();} catch (Exception e) {throw new RuntimeException(e.getMessage(), e);} finally {context.complete();}}} catch (InterruptedException e) {return;}}}});thread.start();}@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {thread.interrupt();} }

這部分代碼稍微復雜一點,所以也許在我們開始深入研究解決方案細節之前,我可以概述一下該解決方案在延遲方面的性能提高約75倍,在吞吐量方面的性能提高了約20倍 。 掌握了此類結果的知識后,您應該更加有動力去理解第二個示例中的實際情況。

servlet本身看起來確實很簡單。 但是,有兩個事實值得概述,第一個事實聲明了該Servlet支持異步方法調用:

@WebServlet(asyncSupported = true, value = "/AsyncServlet")

第二個重要方面隱藏在以下行中

Work.add(request.startAsync());

其中整個請求處理都委托給Work類。 使用AsyncContext實例存儲請求的上下文,該實例保存由容器提供的請求和響應。

現在,第二個也是更復雜的類–以ServletContextListener實現的Work開始看起來更簡單。 傳入的請求只是在實現中排隊等待通知-這可能是對受監控拍賣的更新出價,或者是群聊中所有請求都在等待的下一條消息。

通知到達時-再次簡化為僅在Thread.sleep()中等待2,000ms,隊列中所有被阻止的任務都由一個負責編譯和發送響應的工作線程處理。 我們沒有阻塞數百個線程來等待外部通知,而是以一種更簡單,更簡潔的方式實現了這一點-將興趣組批處理在一起,并在單個線程中處理請求。

結果不言而喻–在具有默認配置的相同Tomcat 7.0.24上進行的相同測試得出以下結果:

  • 平均響應時間:265毫秒
  • 最小響應時間:6毫秒
  • 最長響應時間:2,058毫秒
  • 吞吐量:1,965請求/秒

此處的具體情況很小且綜合,但在實際應用中可以實現類似的改進。

現在,在您將所有servlet重寫為異步servlet之前-稍等片刻。 該解決方案可以完美地用在部分用例上,例如群聊通知和拍賣行價格警報。 對于請求在唯一數據庫查詢完成后等待的情況,您很可能不會從中受益。 因此,與往常一樣,我必須重申我最喜歡的與性能相關的建議–衡量所有事情。 什么都不要猜。

但是在問題確實適合解決方案形狀的情況下,我只能稱贊它。 除了對吞吐量和延遲的明顯改進之外,我們還優雅地避免了在高負載下可能出現的線程不足問題。

另一個重要方面–異步請求處理方法最終實現了標準化。 獨立于您最喜歡的Servlet API 3.0 –兼容應用程序服務器(例如Tomcat 7 , JBoss 6或Jetty 8),您可以確定該方法有效。 不再為不同的Comet實現或與平臺相關的解決方案(例如Weblogic FutureResponseServlet)而費力 。

參考: Plumbr Blog博客上的JCG合作伙伴 Nikita Salnikov Tarnovski 如何使用異步Servlet來提高性能 。

翻譯自: https://www.javacodegeeks.com/2013/10/how-to-use-asynchronous-servlets-to-improve-performance.html

servlet異步

總結

以上是生活随笔為你收集整理的servlet异步_如何使用异步Servlet来提高性能的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。