1. 程式人生 > >tomcat服務二---tomcat調優

tomcat服務二---tomcat調優

一、tomcat的基本原理


Tomcat伺服器的啟動是基於一個server.xml檔案的,Tomcat啟動的時候首先會啟動一個Server,Server裡面就會啟動Service,Service裡面就會啟動多個"Connector(聯結器)",每一個聯結器都在等待客戶機的連線,當有使用者使用瀏覽器去訪問伺服器上面的web資源時,首先是連線到Connector(聯結器),Connector(聯結器)是不處理使用者的請求的,而是將使用者的請求交給一個Engine(引擎)去處理,Engine(引擎)接收到請求後就會解析使用者想要訪問的Host,然後將請求交給相應的Host,Host收到請求後就會解析出使用者想要訪問這個Host下面的哪一個Web應用,一個web應用對應一個Context。

二、tomcat調優

1、記憶體調優,在canalina.sh中寫入如下內容

export JAVA_OPTS="-server -Xms4096m -Xmx4096m -XX:+PrintHeapAtGC -Xloggc:/usr/local/tomcat_front/logs/gc.log -XX:+PrintGCTimeStamps -XX:+TraceClassLoading -XX:+TraceClassUnloading -XX:+PrintReferenceGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/tomcat_front/logs/front1.bin"

引數解釋:

-server:執行jdk的server版本

-Xms:java虛擬機器初始化時堆的記憶體大小,一般配置Xmx配置為相同的值,這樣的好處是GC不必再為擴充套件記憶體空間而消耗效能

-Xmx:java虛擬機器可使用堆的最大記憶體

-XX:+PrintHeapAtGC  

-Xloggc:/usr/local/tomcat_front/logs/gc.log

-XX:+PrintGCTimeStamps

-XX:+TraceClassLoading

-XX:+TraceClassUnloading

-XX:+PrintReferenceGC

-XX:+HeapDumpOnOutOfMemmoryError

-XX:HeapDumpPath=/usr/local/tomcat_front/logs/front1.bin

除了這些引數之外,還可以記錄其他引數,可參考jvm引數的配置。

設定成功後,可以使用jdk自帶的工具進行驗證,在JAVA_HOME/bin目錄下執行

$jps

$jump -heap  程序號

2、聯結器Connector調優,在server.xml中加入如下內容

<Connector port="8080"
        protocol="HTTP/1.1"
        connectionTimeout="20000"    ##超時時間,毫秒,這裡是20秒
        redirectPort="443"
        maxThreads="3000"          ##最大執行緒數
        minSpareThreads="20"   ##最小空閒執行緒數,這裡是一直會執行的執行緒
        acceptCount="1000"        ##接收的佇列數
        enableLookups="false"    ##關閉dns解析,減少效能損耗
        server="None"              
        URIEncoding="UTF-8"  
        compression="on"         ##開啟壓縮
    compressionMinSize="2048"     ##最小壓縮檔案的大小
    noCompressionUserAgents="gozilla,traviata"     ##這倆種瀏覽器下不壓縮
    compressableMimeType="text/html,text/xml,text/javascript,application/x-javascript,application/javascript,text/css,text/plain"  ##壓縮的格式
      />
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"  
      ... 

三、填坑心得(轉發)

http://www.cnblogs.com/hucn/p/3572384.html

我遇到這樣的問題,本地部署時丟擲異常java.lang.OutOfMemoryError:GC overhead limit exceeded導致服務起不來,檢視日誌發現載入了太多資源到記憶體,本地的效能也不好,gc時間消耗的較多。解決這種問題兩種方法是,增加引數,-XX:-UseGCOverheadLimit,關閉這個特性,同時增加heap大小,-Xmx1024m。坑填了,but why?

OOM大家都知道,就是JVM記憶體溢位了,那GC overhead limit exceed呢?

GC overhead limt exceed檢查是Hotspot VM 1.6定義的一個策略,通過統計GC時間來預測是否要OOM了,提前丟擲異常,防止OOM發生。Sun 官方對此的定義是:“並行/併發回收器在GC回收時間過長時會丟擲OutOfMemroyError。過長的定義是,超過98%的時間用來做GC並且回收了不到2%的堆記憶體。用來避免記憶體過小造成應用不能正常工作。“

聽起來沒啥用...預測OOM有啥用?起初開來這玩意只能用來Catch住釋放記憶體資源,避免應用掛掉。後來發現一般情況下這個策略不能拯救你的應用,但是可以在應用掛掉之前做最後的掙扎,比如資料儲存或者儲存現場(Heap Dump)。

而且有些時候這個策略還會帶來問題,比如載入某個大的記憶體資料時頻繁OOM。

假如你也生產環境中遇到了這個問題,在不知道原因時不要簡單的猜測和規避。可以通過-verbose:gc -XX:+PrintGCDetails看下到底什麼原因造成了異常。通常原因都是因為old區佔用過多導致頻繁Full GC,最終導致GC overhead limit exceed。如果gc log不夠可以藉助於JProfile等工具檢視記憶體的佔用,old區是否有記憶體洩露。分析記憶體洩露還有一個方法-XX:+HeapDumpOnOutOfMemoryError,這樣OOM時會自動做Heap Dump,可以拿MAT來排查了。還要留意young區,如果有過多短暫物件分配,可能也會拋這個異常。

日誌的資訊不難理解,就是每次gc時打條日誌,記錄GC的型別,前後大小和時間。舉個例子。

33.125: [GC [DefNew: 16000K->16000K(16192K), 0.0000574 secs][Tenured: 2973K->2704K(16384K), 0.1012650 secs] 18973K->2704K(32576K), 0.1015066 secs]

100.667:[Full GC [Tenured: 0K->210K(10240K), 0.0149142 secs] 4603K->210K(19456K), [Perm : 2999K->2999K(21248K)], 0.0150007 secs] 

GC和Full GC代表gc的停頓型別,Full GC代表stop-the-world。箭頭兩邊是gc前後的區空間大小,分別是young區、tenured區和perm區,括號裡是該區的總大小。冒號前面是gc發生的時間,單位是秒,從jvm啟動開始計算。DefNew代表Serial收集器,為Default New Generation的縮寫,類似的還有PSYoungGen,代表Parallel Scavenge收集器。這樣可以通過分析日誌找到導致GC overhead limit exceeded的原因,通過調節相應的引數解決問題。

文中涉及到的名詞解釋,

Eden Space:堆記憶體池,大多數物件在這裡分配記憶體空間。

Survivor Space:堆記憶體池,儲存在Eden Space的gc中存活下來的物件。

Tenured Generation:堆記憶體池,儲存Survivor Space中存活過幾次gc的物件。

Permanent Generation:非堆空間,儲存的是class和method物件。

Code Cache:非堆空間,JVM用來儲存編譯和儲存native code。