關於tomcat性能優化

前言java

關於 Tomcat 性能調優,一直以來就是運維面試的一個重要話題。今天咱們就簡單聊聊 Tomcat 如何進行性能優化? 首先聲明,我不會去說 Tomcat 是什麼,內部結構,原理什麼的。我不懂......我只是會說一些我在工做當中的一些參數以及本身所瞭解的方法,主要仍是和你們溝通、交流。程序員

1、關於選型面試

簡單說明,關於Openjdk 和 Oracle jdk的選擇,我我的比較傾向於使用Oracle jdk,雖然它很流氓可是我以爲東西仍是靠譜;其次是在版本上的選擇,建議選擇最新穩定版進行在生產環境使用,以此來得到更高效的性能;apache

1、JVM相關參數優化tomcat

export JAVA_OPTS=""-Dfile.encoding=UTF-8 -server -Xms1400M -Xmx1400M -Xss512k 
-XX:+AggressiveOpts 
-XX:+UseBiasedLocking -XX:PermSize=128M -XX:MaxPermSize=256M 
-XX:+DisableExplicitGC -XX:MaxTenuringThreshold=30 -XX:+UseConcMarkSweepGC 
-XX:+UseParNewGC  -XX:+CMSParallelRemarkEnabled -XX:ReservedCodeCacheSize=32m
-XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m  
-XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly 
-Djava.awt.headless=true"

提示:在java 8中永久代已被移除,若是你是java8的環境,須要你去掉"-XX:PermSize=128M -XX:MaxPermSize=256M"參數,而且"-XX:MaxTenuringThreshold=31"參數值只能設置在0-15,不然會提示相關錯誤; 性能優化

配置說明:bash

  • Tomcat 默認是以 java -client 的方式運行,server 意味着是已真正的生產環境來運行,這樣能夠得到更高的併發、更高效的垃圾回收能力;
  • Xms、Xmx表示JVM 最小內存初始值和最大內存初始值,建議設置爲相同參數,以減小CPU對內存資源的調度,避免CPU高速運轉進行的垃圾回收;
  • Xmn設置年輕代大小爲512m。整個堆大小=年輕代大小 + 年老代大小 + 持久代大小。持久代通常固定大小爲64m,因此增大年輕代後,將會減少年老代大小。此值對系統性能影響較大,Sun官方推薦配置爲整個堆的3/8;
  • -Xss是指設定每一個線程的堆棧大小。這個就要依據你的程序,看一個線程 大約須要佔用多少內存,可能會有多少線程同時運行等。通常不易設置超過1M,要否則容易出現out ofmemory;
  • -XX:+AggressiveOpts做用如其名(aggressive),啓用這個參數,則每當JDK版本升級時,你的JVM都會使用最新加入的優化技術;
  • -XX:+UseBiasedLocking啓用一個優化了的線程鎖,咱們知道在咱們的appserver,每一個http請求就是一個線程,有的請求短有的請求長,就會有請求排隊的現象,甚至還會出現線程阻塞,這個優化了的線程鎖使得你的appserver內對線程處理自動進行最優調配;
  • -XX:PermSize=128M -XX:MaxPermSize=256M JVM使用-XX:PermSize設置非堆內存初始值,默認是物理內存的1/64;在數據量的很大的文件導出時,必定要把這兩個值設置上,不然會出現內存溢出的錯誤。由XX:MaxPermSize設置最大非堆內存的大小,默認是物理內存的1/4。那麼,若是是物理內存4GB,那麼64分之一就是64MB,這就是PermSize默認值,也就是永生代內存初始大小;四分之一是1024MB,這就是MaxPermSize默認大小;
  • -XX:+DisableExplicitGC在程序代碼中不容許有顯示的調用」System.gc()」。調用System.gc()付出的代價就是系統響應時間嚴重下降,就和我在關於Xms,Xmx裏的解釋的原理同樣;
  • -XX:+UseParNewGC 對年輕代採用多線程並行回收。
  • -XX:+UseConcMarkSweepGC 即CMS gc,這一特性只有jdk1.5即後續版本才具備的功能,它使用的是gc估算觸發和heap佔用觸發。咱們知道頻頻繁的GC會造面JVM的大起大落從而影響到系統的效率,所以使用了CMS GC後能夠在GC次數增多的狀況下,每次GC的響應時間卻很短,好比說使用了CMS GC後通過jprofiler的觀察,GC被觸發次數很是多,而每次GC耗時僅爲幾毫秒;
  • -XX:+CMSParallelRemarkEnabled在使用UseParNewGC 的狀況下, 儘可能減小mark的時間;
  • -XX:+UseCMSCompactAtFullCollection在使用concurrent gc 的狀況下, 防止 memoryfragmention, 對live object 進行整理, 使 memory 碎片減小;
  • -XX:LargePageSizeInBytes指定 Java heap的分頁頁面大小;
  • -XX:CMSInitiatingOccupancyFraction=70CMSInitiatingOccupancyFraction,這個參數設置有很大技巧,基本上知足(Xmx-Xmn)*(100- CMSInitiatingOccupancyFraction)/100>=Xmn就 不會出現promotion failed。在個人應用中Xmx是6000,Xmn是512,那麼Xmx-Xmn是5488兆,也就是年老代有5488 兆,CMSInitiatingOccupancyFraction=90說明年老代到90%滿的時候開始執行對年老代的併發垃圾回收(CMS),這時還 剩10%的空間是5488*10%=548兆,因此即便Xmn(也就是年輕代共512兆)裏全部對象都搬到年老代裏,548兆的空間也足夠了,因此只要滿 足上面的公式,就不會出現垃圾回收時的promotion failed,所以這個參數的設置必須與Xmn關聯在一塊兒;
