丨總結(jié)tomcat和jetty的高性能并發(fā)之道_第1頁
丨總結(jié)tomcat和jetty的高性能并發(fā)之道_第2頁
丨總結(jié)tomcat和jetty的高性能并發(fā)之道_第3頁
丨總結(jié)tomcat和jetty的高性能并發(fā)之道_第4頁
丨總結(jié)tomcat和jetty的高性能并發(fā)之道_第5頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

Tomcat和Jetty中用到了大量的高性能、高并發(fā)的設(shè)計,我總結(jié)了幾點(diǎn):I/O和線程模I/O/O模型的本質(zhì)就是為了緩解CPU和外設(shè)之間的速度差。當(dāng)線程發(fā)起I/O請求時,比如讀寫網(wǎng)絡(luò)數(shù)據(jù),網(wǎng)卡數(shù)據(jù)還沒準(zhǔn)備好,這個線程就會被阻塞,讓出CPU,也就是說發(fā)生了線程切換。而線程切換是無用功,并且線程被阻塞后,它持有內(nèi)存資源并沒有釋放,阻塞的線程越多,消耗的內(nèi)存就越大,因此I/O模型的目標(biāo)就是盡量減少線程阻塞。Tomcat和Jety都已經(jīng)拋棄了傳統(tǒng)的同步阻塞I/O,采用了非阻塞/O或者異步/O,目的是業(yè)務(wù)線程不需要阻塞在/O等待上。除了I/O型,線程模型也是影響性能和并發(fā)的關(guān)鍵點(diǎn)。TomcatJetty體處理原則連接請求由專門的Acceptor線程組處理I/O偵測也由專門的Selector線程組來處理具體的協(xié)議解析和業(yè)務(wù)處理可能交給線程池(Tomcat),或者交給Selector程來處將這些事情分開的好處是解耦,并且可以根據(jù)實(shí)際情況合理設(shè)置各部分的線程數(shù)。這里請你注意,線程數(shù)并不是越多越好,因?yàn)镃PU核的個數(shù)有限,線程太多也處理不過來,會導(dǎo)致大量的線程上下文切換。其實(shí)系統(tǒng)調(diào)用是非常耗資源的一個過程,涉及CPU從用戶態(tài)切換到內(nèi)核態(tài)的過程,因此我們在編寫程序的時候要有意識盡量避免系統(tǒng)調(diào)用。比如在TomcatJetty,系統(tǒng)調(diào)用最多的就是網(wǎng)絡(luò)通信操作了,一個Channel上的write就是系統(tǒng)調(diào)用,為了降低系統(tǒng)調(diào)用的次數(shù),最直接的方法就是使用緩沖,當(dāng)輸出數(shù)據(jù)達(dá)到一定的大小才flush緩沖區(qū)。Tomcat和Jetty的Channel都帶有輸入輸出緩沖區(qū)。還有值得一提的是,TomcatJettyHTTP議數(shù)據(jù)時采取了延遲解析的策略,HTTP的請求體(HTTPBody)直到用的時候才解析。也就是說,當(dāng)Tomcat調(diào)用Servlet的service方法時,只是了和解析了HTTP請求頭,并沒有HTTP請求直到你的Web應(yīng)用序調(diào)用了ServletRequest對象的getInputStream方法或者getParameter方法時,Tomcat才會去和解析HTTP請求體中的數(shù)據(jù);這意味著如果你的應(yīng)用序沒有調(diào)用上面那兩個方法,HTTP請求體的數(shù)據(jù)就不會被和解析,這樣就省掉了一次I/O系統(tǒng)調(diào)用。關(guān)于池化和零拷貝,我在專欄前面已經(jīng)詳細(xì)講了它們的原理,你可以回過頭看看專欄第20期和第16期。其實(shí)池化的本質(zhì)就是用內(nèi)存換CPU;而零拷貝就是不做無用功,減少資源我們知道并發(fā)的過中為了同步多個線對共享變量的,需要加鎖來實(shí)現(xiàn)。而鎖的開銷要有意識的盡量避免鎖的使用,比如可以使用原子類CAS或者并發(fā)集合來代替。如果萬不得已需要用到鎖,也要盡量縮小鎖的范圍和鎖的強(qiáng)度。接下來我們來看看Tomcat和Jetty縮小鎖的范縮小鎖的范圍,其實(shí)就是不直接在方法上 synchronized,而是使用細(xì)粒度的對象鎖代1protectedvoidstartInternal()throwsLifecycleException2 4//鎖engine成員if(engine!=null)synchronized(engine) //鎖executors成員synchronized(executors)for(Executorexecutor:executors) //鎖connectors成員變synchronized(connectorsLock)for(Connectorconnector:connectors)//Ifithasalreadyfailed,don'ttryandstartif(connector.getState()!=LifecycleState.FAILED) 30比如上面的代碼是Tomcat的StandardService組件的啟動方法,這個啟動方法要啟動三組件:engine、executors和connectors。它沒有直接在方法上加鎖,而是用了三把細(xì)粒度的鎖,來分別用來鎖三個成員變量。如果直接在方法上加synchronized,多個線執(zhí)行到這個方法時需要排隊(duì);而在對象級別上加synchronized,多個線可以并行執(zhí)行這用原子變量和CAS取代下面的代碼是Jetty線池的啟動方法,它的主要功能就是根據(jù)傳入的參數(shù)啟動相應(yīng)個數(shù)的代privatebooleanstartThreads(int{while(threadsToStart>0&&{//獲取當(dāng)前已經(jīng)啟動的線數(shù),如果已經(jīng)夠了就不需要啟動intthreads=if(threads>=return9//用CAS方法將線數(shù)加一,請注意執(zhí)行失敗走continue,繼續(xù)嘗if pareAndSet(threads,threads+booleanstarted={Threadthread=thread.setName(_name+"-"+_threads.add(thread);//_threads并發(fā)集_lastShrink.set(System.nanoTime());//_lastShrink是原子變started=-- //如果最終線啟動失敗,還需要把線數(shù)減 if return35你可以看到整個函數(shù)的實(shí)現(xiàn)是一個while循環(huán),并且是無鎖的。_threadsStarted表示當(dāng)前線池已經(jīng)啟動了多少個線,它是一個原子變量AtomicInteger,首先通過它的get方法拿到值,如果線數(shù)已經(jīng)達(dá)到最大值,直接返回。否則嘗試用CAS操作將eStd的值加一,如果成功了意味著沒有其他線在改這個值,當(dāng)前線可以繼續(xù)往下執(zhí)行;否則走oie分支,也就是繼續(xù)重試,直到成功為止。在這里當(dāng)然你并發(fā)容器的使CopyOnWriteArrayList適用于讀多寫少的場景,比如Tomcat用它來“存放”器,這是因?yàn)槠饕话阍诔跏蓟^中確定后就基本不會改變,當(dāng)觸發(fā)時需要遍歷這個器列表,所以這個場景符合讀多寫少的特征。代1 classLifecycleBaseimplementsLifecycle23 privatefinalList<LifecycleListener>lifecycleListeners=35 7volatile關(guān)鍵字的使再拿Tomcat中的LifecycleBase作為例子,它里面的生命狀態(tài)就是用volatile關(guān)鍵字修飾的。volatile的目的是為了保證一個線修改了變量,另一個線能夠讀到這種變化。對于生命狀態(tài)來說,需要在各個線中保持是的值,因此采用了volatile修飾。代1 classLifecycleBaseimplementsLifecycle2//當(dāng)前組件的生命狀態(tài),用volatile修privatevolatileLifecycleStatestate=56高性能序能夠高效的利用系統(tǒng)資源,首先就是減少資源浪費(fèi),比如要減少線的阻塞,因?yàn)樽枞麜?dǎo)致資源閑置和線上下文切換,Tomcat和Jetty通過合理的I/O模型和線模另外系統(tǒng)調(diào)用會導(dǎo)致用戶態(tài)和內(nèi)核態(tài)切換的過,Tomcat和Jetty通過緩存和延遲解析盡 取另一種資源,比如Tomcat和Jetty中使用的對象池技術(shù),就是用內(nèi)存換取CPU,將數(shù)據(jù)壓縮后再傳輸就是用CPU換網(wǎng)絡(luò)。此我們在實(shí)際編過中要盡量避免使用鎖,比如可以用原子變量和CAS操作來代替鎖。如果實(shí)在避免不了用鎖,也要盡量減少鎖的范圍和強(qiáng)度,比如可以用細(xì)粒度的對象鎖或者強(qiáng)度的讀寫鎖。Tomcat和Jetty的代碼也很好的實(shí)踐了這一理念今天的文章提到我們要有意識盡量避免系統(tǒng)調(diào)用,那你知道有哪些JavaAPI致系統(tǒng)調(diào)不知道今天的內(nèi)容你消化得如何?如果還有疑問,請大膽的在留言區(qū)提問,也歡迎你的課后思考和心得記錄下來,與我和其他同學(xué)一起討論。如果你覺得今天有所收獲,歡迎你把它給你的朋友。?

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論