ServletRequest startAsync()的有用性有限

前段時間我遇到了Servlet 3.0中AsyncContext.start(…)的目的是什么? 題。 引用上述方法的Javadoc :
使容器調度線程(可能從托管線程池中)運行指定的Runnable
提醒大家, AsyncContext是Servlet 3.0規范中定義的一種標準方式,用于異步處理HTTP請求。 基本上,HTTP請求不再綁定到HTTP線程,這使我們以后可以使用更少的線程來處理它。 事實證明,該規范提供了一個API,用于處理其他不同線程池中的異步線程。 首先,我們將了解該功能在Tomcat和Jetty中是如何被完全破壞和無用的,然后我們將討論為什么該功能的用途普遍存在疑問。
我們的測試servlet只會在給定的時間內睡眠。 在正常情況下,這是可伸縮性的殺手,因為即使休眠的Servlet不會消耗CPU,但是與該特定請求綁定的休眠的HTTP線程也會消耗內存,并且其他傳入請求都無法使用該線程。 在我們的測試設置中,我將HTTP工作線程的數量限制為10個,這意味著即使應用程序本身幾乎完全處于空閑狀態,也只有10個并發請求完全阻塞了該應用程序(外部沒有響應)。 顯然,睡眠是可擴展性的敵人。
@WebServlet(urlPatterns = Array("/*"))
class SlowServlet extends HttpServlet with Logging {protected override def doGet(req: HttpServletRequest, resp: HttpServletResponse) {logger.info("Request received")val sleepParam = Option(req.getParameter("sleep")) map {_.toLong}TimeUnit.MILLISECONDS.sleep(sleepParam getOrElse 10)logger.info("Request done")}
}
對這段代碼進行基準測試可以發現,只要并發連接數低于HTTP線程數,平均響應時間就會接近sleep參數。 毫不奇怪,一旦我們超過HTTP線程數,響應時間就會開始增加。 第十一連接必須等待任何其他請求完成并釋放工作線程。 當并發級別超過100時,Tomcat開始斷開連接-太多的客戶端已排隊。
那么花哨的AsyncContext.start()方法又如何呢(不要與ServletRequest.startAsync()混淆)? 根據JavaDoc,我可以提交任何Runnable ,并且容器將使用某些托管線程池來處理它。 這將在一定程度上有所幫助,因為我不再阻止HTTP工作線程(但仍使用servlet容器中某個位置的另一個線程)。 快速切換到異步servlet:
@WebServlet(urlPatterns = Array("/*"), asyncSupported = true)
class SlowServlet extends HttpServlet with Logging {protected override def doGet(req: HttpServletRequest, resp: HttpServletResponse) {logger.info("Request received")val asyncContext = req.startAsync()asyncContext.setTimeout(TimeUnit.MINUTES.toMillis(10))asyncContext.start(new Runnable() {def run() {logger.info("Handling request")val sleepParam = Option(req.getParameter("sleep")) map {_.toLong}TimeUnit.MILLISECONDS.sleep(sleepParam getOrElse 10)logger.info("Request done")asyncContext.complete()}})}
}
我們首先啟用異步處理,然后簡單地將sleep()移至Runnable并希望移至其他線程池中,從而釋放HTTP線程池。 快速壓力測試揭示了一些出乎意料的結果(此處:響應時間與并發連接數):
猜猜是什么,響應時間與根本沒有異步支持的響應時間完全相同 (!)。仔細檢查后,我發現當調用AsyncContext.start() ,Tomcat將給定的任務提交回……HTTP工作線程池,即用于所有HTTP請求! 基本上,這意味著我們發布了一個HTTP線程,只是為了在稍后的一毫秒內使用(甚至可能是同一線程)。 在Tomcat中調用AsyncContext.start()絕對沒有好處。 我不知道這是錯誤還是功能。 一方面,這顯然不是API設計人員想要的。 假定servlet容器管理單獨的獨立線程池,因此HTTP工作線程池仍然可用。 我的意思是,異步處理的全部目的是逃避HTTP池。 Tomcat假裝將我們的工作委托給另一個線程,而它仍然使用原始的工作線程池。
那么,為什么我認為這是一個功能? 因為Jetty以完全相同的方式“破壞”了……無論它是按設計運行還是僅是不良的API實現,因此在Tomcat和Jetty中使用AsyncContext.start()都是沒有意義的,并且只會不必要地使代碼復雜化。 它不會給您任何好處,該應用程序在高負載下的工作原理完全相同,就好像根本沒有異步邏輯一樣。
但是,如何在正確的實現(例如IBM WAS)上使用此API功能呢? 更好,但API仍然沒有像在擴展性方面給我們帶來太多好處。 再次說明:異步處理的全部要點是能夠將HTTP請求與基礎線程分離,最好通過使用同一線程處理多個連接來實現。
AsyncContext.start()將在單獨的線程池中運行提供的Runnable 。 您的應用程序仍然可以響應,可以處理普通的請求,而您決定異步處理的長期運行的請求則在單獨的線程池中處理。 更好的是,不幸的是線程池和每個連接線程的成語仍然是瓶頸。 對于JVM,啟動什么類型的線程都沒有關系–它們仍然占用內存。 因此,我們不再阻塞HTTP工作線程,但就我們可以支持的并發長期運行任務而言,我們的應用程序具有更大的可伸縮性。
在這個帶有休眠servlet的簡單,不現實的示例中,實際上,我們可以使用Servlet 3.0異步支持(只有一個額外的線程)并且不使用AsyncContext.start()來支持數千個并發(等待)連接。 你知道如何? 提示: ScheduledExecutorService
后記:斯卡拉善良
我差點忘了。 盡管示例是用Scala編寫的,但我還沒有使用任何出色的語言功能。 這是一個:隱式轉換。 使它在您的范圍內可用:
implicit def blockToRunnable[T](block: => T) = new Runnable {def run() {block}
}
突然之間,您可以使用代碼塊來代替手動和顯式實例化Runnable
asyncContext start {logger.info("Handling request")val sleepParam = Option(req.getParameter("sleep")) map { _.toLong}TimeUnit.MILLISECONDS.sleep(sleepParam getOrElse 10)logger.info("Request done")asyncContext.complete()
}
甜!
參考: Javax 和 servlet 社區的 JCG合作伙伴 Tomasz Nurkiewicz提供的javax.servlet.ServletRequest.startAsync()用途有限 。

