摘要:但是這樣依然有一個(gè)問(wèn)題,考慮以下場(chǎng)景有一個(gè)容器,線(xiàn)程池大小。這個(gè)時(shí)候工程師發(fā)現(xiàn)了問(wèn)題,擴(kuò)展了線(xiàn)程池大小到,但是負(fù)載依然持續(xù)走高,現(xiàn)在有個(gè)到,依然無(wú)法響應(yīng)。你可以修改的線(xiàn)程池大小,把它和比較結(jié)果來(lái)驗(yàn)證這一結(jié)論。
Github地址
相關(guān)系列文章:
Servlet 3.1 Async IO分析
Spring MVC異步處理的幾種方式
Servlet 3.0 開(kāi)始提供了AsyncContext用來(lái)支持異步處理請(qǐng)求,那么異步處理請(qǐng)求到底能夠帶來(lái)哪些好處?
Web容器一般來(lái)說(shuō)處理請(qǐng)求的方式是:為每個(gè)request分配一個(gè)thread。我們都知道thread的創(chuàng)建不是沒(méi)有代價(jià)的,Web容器的thread pool都是有上限的。
那么一個(gè)很容易預(yù)見(jiàn)的問(wèn)題就是,在高負(fù)載情況下,thread pool都被占著了,那么后續(xù)的request就只能等待,如果運(yùn)氣不好客戶(hù)端會(huì)報(bào)等待超時(shí)的錯(cuò)誤。
在AsyncContext出現(xiàn)之前,解決這個(gè)問(wèn)題的唯一辦法就是擴(kuò)充Web容器的thread pool。
但是這樣依然有一個(gè)問(wèn)題,考慮以下場(chǎng)景:
有一個(gè)web容器,線(xiàn)程池大小200。有一個(gè)web app,它有兩個(gè)servlet,Servlet-A處理單個(gè)請(qǐng)求的時(shí)間是10s,Servlet-B處理單個(gè)請(qǐng)求的時(shí)間是1s。
現(xiàn)在遇到了高負(fù)載,有超過(guò)200個(gè)request到Servlet-A,如果這個(gè)時(shí)候請(qǐng)求Servlet-B就會(huì)等待,因?yàn)樗蠬TTP thread都已經(jīng)被Servlet-A占用了。
這個(gè)時(shí)候工程師發(fā)現(xiàn)了問(wèn)題,擴(kuò)展了線(xiàn)程池大小到400,但是負(fù)載依然持續(xù)走高,現(xiàn)在有400個(gè)request到Servlet-A,Servlet-B依然無(wú)法響應(yīng)。
看到問(wèn)題了沒(méi)有,因?yàn)?strong>HTTP thread和Worker thread耦合在了一起(就是同一個(gè)thread),所以導(dǎo)致了當(dāng)大量request到一個(gè)耗時(shí)操作時(shí),就會(huì)將HTTP thread占滿(mǎn),導(dǎo)致整個(gè)Web容器就會(huì)無(wú)法響應(yīng)。
但是如果使用AsyncContext,我們就可以將耗時(shí)的操作交給另一個(gè)thread去做,這樣HTTP thread就被釋放出來(lái)了,可以去處理其他請(qǐng)求了。
注意,只有使用AsyncContext才能夠達(dá)到上面所講的效果,如果直接new Thread()或者類(lèi)似的方式的,HTTP thread并不會(huì)歸還到容器。
下面是一個(gè)官方的例子:
@WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true) public class AsyncServlet extends HttpServlet { /* ... Same variables and init method as in SyncServlet ... */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) { response.setContentType("text/html;charset=UTF-8"); final AsyncContext acontext = request.startAsync(); acontext.start(new Runnable() { public void run() { String param = acontext.getRequest().getParameter("param"); String result = resource.process(param); HttpServletResponse response = acontext.getResponse(); /* ... print to the response ... */ acontext.complete(); } }); } }陷阱
在這個(gè)官方例子里,每個(gè)HTTP thread都會(huì)開(kāi)啟另一個(gè)Worker thread來(lái)處理請(qǐng)求,然后把HTTP thread就歸還給Web容器。但是看AsyncContext.start()方法的javadoc:
Causes the container to dispatch a thread, possibly from a managed thread pool, to run the specified Runnable.
實(shí)際上這里并沒(méi)有規(guī)定Worker thread到底從哪里來(lái),也許是HTTP thread pool之外的另一個(gè)thread pool?還是說(shuō)就是HTTP thread pool?
The Limited Usefulness of AsyncContext.start()文章里寫(xiě)道:不同的Web容器對(duì)此有不同的實(shí)現(xiàn),不過(guò)Tomcat實(shí)際上是利用HTTP thread pool來(lái)處理AsyncContext.start()的。
這也就是說(shuō),我們?cè)臼窍脶尫臜TTP thread的,但實(shí)際上并沒(méi)有,因?yàn)橛蠬TTP thread依然被用作Worker thread,只不過(guò)這個(gè)thread和接收請(qǐng)求的HTTP thread不是同一個(gè)而已。
這個(gè)結(jié)論我們也可以通過(guò)AsyncServlet1和SyncServlet的Jmeter benchmark看出來(lái),兩者的throughput結(jié)果差不多。啟動(dòng)方法:?jiǎn)?dòng)Main,然后利用Jmeter啟動(dòng)benchmark.jmx(Tomcat默認(rèn)配置下HTTP thread pool=200)。
使用ExecutorService前面看到了Tomcat并沒(méi)有多帶帶維護(hù)Worker thread pool,那么我們就得自己想辦法搞一個(gè),見(jiàn)AsyncServlet2,它使用了一個(gè)帶Thread pool的ExecutorService來(lái)處理AsyncContext。
其他方式所以對(duì)于AsyncContext的使用并沒(méi)有固定的方式,你可以根據(jù)實(shí)際需要去采用不同的方式來(lái)處理,為此你需要一點(diǎn)Java concurrent programming的知識(shí)。
對(duì)于性能的誤解AsyncContext的目的并不是為了提高性能,也并不直接提供性能提升,它提供了把HTTP thread和Worker thread解藕的機(jī)制,從而提高Web容器的響應(yīng)能力。
不過(guò)AsyncContext在某些時(shí)候的確能夠提高性能,但這個(gè)取決于你的代碼是怎么寫(xiě)的。
比如:Web容器的HTTP thread pool數(shù)量200,某個(gè)Servlet使用一個(gè)300的Worker thread pool來(lái)處理AsyncContext。
相比Sync方式Worker thread pool=HTTP thread pool=200,在這種情況下我們有了300的Worker thread pool,所以肯定能夠帶來(lái)一些性能上的提升(畢竟干活的人多了)。
相反,如果當(dāng)Worker thread的數(shù)量<=HTTP thread數(shù)量的時(shí)候,那么就不會(huì)得到性能提升,因?yàn)榇藭r(shí)處理請(qǐng)求的瓶頸在Worker thread。
你可以修改AsyncServlet2的線(xiàn)程池大小,把它和SyncServlet比較benchmark結(jié)果來(lái)驗(yàn)證這一結(jié)論。
一定不要認(rèn)為Worker thread pool必須比HTTP thread pool大,理由如下:
兩者職責(zé)不同,一個(gè)是Web容器用來(lái)接收外來(lái)請(qǐng)求,一個(gè)是處理業(yè)務(wù)邏輯
thread的創(chuàng)建是有代價(jià)的,如果HTTP thread pool已經(jīng)很大了再搞一個(gè)更大的Worker thread pool反而會(huì)造成過(guò)多的Context switch和內(nèi)存開(kāi)銷(xiāo)
AsyncContext的目的是將HTTP thread釋放出來(lái),避免被操作長(zhǎng)期占用進(jìn)而導(dǎo)致Web容器無(wú)法響應(yīng)
所以在更多時(shí)候,Worker thread pool不會(huì)很大,而且會(huì)根據(jù)不同業(yè)務(wù)構(gòu)建不同的Worker thread pool。
比如:Web容器thread pool大小200,一個(gè)慢速Servlet的Worker thread pool大小10,這樣一來(lái),無(wú)論有多少請(qǐng)求到慢速操作,它都不會(huì)將HTTP thread占滿(mǎn)導(dǎo)致其他請(qǐng)求無(wú)法處理。
Java EE 7 Tutorial: Java Servlet Technology - Asynchronous Processing
The Limited Usefulness of AsyncContext.start()
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/70726.html
摘要:于是提供了機(jī)制,使得從中讀往里寫(xiě)變成異步動(dòng)作。這是因?yàn)榭蛻?hù)端的數(shù)據(jù)推送速度太慢了,容器先將收回,當(dāng)容器發(fā)現(xiàn)可以讀取到新數(shù)據(jù)的時(shí)候,再分配一個(gè)去讀,如此循環(huán)直到全部讀完為止。注意和不能同時(shí)使用。 Github地址 相關(guān)系列文章: Servlet 3.0 異步處理詳解 Spring MVC異步處理的幾種方式 Servlet Async Processing提供了一種異步請(qǐng)求處理的手段(...
摘要:異步處理簡(jiǎn)介地址相關(guān)系列文章異步處理詳解分析本文講到的所有特性皆是基于的,不是基于的。用于異步返回結(jié)果,使用自己的,使用負(fù)責(zé)處理它。配置執(zhí)行異步操作需要用到,這個(gè)可以在用方法來(lái)提供相關(guān)文檔。 Spring MVC異步處理簡(jiǎn)介 Github地址 相關(guān)系列文章: Servlet 3.0 異步處理詳解 Servlet 3.1 Async IO分析 本文講到的所有特性皆是基于Servlet...
摘要:本部分示例見(jiàn)這個(gè)項(xiàng)目的分支下的中引進(jìn)了基于異步請(qǐng)求處理的。同時(shí)主容器線(xiàn)程退出釋放并允許處理其他請(qǐng)求。對(duì)的調(diào)用返回,可以被用于異步處理之上的進(jìn)一步控制。 ??本部分示例見(jiàn)這個(gè)項(xiàng)目的 mvc 分支下的 AsyncController.java ??Spring MVC 3.2 中引進(jìn)了基于異步請(qǐng)求處理的 Servlet 3。除了返回一個(gè)值,一個(gè)控制器方法現(xiàn)在可以返回一個(gè)java.util...
摘要:的版本增加了對(duì)事件監(jiān)聽(tīng)程序的支持,事件監(jiān)聽(tīng)程序在建立修改和刪除會(huì)話(huà)或環(huán)境時(shí)得到通知。元素指出事件監(jiān)聽(tīng)程序類(lèi)。過(guò)濾器配置將一個(gè)名字與一個(gè)實(shí)現(xiàn)接口的類(lèi)相關(guān)聯(lián)。 1.簡(jiǎn)介 web.xml文件是Java web項(xiàng)目中的一個(gè)配置文件,主要用于配置歡迎頁(yè)、Filter、Listener、Servlet等,但并不是必須的,一個(gè)java web項(xiàng)目沒(méi)有web.xml文件照樣能跑起來(lái)。Tomcat容器/...
閱讀 3337·2021-11-18 10:02
閱讀 2088·2021-09-22 10:54
閱讀 3037·2019-08-30 15:43
閱讀 2647·2019-08-30 13:22
閱讀 1629·2019-08-29 13:57
閱讀 1115·2019-08-29 13:27
閱讀 805·2019-08-26 14:05
閱讀 2595·2019-08-26 13:30