jstack $PID #查看java進程的狀態,分析tomcat卡死緣由,定位java進程卡死的函數,調整代碼html
#RUNNABLE,在虛擬機內執行的。運行中狀態,可能裏面還能看到locked字樣,代表它得到了某把鎖。java
#BLOCKED,受阻塞並等待監視器鎖。被某個鎖(synchronizers)給block住了。linux
#WATING,無限期等待另外一個線程執行特定操做。等待某個condition或monitor發生,通常停留在park(), wait(), sleep(),join() 等語句裏。web
#TIMED_WATING,有時限的等待另外一個線程的特定操做。和WAITING的區別是wait() 等語句加上了時間限制 wait(timeout)。apache
#TERMINATED,已退出的。windows
1、內存優化tomcat
默認狀況下Tomcat的相關內存配置較低,這對於一些大型項目顯然是不夠用的,這些項目運行就已經耗費了大部份內存空間,況且大規模訪問的狀況。即便是本文中的這個只有一個頁面的超小項目,在併發達到必定程度後也會拋出如下相似異常:安全
- 嚴重: Exception invoking periodic operation: java.lang.OutOfMemoryError: Java heap space
- 嚴重: Error processing request java.lang.OutOfMemoryError: GC overhead limit exceeded
說明Tomcat已經無力支持訪問處理,內部GC也已經「無能無力」。因此通常狀況下咱們須要從新配置Tomcat的相關內存大小。
1.修改內存等 JVM相關配置服務器
Linux下修改TOMCAT_HOME/bin/catalina.sh,在其中加入,能夠放在CLASSPATH=下面:網絡
- JAVA_OPTS="-server -XX:PermSize=512M -XX:MaxPermSize=1024m -Xms2048m -Xmx2048m"
windows下修改TOMCAT_HOME/bin/catalina.bat,在其中加入,能夠放在set CLASSPATH=下面:
- set JAVA_OPTS=-server -XX:PermSize=512M -XX:MaxPermSize=1024m -Xms2048m -Xmx2048m
這些參數在咱們學習JVM部分文章時已經都認識過了,不過這裏仍是簡單介紹下:
-server:啓用 JDK的 server 版本;
-Xms:Java虛擬機初始化時堆的最小內存,通常與 Xmx配置爲相同值,這樣的好處是GC沒必要再爲擴展內存空間而消耗性能;
-Xmx:Java虛擬機可以使用堆的最大內存;
-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命令:
- jps
- #顯示如下結果
- 2340 Bootstrap
- 6696 Jps
其中 Bootstrap進程就是咱們啓動了的 Tomcat,其進程號爲2340.
而後咱們利用 jmap工具查看其內存相關配置:
- jmap -heap 2340
- #顯示如下結果
- Attaching to process ID 2340, please wait...
- Debugger attached successfully.
- Server compiler detected.
- JVM version is 24.65-b04
- using thread-local object allocation.
- Parallel GC with 4 thread(s)
- Heap Configuration:
- MinHeapFreeRatio = 0
- MaxHeapFreeRatio = 100
- MaxHeapSize = 2147483648 (2048.0MB) //最大堆內存
- NewSize = 1310720 (1.25MB)
- MaxNewSize = 17592186044415 MB
- OldSize = 5439488 (5.1875MB)
- NewRatio = 2
- SurvivorRatio = 8
- PermSize = 536870912 (512.0MB) //永久代初始大小
- MaxPermSize = 1073741824 (1024.0MB) //永久代最大大小
- G1HeapRegionSize = 0 (0.0MB)
- Heap Usage:
- PS Young Generation
- Eden Space:
- capacity = 537919488 (513.0MB)
- used = 247606720 (236.13616943359375MB)
- free = 290312768 (276.86383056640625MB)
- 46.03044238471613% used
- From Space:
- capacity = 89128960 (85.0MB)
- used = 0 (0.0MB)
- free = 89128960 (85.0MB)
- 0.0% used
- To Space:
- capacity = 89128960 (85.0MB)
- used = 0 (0.0MB)
- free = 89128960 (85.0MB)
- 0.0% used
- PS Old Generation
- capacity = 1431830528 (1365.5MB)
- used = 0 (0.0MB)
- free = 1431830528 (1365.5MB)
- 0.0% used
- PS Perm Generation
- capacity = 536870912 (512.0MB)
- used = 20770360 (19.80815887451172MB)
- free = 516100552 (492.1918411254883MB)
- 3.86878103017807% used
- 12005 interned Strings occupying 1039352 bytes.
從結果就能夠看出咱們的配置已經成功了。
2、配置優化
咱們知道TOMCAT_HOME/conf/server.xml能夠配置端口,虛擬路徑等等 Tomcat相關主要配置。
1.Connector 優化
Connector是鏈接器,負責接收客戶的請求,以及向客戶端回送響應的消息。因此 Connector的優化是重要部分。默認狀況下 Tomcat只支持200線程訪問,超過這個數量的鏈接將被等待甚至超時放棄,因此咱們須要提升這方面的處理能力。
修改這部分配置須要修改TOMCAT_HOME/conf/server.xml,打開server.xml找到Connector 標籤項,默認配置以下:
- <Connector port="8080" protocol="HTTP/1.1"
- connectionTimeout="20000"
- redirectPort="8443" />
其中port表明服務接口;protocol表明協議類型;connectionTimeout表明鏈接超時時間,單位爲毫秒;redirectPort表明安全通訊(https)轉發端口,通常配置成443。
能夠看到除了這幾個基本配置外並沒有特殊功能,因此咱們須要對 Connector 進行擴展。
其中Connector 支持參數屬性能夠參考Tomcat官方網站(https://tomcat.apache.org/tomcat-8.0-doc/config/http.html),很是多,因此本文就只介紹些經常使用的。
咱們將 Connector 配置修改成以下:
- <Connector port="8080"
- protocol="HTTP/1.1"
- maxThreads="1000"
- minSpareThreads="100"
- acceptCount="1000"
- maxConnections="1000"
- connectionTimeout="20000"
- maxHttpHeaderSize="8192"
- tcpNoDelay="true"
- compression="on"
- compressionMinSize="2048"
- disableUploadTimeout="true"
- redirectPort="8443"
- enableLookups="false"
- URIEncoding="UTF-8" />
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類型修改成:
- //NIO
- protocol="org.apache.coyote.http11.Http11NioProtocol"
- //NIO2
- protocol="org.apache.coyote.http11.Http11Nio2Protocol"
便可。
(3)APR:APR(Apache Portable Runtime/Apache可移植運行時),是Apache HTTP服務器的支持庫。你能夠簡單地理解爲:Tomcat將以JNI的形式調用 Apache HTTP服務器的核心動態連接庫來處理文件讀取或網絡傳輸操做,從而大大地提升 Tomcat對靜態文件的處理性能。
與配置 NIO運行模式同樣,也須要將對應的 Connector節點的 protocol屬性值改成:
- protocol="org.apache.coyote.http11.Http11AprProtocol"
相關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處理請求。
- //BIO
- protocol="HTTP/1.1"
- //NIO
- protocol="org.apache.coyote.http11.Http11NioProtocol"
- //NIO2
- protocol="org.apache.coyote.http11.Http11Nio2Protocol"
- //APR
- protocol="org.apache.coyote.http11.Http11AprProtocol"
如下是幾種類型 Connector的參數對比:
並非說 BIO的性能就必定不如 NIO,這幾種類型 Connector之間並無明顯的性能區別,它們之間實現流程和原理不一樣,因此它們的選擇是須要根據應用的類型來決定的。
BIO更適合處理簡單流程,如程序處理較快能夠當即返回結果。簡單項目及應用能夠採用BIO。
NIO更適合後臺須要耗時完成請求的操做,如程序接到了請求後須要比較耗時的處理這已請求,因此沒法當即返回結果,這樣若是採用BIO就會佔用一個鏈接,而使用NIO後就能夠將此鏈接轉讓給其餘請求,直至程序處理完成返回爲止。
APR能夠大大提高Tomcat對靜態文件的處理性能,同時若是你使用了HTTPS方式傳輸的話,也能夠提高SSL的處理性能。
本文的最後會對幾種 Connector進行對比測試。
3.線程池
Executor表明了一個線程池,能夠在Tomcat組件之間共享。使用線程池的好處在於減小了建立銷燬線程的相關消耗,並且能夠提升線程的使用效率。
要想使用線程池,首先須要在 Service標籤中配置 Executor,以下:
- <Service name="Catalina">
- <Executor name="tomcatThreadPool"
- namePrefix="catalina-exec-"
- maxThreads="1000"
- minSpareThreads="100"
- maxIdleTime="60000"
- maxQueueSize="Integer.MAX_VALUE"
- prestartminSpareThreads="false"
- threadPriority="5"
- className="org.apache.catalina.core.StandardThreadExecutor"/>
- ....
其中,
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中指定:
- <Connector executor="tomcatThreadPool"
- ...
4.Listener
另外一個影響Tomcat 性能的因素是內存泄露。Server標籤中能夠配置多個Listener,其中 JreMemoryLeakPreventionListener是用來預防JRE內存泄漏。此Listener只需在Server標籤中配置便可,默認狀況下無需配置,已經添加在 Server中。
- <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
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下構建就相對簡單和熟悉了,只須要執行常規構建命令便可:
- ./configure --prefix=/usr/local/apr
- make
- make install
安裝成功後,APR會默認安裝在 /usr/local/apr目錄下,也能夠指定安裝目錄。
apr-iconv安裝時須要指定apr的安裝位置:
- ./configure --prefix=/usr/local/apr-iconv --with-apr=/usr/local/apr
- make
- make install
apr-util安裝時須要指定apr的安裝位置:
- ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr --with-apr-iconv=/usr/local/apr-iconv/bin/apriconv
- make
- make install
安裝完成後目錄結構:
安裝完成後實際上是沒法直接使用APR的,想使用APR還須要安裝Tomcat Native,不然Tomcat啓動時會報如下錯誤:
- 16-May-2016 02:52:42.992 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/local/apr/lib:/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
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安裝經過如下命令:
- yum install apr-devel openssl-devel
安裝成功後就能夠安裝Tomcat Native了,運行如下命令下載地址:
- ./configure --with-apr=/usr/local/apr/bin/apr-1-config \
- --with-java-home=/usr/java/jdk1.7.0_79 \
- --with-ssl=yes \
- --prefix=/usr/local/tomcat
注意,--prefix指向的是 Tomcat目錄。
注意,下載後的 Tomcat Native解壓後目錄結構以下:
安裝時須要進入native目錄。
安裝過程當中還有可能產生依賴包版本不兼容的問題(通常爲openssl版本太低),這時須要卸載舊的依賴,並安裝最新版本
當安裝完成後出現如下相似輸出時,說明安裝已經成功:
- ----------------------------------------------------------------------
- Libraries have been installed in:
- /usr/local/tomcat/lib
- If you ever happen to want to link against installed libraries
- in a given directory, LIBDIR, you must either use libtool, and
- specify the full pathname of the library, or use the `-LLIBDIR'
- flag during linking and do at least one of the following:
- - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
- during execution
- - add LIBDIR to the `LD_RUN_PATH' environment variable
- during linking
- - use the `-Wl,-rpath -Wl,LIBDIR' linker flag
- - have your system administrator add LIBDIR to `/etc/ld.so.conf'
- See any operating system documentation about shared libraries for
- more information, such as the ld(1) and ld.so(8) manual pages.
- ----------------------------------------------------------------------
(2)Windows下
Windows下安裝就異常簡單了,只須要把bin目錄下文件複製到tomcat/bin下便可,若是爲64位,則複製x64中文件下載地址。
3)使用
(1)環境變量配置
使用前須要配置環境變量:
- vi /etc/profile
打開配置文件後,添加如下內容:
- export LD_LIBRARY_PATH=/usr/local/apr/lib
退出保存,而後執行:
- source /etc/profile
(2)修改Tomcat配置文件
打開conf/server.xml文件,修改Connector 標誌的protocol屬性:
- protocol="org.apache.coyote.http11.Http11AprProtocol"
而後添加Listener:
- <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
保存配置文件後,啓動Tomcat,從日誌中看到如下輸出時,說明所有功能都已配置成功:
- 16-May-2016 04:28:54.734 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded APR based Apache Tomcat Native library 1.1.34 using APR version 1.5.2.
- 16-May-2016 04:28:54.734 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
- 16-May-2016 04:28:54.739 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized (OpenSSL 1.0.2h 3 May 2016)
至此,APR與 Native都已安裝完成,可使用,對於 APR與 Native還有不少知識要學習,但不是本文的重點,因此之後有機會還會深刻學習。
https://blog.csdn.net/kally_wang/article/details/74989885