tomcat優化

常見的http服務器有apache,nginx,iis,tomcat等。HTTP服務器本質上也是一種應用程序——它通常運行在服務器之上,綁定服務器的IP地址并監聽某一個tcp端口來接收并處理HTTP請求,這樣客戶端(一般來說是IE, Firefox,Chrome這樣的瀏覽器)就能夠通過HTTP協議來獲取服務器上的網頁(HTML格式)、文檔(PDF格式)、音頻(MP4格式)、視頻(MOV格式)等等資源。
??Tomcat運行在JVM之上,它和HTTP服務器一樣,綁定IP地址并監聽TCP端口,同時還包含以下職責:

  • 管理Servlet程序的生命周期。
  • 將URL映射到指定的Servlet進行處理。
  • 與Servlet程序合作處理HTTP請求——根據HTTP請求生成HttpServletResponse對象并傳遞給Servlet進行處理,將Servlet中的HttpServletResponse對象生成的內容返回給瀏覽器。

自己的第一門語言就是java,所以tomcat一直在用,但也基本只是在開發環境用一下,具體的參數也就改過JVM內存,沒做過深入研究,主要還是因為自己工作一直沒有需要去優化過tomcat。
??最近由于工作上的原因,需要對tomcat并發進行優化。在tomcat的server.xml文件中有關于請求連接的配置Connector。本文就具體屬性進行一下說明。

Connector的protocol屬性,三種運行模式(BIO, NIO, APR)
1)BIO:一個線程處理一個請求。缺點:并發量高時,線程數較多,浪費資源。Tomcat7或以下在Linux系統中默認使用這種方式。
2)NIO:利用Java的異步IO處理,可以通過少量的線程處理大量的請求。Tomcat8在Linux系統中默認使用這種方式。Tomcat7必須修改Connector配置來啟動(conf/server.xml配置文件) protocol="org.apache.coyote.http11.Http11NioProtocol"
3)APR(Apache Portable Runtime):從操作系統層面解決io阻塞問題。Linux如果安裝了apr和native,Tomcat直接啟動就支持apr。在Tomcat.7.0.30版本開始,tomcat自帶tcnative-1.dll等文件,windows上默認是運行apr模式。

linux安裝apr和native

apr是比較惡心的一個東東,因為用直接用yum install apr安裝apr后,當再安裝其他東西需要apr環境時候 經常還是找不到,盡管已經安裝它了。需要的幾個環境:
??#yum -y install autoconf // 安裝autoconf
??#yum -y install libtool // 安裝libtool
??#yum -y install openssl openssl-devel // 安裝openssl
這樣的話我們只能通過下面這兩個參數來指定他們的位置了
apr官網下載地址 http://apr.apache.org/download.cgi
安裝apr:
??#tar xvzf apr-1.5.2.tar.gz // 解壓apr-1.5.2.tar.gz
??#cd apr-1.5.2 // 進入apr-1.5.2目錄
??#./configure --prefix=/usr/apr // 指定安裝到/usr/apr目錄
??#make & make install
安裝tomcat-native:
??#cd /usr/tomcat/apache-tomcat-7.0.59/bin // 切換目錄,在tomcat/bin目錄下找到tomcat-native.tar.gz;
??#tar xvzf tomcat-native.tar.gz // 解壓tomcat-native.tar.gz
??#cd /usr/tomcat/apache-tomcat-7.0.59/bin/tomcat-native-1.1.32-src/jni/native // 切換目錄
??#./configure --with-apr=/usr/local/apr --with-java-home=/usr/java/jdk1.8.0_11 --with-ssl=/usr/bin --prefix=/usr/local/apr // 指定之前安裝的目錄
??#make & make install
配置APR本地庫到系統共享庫搜索路徑中
??編輯$TOMCAT_HOME/bin/catalina.sh文件,在虛擬機啟動參數JAVA_OPTS中添加java.library.path參數,指定apr庫的路徑
JAVA_OPTS="$JAVA_OPTS -Djava.library.path=/usr/local/apr/lib"
??Tomcat8以下版本,需要指定運行模式,將protocol從HTTP/1.1改成org.apache.coyote.http11.Http11AprProtocol

這里重點比較一下BIO和NIO,在百度很多文章都是說BIO是一個請求一個線程,NIO可以一個線程服務多個請求。字面意思很清楚,但具體細節卻不是很明白。雖然網上也有測試說明NIO在高并發的時候比BIO性能要好。我也做了一個簡單的實驗。

圖片.png