3、Tomcat 自身優化
3.1 修改Tomcat Connector運行模式

Tomcat Connector(Tomcat鏈接器)有bio、nio、apr三種運行模式,簡單介紹(抄百度的,有本事來打我):服務器

  • 1. bio(blocking I/O),即阻塞式I/O操做,表示Tomcat使用的是傳統的Java I/O操做(即java.io包 及其子包)。Tomcat在默認狀況下(敲黑板,主要是在tomcat7或如下的版本),就是以bio模式運行的。遺憾的是,就通常而言,bio模式是三種運行模式中性能最低的一種。

  特性:一個線程處理一個請求。缺點:併發量高時,線程數較多,浪費資源。網絡

  • 2. 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)更好的併發運行性能。nio目前存在nio以及nio2模式,所以到了Tomcat8.5和Tomcat9.0,則去掉了對BIO的支持。tomcat 8默認以 nio 啓動,其餘版本本身百度怎麼修改成 nio,在啓動的時候觀察日誌:
12-Dec-2017 14:17:46.429 信息 [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
12-Dec-2017 14:17:46.445 信息 [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
12-Dec-2017 14:17:46.473 信息 [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["ajp-nio-8009"]
12-Dec-2017 14:17:46.474 信息 [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
12-Dec-2017 14:17:46.476 信息 [main] org.apache.catalina.startup.Catalina.load Initialization processed in 1031 ms

特性:利用Java的異步IO處理,能夠經過少許的線程處理大量的請求。多線程

  • 3. apr(Apache Portable Runtime/Apache可移植運行時),是Apache HTTP服務器的支持庫。在tomcat中,又被稱爲 tomcat native,從操做系統層面解決io阻塞問題。是一個利用 APR 來提高Tomcat性能的本地API。怎麼配置?本身查!生產環境,強烈推薦。

3.2 tomcat server.xml配置優化

線程池參數配置:

<?xml version="1.0" encoding="UTF-8"?>
  <Service name="Catalina">

    <!--The connectors can use a shared executor, you can define one or more named thread pools-->
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>
    -->
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
    maxThreads="1000" 
    minSpareThreads="100" 
    maxIdleTime="60000"
    prestartminSpareThreads = "true"
    maxQueueSize = "100" 
    className="org.apache.catalina.core.StandardThreadExecutor" />
  • URIEncoding="UTF-8" 使得tomcat能夠解析含有中文名的文件的url;
  • minSpareThreads 最小備用線程數,tomcat啓動時的初始化的線程數。
  • enableLookups 消除DNS查詢對性能的影響咱們能夠關閉DNS查詢。
  • connectionTimeout爲網絡鏈接超時時間毫秒數。
  • maxThreads Tomcat使用線程來處理接收的每一個請求。這個值表示Tomcat可建立的最大的線程數,即最大併發數。建議值爲500-1000,具體根據服務器性能以及壓測數據結果測試;
  • acceptCount是當線程數達到maxThreads後,後續請求會被放入一個等待隊列,這個acceptCount是這個隊列的大小,若是這個隊列也滿了,就直接refuse connection。
  • maxProcessors與minProcessors在 Java中線程是程序運行時的路徑,是在一個程序中與其它控制線程無關的、可以獨立運行的代碼段。它們共享相同的地址空間。多線程幫助程序員寫出CPU最 大利用率的高效程序,使空閒時間保持最低,從而接受更多的請求。

提示:網上不少混淆了,異步servlet和非阻塞connector,一個是Executor,一個是connector,二者的工做階段不一樣。

鏈接器配置:

    <Connector executor="tomcatThreadPool" URIEncoding="utf-8"
               port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
               enableLookups="false"
               maxConnections="2000"
               useURIValidationHack="false"
               keepAliveTimeout="60000"
               connectionTimeout="20000"               
maxThreads="1000"
minSpareThreads="100"
maxSpareThreads="2000"
minProcessors="100"
maxProcessors="1000" tcpNoDelay="true" redirectPort="8443" />
  • maxThreads="X" 表示最多同時處理X個鏈接;
  • minSpareThreads="X" 初始化X個鏈接;
  • maxSpareThreads="X" 表示若是最多能夠有X個線程,一旦超過X個,則會關閉不在須要的線程;
  • acceptCount="X" 當同時鏈接的人數達到maxThreads時,還能夠排隊,隊列大小爲X.超過X就不處理;

提示:Tomcat 中能夠同時接收的鏈接數爲maxConnections+acceptCount 。上面這些參數須要手動開啓,默認值配置都較低,沒法發揮最佳性能。能夠去大家生產環境看看,是否是不少沒有作優化呢;

4、關於性能分析

4.1 常見工具

  • 1 jmx 端口獲取監控信息(好比,zabbix);
  • 2 jps/jstat/jmap等命令進行調試;
  • 3 java agent方式獲取以及代碼植入以探針的方式監控(開源PinPoint);

 4.2 其餘

查看tomcat鏈接數:

netstat –nat | grep 8080

查看 tomcat 線程數:  

# 查看進程ID
ps -ef |grep java

# 查看線程
ps -o nlwp 3598

 提示:經過使用該方式能夠查看到該進程有多少線程,但並無排除處於idle狀態的線程。因此,要想獲取當前進程running的線程數,還須要執行以下命令。

ps -eLo pid,stat | grep 3598 | grep running | wc -l

其中ps -eLo pid,stat能夠找出全部線程,並打印其所在的進程號和線程當前的狀態;兩個grep命令分別篩選進程號和線程狀態;wc統計個數。SL表示空閒狀態。 

相關文章
相關標籤/搜索