翻譯自: https://www.javacodegeeks.com/2012/05/servletrequest-startasync-limited.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372904.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372904.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372904.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

mysql所支持的比較運算符_mysql比較運算符有哪些?Mysql比較運算符詳解

比較運算符可用于比較數字和字符串。今天發一篇Mysql比較運算符詳解,希望對初學者有所幫助,雖然現在流行NoSQL,但是MYSQL還是很有用的,數字作為浮點值進行比較,字符串以不區為例進行比較,運算符用于比較表達…

數據結構0類模板的使用

類模板的使用 #include <iostream> #include <conio.h> #include <string> #define N 3 using namespace std;template <class numtype> class Swap{public :Swap(numtype a,numtype b){xa;yb;}numtype ___(){tempx;xy;ytemp;return x;}//testnumtype …

JavaScript 函數

函數 由于JavaScript的函數也是一個對象&#xff0c;所以類似function abs(v){}函數實際上是一個函數對象&#xff0c;而函數名abs可以視為指向該函數的變量。 因此&#xff0c;第二種定義函數的方式如下&#xff1a; var abs function (x) {if (x > 0) {return x;} else {…

Http Invoker的Spring Remoting支持

Spring HTTP Invoker是Java到Java遠程處理的重要解決方案。 該技術使用標準的Java序列化機制通過HTTP公開服務&#xff0c;并且可以被視為替代解決方案&#xff0c;而不是Hessian和Burlap中的自定義序列化。 而且&#xff0c;它僅由Spring提供&#xff0c;因此客戶端和服務器應…

mysql 日期列表_MySQL 生成日期表

1、創建一個num表&#xff0c;用來存儲數字0~9CREATE TABLE num (i int);2、在num表中生成0~9INSERT INTO num (i) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);3、生成一個存儲日期的表&#xff0c;datalist是字段名CREATE TABLE if not exists calendar(dateli…

學習后綴自動機想法

小序&#xff1a;學習后綴自動機是要有耐心的&#xff0c;clj的論文自己看真心酸爽&#xff01;&#xff08;還是自己太弱&#xff0c;ls&#xff0c;oyzx好勁啊&#xff0c;狂膜不止&#xff09; 剛剛在寫博客之前又看了篇論文&#xff0c;終于看懂了&#xff0c;好開心 正文&…

【BZOJ】3575: [Hnoi2014]道路堵塞

題目鏈接&#xff1a;http://www.lydsy.com/JudgeOnline/problem.php?id3575 大概的做法是&#xff0c;按照順序枚舉每一條要刪去的邊&#xff0c;(假設當前點為$u$&#xff0c;在最短路徑上的下一個點是$v$)然后強制不走${u->v}$這條邊&#xff0c;將$u$入隊&#xff0c;做…

結合使用slf4j和Logback教程

在當前文章中&#xff0c;我將向您展示如何配置您的應用程序以使用slf4j和logback作為記錄器解決方案。 Java簡單日志記錄外觀&#xff08;slf4j&#xff09;是各種日志記錄框架的簡單外觀&#xff0c;例如JDK日志記錄&#xff08;java.util.logging&#xff09;&#xff0c;lo…

mysql 分組top_MySQL:如何查詢出每個分組中的 top n 條記錄?