??這里需要優化的就是網關tomcat,這里的網關tomcat主要起到的作用主要是驗證請求者,然后通過http請求調用后端服務,沒有復雜的業務邏輯處理。后端服務的提供者有很多,圖中只舉例了兩個,各個服務由于業務不同,處理時間也不一樣,有耗時的服務,也有快速返回的服務。網關tomcat如果按照默認的配置,則網關tomcat的服務器數量必須大于等于后端服務中并發量最大的那個服務的機器數量。這就形成了網關tomcat成為了整個系統的一個瓶頸,但網關tomcat只是起到一個網關作用,需要可以像nginx代理服務器那樣可以抗大并發的能力。
??由于后端機器使用的低配置的阿里云,10秒的耗時應用的并發能力不到100,也就是兩臺機器通過nginx負載均衡后200的并發。這里為了測試方便把網關tomcat的maxThreads設置為50。

首先做一個測試比較protocol分別為BIO和NIO時,并發請求耗時應用的情況。

圖片.png

這里測試了三種情況,分別為并發50,并發100,并發200,總請求數都是500,每種情況測試3次。通過圖片數據可以看到BIO和NIO的結果沒有什么區別。NIO并有像描述的那樣一個線程可以處理更多的請求連接。網上也有實驗數據說明NIO確實在并發處理上比BIO效果要好很多,但這個實驗就不行,為什么呢?后來在知乎上的一篇文章上找到了點原因。

圖片.png

這張表格引用自apache-tomcat官方網站,對于connector的三種模式有很好的對比,NIO也不是完全非阻塞(讀body和寫response是模擬阻塞行為)的地方用紅色突出了一下,于header的處理,NIO不會阻塞,只有在body的讀取時,NIO采取模擬阻塞的方式。這是由于servlet規范,tomcat要實現servlet規范所以不能最大發揮NIO的特性。在read http body 以及 response的情況下,即使tomcat選擇 NIO的 connector也是模擬阻塞的行為,因為servlet規范里定義了ServletInputStream在讀數據時是阻塞模式。

關于Wait for next Request
它表示的是當開啟keep-alive的情況下三種模式對等待下一次請求是否阻塞。
在BIO模式下,如果請求是開啟keep-alive的話,socket在請求結束后仍處于OPEN狀態,下一次請求仍可以復用當前socket而不必重新創建,在 finally 塊里會判斷連接狀況如果是keep-alive會再次封裝為同樣的任務提交給線程池,重復這段邏輯,相當于一個循環,只不過每次執行的線程不一定相同。如果socket上已經沒有請求了,最終socket會因超時或客戶端close造成的EOFException而關閉。也就是說在BIO下的keep-alive的請求,只有等到keep-alive超時或者達到maxKeepAliveRequests時才會把線程放回tomcat的線程池,服務其他請求。
在NIO和APR模式下,即使開啟keep-alive,在Wait for next Request時候,這個線程也是可以服務其他請求的。

??看了上面這么多也就知道為什么會出現實驗的效果了,NIO的非阻塞并不能完全解決我這個業務場景,因為即使是NIO下,在read body時也還是阻塞的,而我當前的業務場景是在serlvet中請求服務耗時。servlet的規范ServletInputStream在讀數據時是阻塞模式這一特性是問題根本節點。通過調整maxThreads會是解決這種并發的一個方式。

??在查找上面BIO和NIO比較的時候,我看到有人說到了servlet3.0中有異步serlvet,可以解決serlvet阻塞的問題。于是我使用異步servlet重試了上訴實驗:

圖片.png

通過實驗結果可以看到在NIO下使用異步serlvet確實可以達到想要的效果,tomcat網關在線程數50時也能處理并發200個請求。

AsyncContext asyncContext = request.startAsync();
asyncContext.start();//如果使用start方法,雖然把請求交給了另一個線程,但這個線程還是使用的tomcat的線程。
//這里最好使用一個線程池,為了簡化測試,我直接使用new Thread
 new Thread(new AsyncRequest(asyncContext)).start();//這樣就可以把tomcat的線程還回給tomcat線程池接收新請求了。

Connector的其他屬性
connectionTimeout:網絡連接超時,單位:毫秒。設置為0表示永不超時,通常可設置為20000毫秒。
URIEncoding:指定Tomcat 容器的URL編碼格式。
enableLookups:如果為true,則可以通過調用request.getRemoteHost()進行DNS查詢來得到遠程客戶端的實際主機名,若為false則不進行DNS查詢,而是返回其ip地址。建議設置false,能提高部分性能。
maxThreads:tomcat起動的最大線程數,即同時處理的任務個數,默認值為200
acceptCount:當tomcat起動的線程數達到最大時,接受排隊的請求個數,默認值為100
minSpareThreads:表示即使沒有人使用也開這么多空線程等待
maxConnections:這個貌似應該是新加的參數吧,我沒求證。服務器能接受和處理的最大數量,bio默認是maxThreads的值,nio默認10000,APR/native 默認是8192。
keepAliveTimeout:這個是保持長連接的時間限制,默認就是connectionTimeout設置的時間。

