[译]GC专家系列4-Apache的MaxClients设置及其对Tomcat Full GC的影响
2
原文鏈接:http://www.cubrid.org/blog/dev-platform/maxclients-in-apache-and-its-effect-on-tomcat-during-full-gc/
本文是GC專家系列中的第四篇。在第一篇理解Java垃圾回收中我們學(xué)習(xí)了幾種不同的GC算法的處理過程,GC的工作方式,新生代與老年代的區(qū)別。所以,你應(yīng)該已經(jīng)了解了JDK 7中的5種GC類型,以及每種GC對性能的影響。
在第二篇Java垃圾回收的監(jiān)控中介紹了在真實場景中JVM是如何運行GC,如何監(jiān)控GC數(shù)據(jù)以及有哪些工具可用來方便進行GC監(jiān)控。
在第三篇GC 調(diào)優(yōu)中基于真實案例介紹了可用于GC調(diào)優(yōu)的最佳選項。同時也描述了如何通過降低移動到老年代中對象的數(shù)量來縮短Full GC耗時,以及如何設(shè)置GC類型及內(nèi)存大小。
本文將介紹Apache的MaxClients參數(shù)的重要性以及在GC發(fā)生時對系統(tǒng)整體性能的顯著影響。通過幾個例子,你將會更清晰的理解MaxClients值所引發(fā)的問題。最后會介紹如何依據(jù)系統(tǒng)的可用內(nèi)存來為MaxClients設(shè)置合理的數(shù)值。
MaxClients對系統(tǒng)的影響
NHN的服務(wù)運行環(huán)境中有大量的流控(Throttle valve)選項,這些選項對系統(tǒng)的穩(wěn)定運行具有重要作用。我們來看下Apache的MaxClients選項在Tomcat發(fā)生Full GC時會對系統(tǒng)帶來哪些影響。
大部分的開發(fā)人員都知道GC 發(fā)生中會伴隨著"stop the world(STW)現(xiàn)象"(具體詳情參考理解Java垃圾回收)。尤其是NHN的Java開發(fā)人員可能都經(jīng)歷過在Tomcat中由GC相關(guān)問題而導(dǎo)致的系統(tǒng)崩潰。因為JVM管理內(nèi)存,因此Java應(yīng)用系統(tǒng)不可避免的會遇到GC引起的STW現(xiàn)象。
在你開發(fā)的線上系統(tǒng)中,GC每天都會發(fā)生很多次。在GC發(fā)生時,即便TTS沒有發(fā)生,卻依然可能會給用戶503的錯誤響應(yīng)。
系統(tǒng)運行環(huán)境
根據(jù)結(jié)構(gòu)特點,Web服務(wù)更適合于做橫向擴展而非單純的提高單一機器的性能。所以通常根據(jù)性能需要,Web服務(wù)的服務(wù)器部署結(jié)構(gòu)由一臺Apache服務(wù)器和多臺Tomcat服務(wù)器組成。在本文中,假設(shè)一個Apache服務(wù)和Tomcat服務(wù)部署在同一臺物理主機上,如下圖所示:
圖1: 本文假設(shè)的服務(wù)運行環(huán)境
作為參考,本文所述參數(shù)均是基于Apache 2.2.21(prefork MPM),Tomcat 6.0.35,jdk 1.6.0_24,并運行在CentOS 4.7.2(32位)操作系統(tǒng)上。
系統(tǒng)內(nèi)存2GB,并使用ParallelOldGC垃圾回收,默認開啟了AdaptiveSizePolicy選項并設(shè)置堆大小為600MB。
STW 和 HTTP 503
假設(shè)Apache的流量為200QPS,并開啟10個httpd處理進程(盡管實際場景依賴于請求的響應(yīng)時間)。在這種前提下,假設(shè)full GC導(dǎo)致的停頓耗時1秒,如果Tomcat發(fā)生了Full GC將會怎么樣?
首先你能想到的是full GC導(dǎo)致Tomcat停頓,處理中的請求將得不到響應(yīng)。如果這樣,Tomcat暫停,請求得不到處理,Apache將會怎么樣?
即使Tomcat因Full GC而暫停處理,而請求卻仍以200 req/s的速度到達Apache。在full GC發(fā)生前,只需要10個或者稍微多一點的httpd進程就可以快速響應(yīng)服務(wù)請求。但是現(xiàn)在Tomcat暫停了,為了處理新的請求Apache將持續(xù)創(chuàng)建新的httpd進程直到httpd.conf文件中定義的MaxClients閥值。因為MaxClients默認值為256,所以200 req/s的請求并不會帶來太大問題。
這個時候,新創(chuàng)建的httpd 進程會怎么樣?
Httpd 進程使用mod_jk模塊管理的AJP連接池中的空閑連接把請求發(fā)送到Tomcat。如果沒有空閑連接,則會要求創(chuàng)建新的連接。然而因為Tomcat處理暫停狀態(tài),新建連接的請求將被拒絕。所以這些請求將會放到堆積隊列(backlog queue),隊列的長度是server.xml的AJP Connector中設(shè)置的。
如果請求數(shù)據(jù)超出了堆積隊列的長度,Apache將會收到連接拒絕錯誤,并把這個錯誤以HTTP 503的方式返回給用戶。
在本例的中,堆積隊列的長度默認設(shè)置為100,而請求速度為200 req/s,因此在由full GC導(dǎo)致Tomcat暫停的這1秒中,將有超過100的請求將會收到503錯誤。
Full GC結(jié)束之后,堆積隊列中的socket連接會被Tomcat接收并分配給工作線程(最大工作線程數(shù)由MaxThreads決定,默認值為200)來處理請求。
MaxClients和堆積隊列
在上面的場景中,如何設(shè)置才能避免給用戶返回503錯誤?
首先我們需要知道,應(yīng)該設(shè)置足夠的堆積隊列長度以容納在Tomcat Full GC導(dǎo)致的暫停期間流入的請求。因此堆積隊列最小長度至少為200(上文中QPS為200)。
這樣配置以后,是否還有其他問題?
把堆積隊列長度設(shè)置為200后,我們再次重復(fù)上面的場景。結(jié)果問題卻比之前更加嚴重。
正常情況下系統(tǒng)內(nèi)存使用量維持在50%,而在發(fā)生Full GC時內(nèi)存使用卻迅速上升到100%,引起內(nèi)存交換區(qū)(swap)使用量的極劇增加。更為嚴重的是Full GC導(dǎo)致的響應(yīng)停頓由原來的1秒增加到了4秒,直接后果就是期間系統(tǒng)像掛掉了一樣,不能響應(yīng)任何請求。
在之前的場景中,只有100左右的請求會收到 503 的錯誤,而增加堆積隊列到200后卻導(dǎo)致了500甚至更多的請求被掛起至少3秒不能收到任何響應(yīng)。
這個例子很好的證明了如果不能準備的理清配置信息之間的因果關(guān)系,可能會對系統(tǒng)帶來極為嚴重的影響。
為什么會這樣?
原理就是要清楚MaxClients選項的特性。
MaxClients的值不易設(shè)置過大,設(shè)置MaxClients的關(guān)鍵在于即便創(chuàng)建了MaxClients數(shù)量的httpd進程,也要需要維持應(yīng)用系統(tǒng)的內(nèi)存使用量不應(yīng)超過80%。
系統(tǒng)交換區(qū)默認值為60,因此如果內(nèi)存使用超過80%,系統(tǒng)將會發(fā)生頻繁的內(nèi)存交換。
我們再來看下為什么這個特性會導(dǎo)致上面所述的嚴重后果。
當請求的QPS為200時,Tomcat會被Full GC暫停響應(yīng),然后把堆積列隊容量設(shè)置為200。起初大約有100個額外的httpd 進程會被Apache創(chuàng)建,緊接著內(nèi)存使用量超過了80%,引起操作系統(tǒng)主動的使用交換區(qū)的內(nèi)存空間,而因GC存活在JVM老年代中的對象被操作系統(tǒng)誤認為長時間未使用,從而導(dǎo)致這些對象被移動到交換區(qū)。
最后,當GC過程中涉及到交換區(qū)時,耗時就會迅速增加。而后httpd進程數(shù)繼續(xù)增加,導(dǎo)致內(nèi)存使用量達到了100%,從而出現(xiàn)了上述的嚴重后果。
上述案例的前后區(qū)別僅在于堆積隊列的長度:100和200。但為什么在200時會出現(xiàn)更嚴重的狀況?
原因是堆積隊列不同的長度導(dǎo)致了httpd進程數(shù)的不同。當值為100時,在發(fā)生Full GC時100個請求所要求創(chuàng)建的連接被置于堆積隊列中。再有新的請求會被拒絕并返回503錯誤,所以系統(tǒng)的整個httpd的進程數(shù)僅超出100很少的數(shù)量。
但當隊列長度設(shè)置為200時,有200個請求被接收并置于隊列中。從而導(dǎo)致httpd進程的數(shù)量超過200,并觸發(fā)了操作系統(tǒng)進行內(nèi)存交換的閥值。
所以,如果不顧內(nèi)存使用情況而一味的加大MaxClients的數(shù)值,將會導(dǎo)致Full GC時httpd進程數(shù)迅速增加,引進內(nèi)存交換并最終降低系統(tǒng)的整體性能。
所以如何設(shè)置MaxClients,如何找到當前系統(tǒng)的閥值?
MaxClients 取值的計算方式
如果系統(tǒng)總內(nèi)存為2GB,設(shè)置MaxClient的值需要保證在任何時候內(nèi)存的使用量不超過80%即1.6GB,從而避免因內(nèi)存交換導(dǎo)致的性能下降。也就是說僅有1.6GB空間供Apache, Tomcat和其他默認安裝的代理程序共享和分配內(nèi)存。
假如默認安裝的代理程序占用200M內(nèi)存;Tomcat的堆空間設(shè)置-Xmx為600M,如下圖所示,Tomcat總占用量將725M (持久代 + 本地堆空間)。Apache可使用的空間為剩下的700M。
圖 2:Top命令的截圖
對于Apache的700M內(nèi)存,該如何設(shè)置合理的MaxClients值?
當然這也取決于Apache加載的模塊類型和數(shù)量。以NHN的Web服務(wù)為例,把Apache當作簡單的代理使用,根據(jù)上圖RES顯示,4M空間對于每個httpd進程來說已足夠使用。因此700M空間能設(shè)置的MaxClients為175。
總結(jié)
可靠的服務(wù)配置要能夠在滿載的情況下降低系統(tǒng)停頓時間并能夠最大范圍的保證成功響應(yīng)用戶請求。對于Java應(yīng)用來說,必須要確認在Full GC引起的SWT情況下,系統(tǒng)的配置是否能夠提供足夠可靠的服務(wù)。
如果為了應(yīng)對單純的請求增加和防止DDos攻擊,在不考慮內(nèi)存使用的情況下把MaxClients設(shè)置過大,那么MaxClients不但會失去作為流控的用途,反而會帶來更為嚴重的后果。
在這個案例中,解決問題的最優(yōu)途徑是加大系統(tǒng)的內(nèi)存,或者設(shè)置MaxClients為175(上面的計算結(jié)果)以保證只有QPS超過175時才會出現(xiàn)503錯誤。
2原文鏈接:http://www.cubrid.org/blog/dev-platform/maxclients-in-apache-and-its-effect-on-tomcat-during-full-gc/
本文是GC專家系列中的第四篇。在第一篇理解Java垃圾回收中我們學(xué)習(xí)了幾種不同的GC算法的處理過程,GC的工作方式,新生代與老年代的區(qū)別。所以,你應(yīng)該已經(jīng)了解了JDK 7中的5種GC類型,以及每種GC對性能的影響。
在第二篇Java垃圾回收的監(jiān)控中介紹了在真實場景中JVM是如何運行GC,如何監(jiān)控GC數(shù)據(jù)以及有哪些工具可用來方便進行GC監(jiān)控。
在第三篇GC 調(diào)優(yōu)中基于真實案例介紹了可用于GC調(diào)優(yōu)的最佳選項。同時也描述了如何通過降低移動到老年代中對象的數(shù)量來縮短Full GC耗時,以及如何設(shè)置GC類型及內(nèi)存大小。
本文將介紹Apache的MaxClients參數(shù)的重要性以及在GC發(fā)生時對系統(tǒng)整體性能的顯著影響。通過幾個例子,你將會更清晰的理解MaxClients值所引發(fā)的問題。最后會介紹如何依據(jù)系統(tǒng)的可用內(nèi)存來為MaxClients設(shè)置合理的數(shù)值。
MaxClients對系統(tǒng)的影響
NHN的服務(wù)運行環(huán)境中有大量的流控(Throttle valve)選項,這些選項對系統(tǒng)的穩(wěn)定運行具有重要作用。我們來看下Apache的MaxClients選項在Tomcat發(fā)生Full GC時會對系統(tǒng)帶來哪些影響。
大部分的開發(fā)人員都知道GC 發(fā)生中會伴隨著"stop the world(STW)現(xiàn)象"(具體詳情參考理解Java垃圾回收)。尤其是NHN的Java開發(fā)人員可能都經(jīng)歷過在Tomcat中由GC相關(guān)問題而導(dǎo)致的系統(tǒng)崩潰。因為JVM管理內(nèi)存,因此Java應(yīng)用系統(tǒng)不可避免的會遇到GC引起的STW現(xiàn)象。
在你開發(fā)的線上系統(tǒng)中,GC每天都會發(fā)生很多次。在GC發(fā)生時,即便TTS沒有發(fā)生,卻依然可能會給用戶503的錯誤響應(yīng)。
系統(tǒng)運行環(huán)境
根據(jù)結(jié)構(gòu)特點,Web服務(wù)更適合于做橫向擴展而非單純的提高單一機器的性能。所以通常根據(jù)性能需要,Web服務(wù)的服務(wù)器部署結(jié)構(gòu)由一臺Apache服務(wù)器和多臺Tomcat服務(wù)器組成。在本文中,假設(shè)一個Apache服務(wù)和Tomcat服務(wù)部署在同一臺物理主機上,如下圖所示:
圖1: 本文假設(shè)的服務(wù)運行環(huán)境
作為參考,本文所述參數(shù)均是基于Apache 2.2.21(prefork MPM),Tomcat 6.0.35,jdk 1.6.0_24,并運行在CentOS 4.7.2(32位)操作系統(tǒng)上。
系統(tǒng)內(nèi)存2GB,并使用ParallelOldGC垃圾回收,默認開啟了AdaptiveSizePolicy選項并設(shè)置堆大小為600MB。
STW 和 HTTP 503
假設(shè)Apache的流量為200QPS,并開啟10個httpd處理進程(盡管實際場景依賴于請求的響應(yīng)時間)。在這種前提下,假設(shè)full GC導(dǎo)致的停頓耗時1秒,如果Tomcat發(fā)生了Full GC將會怎么樣?
首先你能想到的是full GC導(dǎo)致Tomcat停頓,處理中的請求將得不到響應(yīng)。如果這樣,Tomcat暫停,請求得不到處理,Apache將會怎么樣?
即使Tomcat因Full GC而暫停處理,而請求卻仍以200 req/s的速度到達Apache。在full GC發(fā)生前,只需要10個或者稍微多一點的httpd進程就可以快速響應(yīng)服務(wù)請求。但是現(xiàn)在Tomcat暫停了,為了處理新的請求Apache將持續(xù)創(chuàng)建新的httpd進程直到httpd.conf文件中定義的MaxClients閥值。因為MaxClients默認值為256,所以200 req/s的請求并不會帶來太大問題。
這個時候,新創(chuàng)建的httpd 進程會怎么樣?
Httpd 進程使用mod_jk模塊管理的AJP連接池中的空閑連接把請求發(fā)送到Tomcat。如果沒有空閑連接,則會要求創(chuàng)建新的連接。然而因為Tomcat處理暫停狀態(tài),新建連接的請求將被拒絕。所以這些請求將會放到堆積隊列(backlog queue),隊列的長度是server.xml的AJP Connector中設(shè)置的。
如果請求數(shù)據(jù)超出了堆積隊列的長度,Apache將會收到連接拒絕錯誤,并把這個錯誤以HTTP 503的方式返回給用戶。
在本例的中,堆積隊列的長度默認設(shè)置為100,而請求速度為200 req/s,因此在由full GC導(dǎo)致Tomcat暫停的這1秒中,將有超過100的請求將會收到503錯誤。
Full GC結(jié)束之后,堆積隊列中的socket連接會被Tomcat接收并分配給工作線程(最大工作線程數(shù)由MaxThreads決定,默認值為200)來處理請求。
MaxClients和堆積隊列
在上面的場景中,如何設(shè)置才能避免給用戶返回503錯誤?
首先我們需要知道,應(yīng)該設(shè)置足夠的堆積隊列長度以容納在Tomcat Full GC導(dǎo)致的暫停期間流入的請求。因此堆積隊列最小長度至少為200(上文中QPS為200)。
這樣配置以后,是否還有其他問題?
把堆積隊列長度設(shè)置為200后,我們再次重復(fù)上面的場景。結(jié)果問題卻比之前更加嚴重。
正常情況下系統(tǒng)內(nèi)存使用量維持在50%,而在發(fā)生Full GC時內(nèi)存使用卻迅速上升到100%,引起內(nèi)存交換區(qū)(swap)使用量的極劇增加。更為嚴重的是Full GC導(dǎo)致的響應(yīng)停頓由原來的1秒增加到了4秒,直接后果就是期間系統(tǒng)像掛掉了一樣,不能響應(yīng)任何請求。
在之前的場景中,只有100左右的請求會收到 503 的錯誤,而增加堆積隊列到200后卻導(dǎo)致了500甚至更多的請求被掛起至少3秒不能收到任何響應(yīng)。
這個例子很好的證明了如果不能準備的理清配置信息之間的因果關(guān)系,可能會對系統(tǒng)帶來極為嚴重的影響。
為什么會這樣?
原理就是要清楚MaxClients選項的特性。
MaxClients的值不易設(shè)置過大,設(shè)置MaxClients的關(guān)鍵在于即便創(chuàng)建了MaxClients數(shù)量的httpd進程,也要需要維持應(yīng)用系統(tǒng)的內(nèi)存使用量不應(yīng)超過80%。
系統(tǒng)交換區(qū)默認值為60,因此如果內(nèi)存使用超過80%,系統(tǒng)將會發(fā)生頻繁的內(nèi)存交換。
我們再來看下為什么這個特性會導(dǎo)致上面所述的嚴重后果。
當請求的QPS為200時,Tomcat會被Full GC暫停響應(yīng),然后把堆積列隊容量設(shè)置為200。起初大約有100個額外的httpd 進程會被Apache創(chuàng)建,緊接著內(nèi)存使用量超過了80%,引起操作系統(tǒng)主動的使用交換區(qū)的內(nèi)存空間,而因GC存活在JVM老年代中的對象被操作系統(tǒng)誤認為長時間未使用,從而導(dǎo)致這些對象被移動到交換區(qū)。
最后,當GC過程中涉及到交換區(qū)時,耗時就會迅速增加。而后httpd進程數(shù)繼續(xù)增加,導(dǎo)致內(nèi)存使用量達到了100%,從而出現(xiàn)了上述的嚴重后果。
上述案例的前后區(qū)別僅在于堆積隊列的長度:100和200。但為什么在200時會出現(xiàn)更嚴重的狀況?
原因是堆積隊列不同的長度導(dǎo)致了httpd進程數(shù)的不同。當值為100時,在發(fā)生Full GC時100個請求所要求創(chuàng)建的連接被置于堆積隊列中。再有新的請求會被拒絕并返回503錯誤,所以系統(tǒng)的整個httpd的進程數(shù)僅超出100很少的數(shù)量。
但當隊列長度設(shè)置為200時,有200個請求被接收并置于隊列中。從而導(dǎo)致httpd進程的數(shù)量超過200,并觸發(fā)了操作系統(tǒng)進行內(nèi)存交換的閥值。
所以,如果不顧內(nèi)存使用情況而一味的加大MaxClients的數(shù)值,將會導(dǎo)致Full GC時httpd進程數(shù)迅速增加,引進內(nèi)存交換并最終降低系統(tǒng)的整體性能。
所以如何設(shè)置MaxClients,如何找到當前系統(tǒng)的閥值?
MaxClients 取值的計算方式
如果系統(tǒng)總內(nèi)存為2GB,設(shè)置MaxClient的值需要保證在任何時候內(nèi)存的使用量不超過80%即1.6GB,從而避免因內(nèi)存交換導(dǎo)致的性能下降。也就是說僅有1.6GB空間供Apache, Tomcat和其他默認安裝的代理程序共享和分配內(nèi)存。
假如默認安裝的代理程序占用200M內(nèi)存;Tomcat的堆空間設(shè)置-Xmx為600M,如下圖所示,Tomcat總占用量將725M (持久代 + 本地堆空間)。Apache可使用的空間為剩下的700M。
圖 2:Top命令的截圖
對于Apache的700M內(nèi)存,該如何設(shè)置合理的MaxClients值?
當然這也取決于Apache加載的模塊類型和數(shù)量。以NHN的Web服務(wù)為例,把Apache當作簡單的代理使用,根據(jù)上圖RES顯示,4M空間對于每個httpd進程來說已足夠使用。因此700M空間能設(shè)置的MaxClients為175。
總結(jié)
可靠的服務(wù)配置要能夠在滿載的情況下降低系統(tǒng)停頓時間并能夠最大范圍的保證成功響應(yīng)用戶請求。對于Java應(yīng)用來說,必須要確認在Full GC引起的SWT情況下,系統(tǒng)的配置是否能夠提供足夠可靠的服務(wù)。
如果為了應(yīng)對單純的請求增加和防止DDos攻擊,在不考慮內(nèi)存使用的情況下把MaxClients設(shè)置過大,那么MaxClients不但會失去作為流控的用途,反而會帶來更為嚴重的后果。
在這個案例中,解決問題的最優(yōu)途徑是加大系統(tǒng)的內(nèi)存,或者設(shè)置MaxClients為175(上面的計算結(jié)果)以保證只有QPS超過175時才會出現(xiàn)503錯誤。
總結(jié)
以上是生活随笔為你收集整理的[译]GC专家系列4-Apache的MaxClients设置及其对Tomcat Full GC的影响的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [译]GC专家系列3-GC调优
- 下一篇: 聊聊JVM(十)Mac下hsdis和ji