問題描述需求&#xff1a;查詢出每月 order_amount(訂單金額) 排行前3的記錄。例如對于2019-02&#xff0c;查詢結果中就應該是這3條&#xff1a;解決方法MySQL 5.7 和 MySQL 8.0 有不同的處理方法。1. MySQL 5.7我們先寫一個查詢語句。根據 order_date 中的年、月&#xff0c;…

ACM第四站————最小生成樹(普里姆算法)

對于一個帶權的無向連通圖&#xff0c;其每個生成樹所有邊上的權值之和可能不同&#xff0c;我們把所有邊上權值之和最小的生成樹稱為圖的最小生成樹。 普里姆算法是以其中某一頂點為起點&#xff0c;逐步尋找各個頂點上最小權值的邊來構建最小生成樹。 其中運用到了回溯&#…

利用jenkins的api來完成相關工作流程的自動化

[本文出自天外歸云的博客園] 背景 1. 實際工作中涉及到安卓客戶端方面的測試&#xff0c;外推或運營部門經常會有很多的渠道&#xff0c;而每個渠道都對應著一個app的下載包&#xff0c;這些渠道都記錄在安卓項目下的一個渠道列表文件中。外推或運營部門經常會有新的渠道產生&a…

擁有成本分析:Oracle WebLogic Server與JBoss

Crimson Consulting Group 撰寫的非常有趣的白皮書 &#xff0c;比較了Weblogic和JBoss之間的擁有成本 。 盡管JBoss是免費的&#xff0c;但該白皮書卻嚴肅地宣稱&#xff0c;從長遠來看&#xff0c;Weblogic更便宜。 盡管此研究是由Oracle贊助的&#xff0c;但它看起來非常嚴肅…

mysql limit 分頁 0_Mysql分頁之limit用法與limit優化

Mysql limit分頁語句用法與Oracle和MS SqlServer相比&#xff0c;mysql的分頁方法簡單的讓人想哭。--語法&#xff1a;SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset--舉例&#xff1a;select * from table limit 5; --返回前5行select * from table limit 0…

與硒的集成測試

總覽 我已經使用了一段時間&#xff0c;遇到了一些似乎可以使生活更輕松的事情。 我以為可以將其作為教程分享&#xff0c;所以我將向您介紹這些部分&#xff1a; 使用Maven設置Web項目&#xff0c;配置Selenium以在CI上作為集成測試運行 尋找使用“頁面對象”為網站中的頁面…

linux每天一小步---sed命令詳解

1 命令功能 sed是一個相當強大的文件處理編輯工具&#xff0c;sed用來替換&#xff0c;刪除&#xff0c;更新文件中的內容。sed以文本行為單位進行處理&#xff0c;一次處理一行內容。首先sed吧當前處理的行存儲在臨時的緩沖區中&#xff08;稱為模式空間pattern space&#xf…

mysql trace工具_100% 展示 MySQL 語句執行的神器-Optimizer Trace

在上一篇文章《用Explain 命令分析 MySQL 的 SQL 執行》中&#xff0c;我們講解了 Explain 命令的詳細使用。但是它只能展示 SQL 語句的執行計劃&#xff0c;無法展示為什么一些其他的執行計劃未被選擇&#xff0c;比如說明明有索引&#xff0c;但是為什么查詢時未使用索引等。…

MOXy作為您的JAX-RS JSON提供程序–服務器端

在以前的系列文章中&#xff0c;我介紹了如何利用EclipseLink JAXB&#xff08;MOXy&#xff09;創建RESTful數據訪問服務。 在本文中&#xff0c;我將介紹在服務器端利用MOXy的新JSON綁定添加對基于JAXB映射的JSON消息的支持有多么容易。 MOXy作為您的JAX-RS JSON提供程序–服…

006_過濾器

過濾器 過濾器&#xff08;Filter&#xff09;把附加邏輯注入到MVC框的請求處理&#xff0c;實現了交叉關注。所謂交叉關注&#xff08;Cross-Cutting Concerns&#xff09;&#xff0c;是指可以用于整個應用程序&#xff0c;而又不適合放置在某個局部位置的功能&#xff0c;否…

Android_項目文件結構目錄分析

android項目文件結構目錄分析 在此我們新建了一個helloworld的項目&#xff0c;先看一些目錄結構&#xff1a; 這么多的文件夾和文件中&#xff0c;我們重點關注是res目錄、src目錄、AndroidManifest.xml文件&#xff1a; 一、res目錄主要是用來存放android項目的各種資源文件&…

實體 聯系 模型mysql_數據庫系統概念讀書筆記――實體-聯系模型_MySQL

bitsCN.com數據庫系統概念讀書筆記——實體-聯系模型前言為了重新回顧我寫的消息系統架構&#xff0c;我需要重新讀一下數據庫系統概念的前三章&#xff0c;這里簡單的做一個筆記&#xff0c;方便自己回顧基本概念實體-聯系(E-R)數據模型基于對現實世界的這樣一種認識&#xff…