Tomcat是咱們常用的 servlet容器之一,甚至不少線上產品都使用 Tomcat充當服務器。並且優化後的Tomcat性能提高顯著,本文從如下幾方面進行分析優化。html
1、內存優化java
默認狀況下Tomcat的相關內存配置較低,這對於一些大型項目顯然是不夠用的,這些項目運行就已經耗費了大部份內存空間,況且大規模訪問的狀況。即便是本文中的這個只有一個頁面的超小項目,在併發達到必定程度後也會拋出如下相似異常:web
1.修改內存等 JVM相關配置正則表達式
Linux下修改TOMCAT_HOME/bin/catalina.sh,在其中加入,能夠放在CLASSPATH=下面:shell
windows下修改TOMCAT_HOME/bin/catalina.bat,在其中加入,能夠放在set CLASSPATH=下面:數據庫
-server:啓用 JDK的 server 版本;apache
-Xms:Java虛擬機初始化時堆的最小內存,通常與 Xmx配置爲相同值,這樣的好處是GC沒必要再爲擴展內存空間而消耗性能;編程
-Xmx:Java虛擬機可以使用堆的最大內存;windows
-XX:PermSize:Java虛擬機永久代大小;緩存
-XX:MaxPermSize:Java虛擬機永久代大小最大值;
除了這些參數外您還能夠根據具體須要配置其餘參數,參數的配置能夠參考JVM參數的配置
2.驗證
設置成功後咱們能夠利用JDK自帶的工具進行驗證,這些工具都在JAVA_HOME/bin目錄下:
1)jps:用來顯示本地的java進程,以及進程號,進程啓動的路徑等。
2)jmap:觀察運行中的JVM 物理內存的佔用狀況,包括Heap size , Perm size 下載地址 等。
進入命令行模式後,進入JAVA_HOME/bin目錄下,而後輸入jps命令:
其中 Bootstrap進程就是咱們啓動了的 Tomcat,其進程號爲2340.
而後咱們利用 jmap工具查看其內存相關配置:
從結果就能夠看出咱們的配置已經成功了。
2、配置優化
咱們知道TOMCAT_HOME/conf/server.xml能夠配置端口,虛擬路徑等等 Tomcat相關主要配置。
1.Connector 優化
Connector是鏈接器,負責接收客戶的請求,以及向客戶端回送響應的消息。因此 Connector的優化是重要部分。默認狀況下 Tomcat只支持200線程訪問,超過這個數量的鏈接將被等待甚至超時放棄,因此咱們須要提升這方面的處理能力。
修改這部分配置須要修改TOMCAT_HOME/conf/server.xml,打開server.xml找到Connector 標籤項,默認配置以下:
其中port表明服務接口;protocol表明協議類型;connectionTimeout表明鏈接超時時間,單位爲毫秒;redirectPort表明安全通訊(https)轉發端口,通常配置成443。
能夠看到除了這幾個基本配置外並沒有特殊功能,因此咱們須要對 Connector 進行擴展。
其中Connector 支持參數屬性能夠參考Tomcat官方網站(https://tomcat.apache.org/tomcat-8.0-doc/config/http.html),很是多,因此本文就只介紹些經常使用的。
咱們將 Connector 配置修改成以下:
1)port:表明Tomcat監聽端口,也就是網站的訪問端口,默認爲8080,能夠根據須要改爲其餘。
2)protocol:協議類型,可選類型有四種,分別爲BIO(阻塞型IO),NIO,NIO2和APR。
(1)BIO:BIO(Blocking I/O),顧名思義,即阻塞式I/O操做,表示Tomcat使用的是傳統的Java I/O操做(即java.io包及其子包)。Tomcat在默認狀況下,是以bio模式運行的。遺憾的是,就通常而言,bio模式是三種運行模式中性能最低的一種。BIO配置採用默認便可。
(2)NIO:NIO(New I/O),是Java SE 1.4及後續版本提供的一種新的I/O操做方式(即java.nio包及其子包)。Java nio是一個基於緩衝區、並能提供非阻塞I/O操做的Java API,所以nio也被當作是non-blocking I/O的縮寫。它擁有比傳統I/O操做(bio)更好的併發運行性能。要讓Tomcat以nio模式來運行也比較簡單,咱們只須要protocol類型修改成:
便可。
(3)APR:APR(Apache Portable Runtime/Apache可移植運行時),是Apache HTTP服務器的支持庫。你能夠簡單地理解爲:Tomcat將以JNI的形式調用 Apache HTTP服務器的核心動態連接庫來處理文件讀取或網絡傳輸操做,從而大大地提升 Tomcat對靜態文件的處理性能。
與配置 NIO運行模式同樣,也須要將對應的 Connector節點的 protocol屬性值改成:
相關APR介紹及配置會在下面專門講。
3)maxThreads:由該鏈接器建立的處理請求線程的最大數目,也就是能夠處理的同時請求的最大數目。若是未配置默認值爲200。若是一個執行器與此鏈接器關聯,則忽略此屬性,由於該屬性將被忽略,因此該鏈接器將使用執行器而不是一個內部線程池來執行任務。
maxThreads是一個重要的配置屬性,maxThreads配置的合理直接影響了Tomcat的相關性能,因此這裏咱們重點討論下。
maxThreads並非配置的越大越好,事實上你即便配置成999999也是沒有用的,由於這個最大值是受操做系統及相關硬件所制約的,而且最大值並不必定是最優值,因此咱們追尋的應該是最優值而不是最大值。
QPS(Query Per Second):每秒查詢率QPS是對一個特定的查詢服務器在規定時間內所處理流量多少的衡量標準。咱們經常使用 QPS值來衡量一個服務器的性能。
QPS = 併發數 / 平均響應時間
或者
併發數 = QPS * 平均響應時間
一個系統吞吐量一般由QPS、併發數兩個因素決定,每套系統的這兩個值都有一個相對極限值,在應用場景訪問壓力下,只要某一項達到系統最高值,系統的吞吐量就上不去了,若是壓力繼續增大,系統的吞吐量反而會降低,緣由是系統超負荷工做,上下文切換、內存等等其它消耗致使系統性能降低。所謂吞吐量這裏能夠理解爲每秒能處理請求的次數。
因此選擇一個合理的 maxThreads值,其實並非那麼容易的事。由於過多的線程只會形成,更多的內存開銷,更多的CPU開銷,可是對提高QPS確毫無幫助;找到最佳線程數後經過簡單的設置,可讓web系統更加穩定,獲得最高,最穩定的QPS輸出。
咱們能夠經過如下幾種方式來獲取 maxThreads的最佳值:
(1)經過線上系統不斷使用和用戶的不斷增加來進行性能測試,觀察QPS,響應時間,這種方式會在爆發式增加時系統崩潰,如雙12等。
(2)根據公式計算,服務器端最佳線程數量=((線程等待時間+線程cpu時間)/線程cpu時間) * cpu數量,這種方式有時會被誤導,由於某些系統處理環節可能會耗時比較長,從而影響公式的結果。
(3)單、多用戶壓力測試,查看CPU的消耗,而後直接乘以百分比,再進行壓測,通常這個值的附近應該就是最佳線程數量,這種方式理想場景比較適用,實際狀況會比這個複雜的多。
(4)根據系統的自身狀況調整,如硬件限制,系統限制,程序處理能力限制等。
(5)按期修改成不一樣的 maxThreads值,看服務器響應結果及用戶反應。
QPS和線程數的關係
(1)在最佳線程數量以前,QPS和線程是互相遞增的關係,線程數量到了最佳線程以後,QPS持平,不在上升,甚至略有降低,同時相應時間持續上升。
(2)同一個系統而言,支持的線程數越多(最佳線程數越多而不是配置的線程數越多),QPS越高。
QPS和響應時間的關係
(1)對於通常的web系統,響應時間通常有CPU執行時間+IO等待時間組成。
(2)CPU的執行時間減小,對QPS有實質的提高,IO時間的減小,對QPS提高不明顯。若是要想明顯提高QPS,優化系統的時候要着重優化CPU消耗大戶。
因此想要找出 maxThreads的最優值可並不容易,沒有最好只有更好,更好的值只能經過時間來顯現,若是你不想考慮那麼多,通常狀況下設置成1000便可。
4)minSpareThreads:線程的最小運行數目,這些始終保持運行。若是未指定,默認值爲10。
5)acceptCount:當全部可能的請求處理線程都在使用時傳入鏈接請求的最大隊列長度。若是未指定,默認值爲100。通常是設置的跟 maxThreads同樣或一半,此值設置的過大會致使排隊的請求超時而未被處理。因此這個值應該是主要根據應用的訪問峯值與平均值來權衡配置。
6)maxConnections:在任何給定的時間內,服務器將接受和處理的最大鏈接數。當這個數字已經達到時,服務器將接受但不處理,等待進一步鏈接。NIO與NIO2的默認值爲10000,APR默認值爲8192。
7)connectionTimeout:當請求已經被接受,但未被處理,也就是等待中的超時時間。單位爲毫秒,默認值爲60000。一般狀況下設置爲30000。
8)maxHttpHeaderSize:請求和響應的HTTP頭的最大大小,以字節爲單位指定。若是沒有指定,這個屬性被設置爲8192(8 KB)。
9)tcpNoDelay:若是爲true,服務器socket會設置TCP_NO_DELAY選項,在大多數狀況下能夠提升性能。缺省狀況下設爲true。
10)compression:是否啓用gzip壓縮,默認爲關閉狀態。這個參數的可接受值爲「off」(不使用壓縮),「on」(壓縮文本數據),「force」(在全部的狀況下強制壓縮)。
11)compressionMinSize:若是compression="on",則啓用此項。被壓縮前數據的最小值,也就是超過這個值後才被壓縮。若是沒有指定,這個屬性默認爲「2048」(2K),單位爲byte。
12)disableUploadTimeout:這個標誌容許servlet Container在一個servlet執行的時候,使用一個不一樣的,更長的鏈接超時。最終的結果是給servlet更長的時間以便完成其執行,或者在數據上載的時候更長的超時時間。若是沒有指定,設爲false。
13)enableLookups:關閉DNS反向查詢。
14)URIEncoding:URL編碼字符集。
Connector 還有不少其餘參數,能夠參考Tomcat官網,這裏只介紹與性能相關的部分。
2.BIO、NIO、APR
經過配置 protocol的類型可使用不一樣的 Connector處理請求。
如下是幾種類型 Connector的參數對比:
並非說 BIO的性能就必定不如 NIO,這幾種類型 Connector之間並無明顯的性能區別,它們之間實現流程和原理不一樣,因此它們的選擇是須要根據應用的類型來決定的。
BIO更適合處理簡單流程,如程序處理較快能夠當即返回結果。簡單項目及應用能夠採用BIO。
NIO更適合後臺須要耗時完成請求的操做,如程序接到了請求後須要比較耗時的處理這已請求,因此沒法當即返回結果,這樣若是採用BIO就會佔用一個鏈接,而使用NIO後就能夠將此鏈接轉讓給其餘請求,直至程序處理完成返回爲止。
APR能夠大大提高Tomcat對靜態文件的處理性能,同時若是你使用了HTTPS方式傳輸的話,也能夠提高SSL的處理性能。
本文的最後會對幾種 Connector進行對比測試。
3.線程池
Executor表明了一個線程池,能夠在Tomcat組件之間共享。使用線程池的好處在於減小了建立銷燬線程的相關消耗,並且能夠提升線程的使用效率。
要想使用線程池,首先須要在 Service標籤中配置 Executor,以下:
name:線程池名稱,用於 Connector中指定。
namePrefix:所建立的每一個線程的名稱前綴,一個單獨的線程名稱爲 namePrefix+threadNumber。
maxThreads:池中最大線程數。
minSpareThreads:活躍線程數,也就是核心池線程數,這些線程不會被銷燬,會一直存在。
maxIdleTime:線程空閒時間,超過該時間後,空閒線程會被銷燬,默認值爲6000(1分鐘),單位毫秒。
maxQueueSize:在被執行前最大線程排隊數目,默認爲Int的最大值,也就是廣義的無限。除非特殊狀況,這個值不須要更改,不然會有請求不會被處理的狀況發生。
prestartminSpareThreads:啓動線程池時是否啓動 minSpareThreads部分線程。默認值爲false,即不啓動。
threadPriority:線程池中線程優先級,默認值爲5,值從1到10。
className:線程池實現類,未指定狀況下,默認實現類爲org.apache.catalina.core.StandardThreadExecutor。若是想使用自定義線程池首先須要實現 org.apache.catalina.Executor接口。
線程池配置完成後須要在 Connector中指定:
4.Listener
另外一個影響Tomcat 性能的因素是內存泄露。Server標籤中能夠配置多個Listener,其中 JreMemoryLeakPreventionListener是用來預防JRE內存泄漏。此Listener只需在Server標籤中配置便可,默認狀況下無需配置,已經添加在 Server中。
3、組件優化
1.APR
以前一直都在說APR,那麼APR到底能給咱們帶來什麼?這節就開始學習APR相關知識。
APR(Apache Portable Runtime)是一個高可移植庫,它是Apache HTTP Server 2.x的核心。APR有不少用途,包括訪問高級 IO功能(例如sendfile,epoll和OpenSSL),OS級別功能(隨機數生成,系統狀態等等),本地進程管理(共享內存,NT管道和UNIX sockets)。這些功能可使Tomcat做爲一個一般的前臺WEB服務器,能更好地和其它本地web技術集成,整體上讓Java更有效率做爲一個高性能web服務器平臺而不是簡單做爲後臺容器。
APR的目的如其名稱同樣,主要爲上層的應用程序提供一個能夠跨越多操做系統平臺使用的底層支持接口庫。在早期的Apache版本中,應用程序自己必須可以處理各類具體操做系統平臺的細節,並針對不一樣的平臺調用不一樣的處理函數。隨着Apache的進一步開發,Apache組織決定將這些通用的函數獨立出來並發展成爲一個新的項目。這樣,APR的開發就從Apache中獨立出來,Apache僅僅是使用APR而已。目前APR主要仍是由Apache使用,不過因爲APR的較好的移植性,所以一些須要進行移植的C程序也開始使用APR。
APR使得平臺細節的處理進行下移。對於應用程序而言,它們根本就不須要考慮具體的平臺,無論是Unix、Linux仍是Window,應用程序執行的接口基本都是統一一致的。所以對於APR而言,可移植性和統一的上層接口是其考慮的一個重點。而APR最先的目的並非如此,它最先只是但願將Apache中用到的全部代碼合併爲一個通用的代碼庫,然而這不是一個正確的策略,所以後來APR改變了其目標。有的時候使用公共代碼並非一件好事,好比如何將一個請求映射到線程或者進程是平臺相關的,所以僅僅一個公共的代碼庫並不能完成這種區分。APR的目標則是但願安全合併全部的可以合併的代碼而不須要犧牲性能。
(1)下載
APR沒有二進制包能夠下載,因此只能下載源代碼版,下載後須要構建,須要下載的文件有:apr-1.5.2.tar.gz、apr-iconv-1.2.1.tar.gz、apr-util-1.5.4.tar.gz(Linux版爲例)這三個。
APR的官網爲:http://apr.apache.org/
(2)安裝
windows下構建源代碼比較麻煩,須要Visual Studio支持。
Linux下構建就相對簡單和熟悉了,只須要執行常規構建命令便可:
安裝成功後,APR會默認安裝在 /usr/local/apr目錄下,也能夠指定安裝目錄。
apr-iconv安裝時須要指定apr的安裝位置:
apr-util安裝時須要指定apr的安裝位置:
安裝完成後目錄結構:
安裝完成後實際上是沒法直接使用APR的,想使用APR還須要安裝Tomcat Native,不然Tomcat啓動時會報如下錯誤:
2.Tomcat Native
Tomcat Native是 Tomcat可選組件,它可讓 Tomcat使用 Apache 的 APR包來處理包括文件和網絡IO操做,從而提高性能及兼容性。
1)下載
Tomcat Native能夠選擇Windows與Linux版本下載。
Tomcat Native下載地址爲:http://tomcat.apache.org/download-native.cgi
2)安裝
(1)Linux/Unix下
安裝Tomcat Native前須要安裝如下組件:
• APR library(咱們已安裝)
• OpenSSL libraries
• Java SE Development Kit (JDK)(也已安裝)
OpenSSL libraries安裝經過如下命令:
安裝成功後就能夠安裝Tomcat Native了,運行如下命令下載地址:
注意,--prefix指向的是 Tomcat目錄。
注意,下載後的 Tomcat Native解壓後目錄結構以下:
安裝時須要進入native目錄。
安裝過程當中還有可能產生依賴包版本不兼容的問題(通常爲openssl版本太低),這時須要卸載舊的依賴,並安裝最新版本
當安裝完成後出現如下相似輸出時,說明安裝已經成功:
(2)Windows下
Windows下安裝就異常簡單了,只須要把bin目錄下文件複製到tomcat/bin下便可,若是爲64位,則複製x64中文件下載地址。
3)使用
(1)環境變量配置
使用前須要配置環境變量:
打開配置文件後,添加如下內容:
退出保存,而後執行:
(2)修改Tomcat配置文件
打開conf/server.xml文件,修改Connector 標誌的protocol屬性:
而後添加Listener:
保存配置文件後,啓動Tomcat,從日誌中看到如下輸出時,說明所有功能都已配置成功:
至此,APR與 Native都已安裝完成,可使用,對於 APR與 Native還有不少知識要學習,但不是本文的重點,因此之後有機會還會深刻學習。
4、性能測試
Tomcat優化部分咱們已經完成,接下來就須要比較一下優化前與優化後的性能對比。
1.Jmeter
Apache JMeter是Apache組織開發的基於Java的壓力測試工具。用於對軟件作壓力測試,它最初被設計用於Web應用測試,但後來擴展到其餘測試領域。 它能夠用於測試靜態和動態資源,例如靜態文件、Java 小服務程序、CGI 腳本、Java 對象、數據庫、FTP 服務器, 等等。JMeter 能夠用於對服務器、網絡或對象模擬巨大的負載,來自不一樣壓力類別下測試它們的強度和分析總體性能。另外,JMeter可以對應用程序作功能/迴歸測試,經過建立帶有斷言的腳原本驗證你的程序返回了你指望的結果。爲了最大限度的靈活性,JMeter容許使用正則表達式建立斷言。
Apache jmeter 能夠用於對靜態的和動態的資源(文件,Servlet,Perl腳本,java 對象,數據庫和查詢,FTP服務器等等)的性能進行測試。它能夠用於對服務器、網絡或對象模擬繁重的負載來測試它們的強度或分析不一樣壓力類型下的總體性能。你可使用它作性能的圖形分析或在大併發負載測試你的服務器/腳本/對象。
Jmeter官網:http://jmeter.apache.org/
1)JMeter的做用
(1)可以對HTTP和FTP服務器進行壓力和性能測試, 也能夠對任何數據庫進行一樣的測試(經過JDBC),Jmeter支持如下服務器協議類型測試:
• Web - HTTP, HTTPS
• SOAP / REST
• FTP
• Database via JDBC
• LDAP
• Message-oriented middleware (MOM) via JMS
• Mail - SMTP(S), POP3(S) and IMAP(S)
• MongoDB (NoSQL)
• Native commands or shell scripts
• TCP
(2)徹底的可移植性和100% 純java。
(3)徹底 Swing 和輕量組件支持(預編譯的JAR使用 javax.swing.*)包。
(4)徹底多線程 框架容許經過多個線程併發取樣和 經過單獨的線程組對不一樣的功能同時取樣。
(5)精心的GUI設計容許快速操做和更精確的計時。
(6)緩存和離線分析/回放測試結果。
2)JMeter下載地址特性
(1)可連接的取樣器容許無限制的測試能力。
(2)各類負載統計表和可連接的計時器可供選擇。
(3)數據分析和可視化插件提供了很好的可擴展性以及個性化。
(4)具備提供動態輸入到測試的功能(包括JavaScript)。
(5)支持腳本編程的取樣器(在1.9.2及以上版本支持BeanShell)。
在設計階段,JMeter可以充當HTTP PROXY(代理)來記錄IE/NETSCAPE的HTTP請求,也能夠記錄apache等WebServer的log文件來重現HTTP流量。當這些HTTP客戶端請求被記錄之後,測試運行時能夠方便的設置重複次數和併發度(線程數)來產生巨大的流量。JMeter還提供可視化組件以及報表工具把量服務器在不一樣壓力下的性能展示出來。
相比其餘HTTP測試工具,JMeter最主要的特色在於擴展性強。JMeter可以自動掃描其lib/ext子目錄下.jar文件中的插件,而且將其裝載到內存,讓用戶經過不一樣的菜單調用。
3)Jmeter使用
使用Jmeter很是簡單,windows下進入bin目錄直接雙擊jmeter.bat文件便可,Linux下相似,須要運行jmeter.sh文件,Jmeter運行後顯示如下界面:
Jmeter使用起來比較簡單,附件是一個簡單的配置,直接導入便可使用。
2.測試條件
Tomcat版本:8.0.33
測試項目:新建立一個web項目也不用實現任何代碼,只須要部署便可以使用,只有一個index.jsp文件。
JDK版本:jdk1.7.0.67
請求方式:POST
循環次數:100,1000
線程數:10,100,1000
總次數:總次數 = 線程數 * 循環次數
CPU:英特爾 第二代酷睿 i5-2450M(雙核)
內存:8GB
附件時Jmeter的配置文件,能夠直接導入使用。
3.測試結果
從部分結果來看優化過的Tomcat會比默認性能及併發處理能力上有提升,但至於參數的配置須要結合硬件及操做系統來不斷調整,因此並不會有一個萬能的參數來使用,須要各位不斷的測試不斷更改。
如下是一個簡單的測試結果,循環100次,線程數分別爲10,100,1000:
各位估計已經發現了相同的應用下並不必定某種protocol就必定性能出色,由於Tomcat中的這個測試項目只有一個index.jsp頁面,在較少線程數訪問狀況下BIO反應最快,而當線程數達到1000時NIO2性能最出色,而APR中規中矩,雖然這種測試的侷限性很大,但也能夠反映出:想要找出適合的配置及最佳性能須要結合實際,不斷的測試與改進,最終才能達到一個相對穩定的性能,雖然此時的性能未必是最佳的,但倒是能應對絕大多數狀況的。
總結:Tomcat相關優化也只是一個入門介紹,每一種技術之中仍是有不少很深奧的知識要去學習,只有不斷的去學習才能不斷的提升。