關于keepAlive,tomcat長連接短連接
1.WEB應用有很多,下面就兩個典型的應用(管理頁面和接口服務)做對比。
管理頁面:多涉及到用戶的登錄和長時間的頻繁操作處理,這些操作都集中在一個session中,建議采用長連接;
接口服務:比如常見的webservice,操作集中在很短時間內完成,不需要對session進行維護,建議采用短連接。
HTTP1.1默認采用長連接,需要去掉長連接的話,只需修改默認配置參數maxKeepAliveRequests。把maxKeepAliveRequests="5",意思是每個連接只響應5個請求,然后就shutdown連接.不用等到keepAliveTimeout就關閉這個連接

Apache優化之KeepAlive
1)KeepAlive是在HTTP1.1中定義的,用來保持客戶機和服務器的長連接,通過減少建立TCP Session的次數來提高性能。
2)常用的配置參數有{KeepAlive,KeepAliveTimeout,MaxKeepAliveRequests}
KeepAlive是決定開啟KeepAlive支持;
KeepAliveTimeout決定一 個KeepAlive的連接能保持多少時間,Timeout就盡快shutdown鏈接,若還有數據必須再建立新的連接了;
MaxKeepAliveRequests于KeepAliveTimeout相似,意思是服務多少個請求就shutdown連接。
3)對于KeepAlive的配置需要慎重,錯誤的參數可能導致嚴重的性能問題。
一個高負載的Server,如果建立的很多長連接將無法繼續服 務新的連接。因此需要根據server的性質調整KeepAliveTimeout或是MaxKeepAliveRequests的值。

其他:tomcat內存優化

主要是在bin/catalina.bat或bin/catalina.sh 配置文件中進行。linux上,在catalina.sh中添加:

JAVA_OPTS="-server -Xms1G -Xmx2G -Xss256K -Djava.awt.headless=true -Dfile.encoding=utf-8 -XX:MaxPermSize=256m -XX:PermSize=128M -XX:MaxPermSize=256M"

其中:
? -server:啟用jdk的server版本。
? -Xms:虛擬機初始化時的最小堆內存。
? -Xmx:虛擬機可使用的最大堆內存。
?-Xms與-Xmx設成一樣的值,避免JVM因為頻繁的GC導致性能大起大落
? -XX:PermSize:設置非堆內存初始值,默認是物理內存的1/64。
? -XX:MaxNewSize:新生代占整個堆內存的最大值。
? -XX:MaxPermSize:Perm(俗稱方法區)占整個堆內存的最大值,也稱內存最大永久保留區域。
1)錯誤提示:java.lang.OutOfMemoryError:Java heap space
Tomcat默認可以使用的內存為128MB,在較大型的應用項目中,這點內存是不夠的,有可能導致系統無法運行。常見的問題是報Tomcat內存溢出錯誤,Outof Memory(系統內存不足)的異常,從而導致客戶端顯示500錯誤,一般調整Tomcat的-Xms和-Xmx即可解決問題,通常將-Xms和-Xmx設置成一樣,堆的最大值設置為物理可用內存的最大值的80%。
set JAVA_OPTS=-Xms512m-Xmx512m
2)錯誤提示:java.lang.OutOfMemoryError: PermGenspace
PermGenspace的全稱是Permanent Generationspace,是指內存的永久保存區域,這塊內存主要是被JVM存放Class和Meta信息的,Class在被Loader時就會被放到PermGenspace中,它和存放類實例(Instance)的Heap區域不同,GC(Garbage Collection)不會在主程序運行期對PermGenspace進行清理,所以如果你的應用中有很CLASS的話,就很可能出現PermGen space錯誤,這種錯誤常見在web服務器對JSP進行precompile的時候。如果你的WEB APP下都用了大量的第三方jar, 其大小超過了jvm默認的大小(4M)那么就會產生此錯誤信息了。解決方法:
setJAVA_OPTS=-XX:PermSize=128M
3)在使用-Xms和-Xmx調整tomcat的堆大小時,還需要考慮垃圾回收機制。如果系統花費很多的時間收集垃圾,請減小堆大小。一次完全的垃圾收集應該不超過3-5 秒。如果垃圾收集成為瓶頸,那么需要指定代的大小,檢查垃圾收集的詳細輸出,研究垃圾收集參數對性能的影響。一般說來,你應該使用物理內存的 80% 作為堆大小。當增加處理器時,記得增加內存,因為分配可以并行進行,而垃圾收集不是并行的。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容