【轉】史上最強Tomcat8性能優化

http://www.javashuo.com/article/p-sembvsfk-m.htmlhtml

文章目錄
授人以魚不如授人以漁
目的
服務器資源
Tomcat配置優化
Linux環境安裝運行Tomcat8
AJP鏈接
執行器(線程池)
3種運行模式
部署測試用的web項目
查看服務器信息
部署web應用
使用Apache JMeter進行性能測試
下載安裝
修改語言
建立接口的測試用例
啓動與進行接口測試
查看測試報告
調整Tomcat參數進行優化
禁用AJP鏈接
設置線程池
最大線程數爲150,初始爲4
最大線程數爲500,初始爲50
最大線程數爲1000,初始爲200
最大線程數爲5000,初始爲1000
設置最大等待隊列數
設置nio2的運行模式
參數說明與最佳實踐
執行器參數說明(加粗是重點)
執行器最佳實踐
鏈接器參數說明
通用屬性(加粗是重點)
標準實現(加粗是重點)
鏈接器最佳實踐
調整JVM參數進行優化
設置並行垃圾回收器
查看gc日誌文件
調全年輕代大小
設置G1垃圾回收器
JVM配置最佳實踐
總結
授人以魚不如授人以漁
本博客的目的不在於給出最佳配置,而是帶領開發者,可以從實際狀況出發,經過不斷的調節tomcat和jvm參數,去發現吞吐量,平均響應時間和錯誤率等信息的變化,同時根據服務器的cpu和內存等信息,結合接口的業務邏輯,最好是測試使用率最高,併發最大,或者是最重要的接口(好比下單支付接口),設置最優的tomcat和jvm配置參數。java

目的
經過Tomcat性能優化能夠提升網站的併發能力。linux

Tomcat服務器在JavaEE項目中使用率很是高,因此在生產環境對Tomcat的優化也變得很是重要了。web

對於Tomcat的優化,主要是從2個方面入手,一是Tomcat自身的配置,另外一個是Tomcat所運行的jvm虛擬機的調優。正則表達式

服務器資源
服務器所能提供CPU、內存、硬盤的性能對處理能力有決定性影響。硬件咱們不說了,這個方面是錢越多越好是吧。數據庫

Tomcat配置優化
Linux環境安裝運行Tomcat8
具體的安裝步驟能夠參考Linux(CentOS7)安裝Tomcat與設置Tomcat爲開機啓動項apache

若是須要登陸系統,必須配置tomcat用戶,在安裝完Tomcat後,進行以下操做centos

在/conf/tomcat-users.xml文件中的<tomcat-users>標籤裏面添加以下內容瀏覽器

<!-- 修改配置文件,配置tomcat的管理用戶 -->
<role rolename="manager"/>
<role rolename="manager-gui"/>
<role rolename="admin"/>
<role rolename="admin-gui"/>
<user username="tomcat" password="tomcat" roles="admin-gui,admin,manager-gui,manager"/>
1
2
3
4
5
6
若是是tomcat7,配置了tomcat用戶就能夠登陸系統了,可是tomcat8中不行,還須要修改另外一個配置文件,不然訪問不了,提示403,打開webapps/manager/META-INF/context.xml文件緩存

<!-- 將Valve標籤的內容註釋掉,保存退出便可 -->
<?xml version="1.0" encoding="UTF-8"?>

<Context antiResourceLocking="false" privileged="true" >
<!--<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />-->
<Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/>
</Context>
1
2
3
4
5
6
7
8
打開瀏覽器進行訪問10.172.0.202:8080

 

點擊「Server Status」,輸入用戶名、密碼進行登陸,tomcat/tomcat

 

登陸以後能夠看到服務器狀態等信息,主要包括服務器信息,JVM,ajp和http信息

 

AJP鏈接
在服務狀態頁面中能夠看到,默認狀態下會啓用AJP服務,而且佔用8009端口。

 

什麼是AJP

AJP(Apache JServer Protocol)
AJPv13協議是面向包的。WEB服務器和Servlet容器經過TCP鏈接來交互;爲了節省SOCKET建立的昂貴代價,WEB服務器會嘗試維護一個永久TCP鏈接到servlet容器,而且在多個請求和響應週期過程會重用鏈接。

 

咱們通常是使用Nginx+Tomcat的架構,因此用不着AJP協議,把AJP鏈接器禁用。

修改conf下的server.xml文件,將AJP服務禁用掉便可。

<!-- 禁用AJP鏈接 -->
<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->
1
2


重啓tomcat,查看效果。能夠看到AJP服務已經不存在了。

 

執行器(線程池)
在tomcat中每個用戶請求都是一個線程,因此可使用線程池提升性能。

修改server.xml文件:

<!--將註釋打開-->
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="500" minSpareThreads="50" prestartminSpareThreads="true" maxQueueSize="100"/>

<!--
參數說明:
maxThreads:最大併發數,默認設置 200,通常建議在 500 ~ 1000,根據硬件設施和業務來判斷
minSpareThreads:Tomcat 初始化時建立的線程數,默認設置 25
prestartminSpareThreads: 在 Tomcat 初始化的時候就初始化 minSpareThreads 的參數值,若是不等於 true,minSpareThreads 的值就沒啥效果了
maxQueueSize,最大的等待隊列數,超過則拒絕請求
-->

<!--在Connector中設置executor屬性指向上面的執行器-->
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
保存退出,重啓tomcat,查看效果。

 

在頁面中顯示最大線程數爲-1,這個是正常的,僅僅是顯示的問題,實際使用的是指定的值。若是配置了一個Executor,則該屬性的任何值將被正確記錄,可是它將被顯示爲-1

3種運行模式
tomcat的運行模式有3種:

bio
性能很是低下,沒有通過任何優化處理和支持

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)更好的併發運行性能。Tomcat8默認使用nio運行模式。

apr
安裝起來最困難,可是從操做系統級別來解決異步的IO問題,大幅度的提升性能

對於每種協議,Tomcat都提供了對應的I/O方式的實現,並且Tomcat官方還提供了在每種協議下每種I/O實現方案的差別, HTTP協議下的處理方式以下表,詳情可查看Tomcat官網說明

BIO NIO NIO2 APR
類名 Http11Protocol Http11NioProtocol Http11Nio2Protocol Http11AprProtocol
引用版本 ≥3.0 ≥6.0 ≥8.0 ≥5.5
輪詢支持 否 是 是 是
輪詢隊列大小 N/A maxConnections maxConnections maxConnections
讀請求頭 阻塞 非阻塞 非阻塞 阻塞
讀請求體 阻塞 阻塞 阻塞 阻塞
寫響應 阻塞 阻塞 阻塞 阻塞
等待新請求 阻塞 非阻塞 非阻塞 非阻塞
SSL支持 Java SSL Java SSL Java SSL Open SSL
SSL握手 阻塞 非阻塞 非阻塞 阻塞
最大連接數 maxConnections maxConnections maxConnections maxConnections
推薦使用nio,在tomcat8中有最新的nio2,速度更快,建議使用nio2

設置nio2:

<Connector executor="tomcatThreadPool" port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
connectionTimeout="20000"
redirectPort="8443" />
1
2
3


能夠看到已經設置爲nio2了。

部署測試用的web項目
爲了方便測試性能,咱們將部署一個java web項目,這個項目自己和本博客沒有什麼關係,僅僅用於測試。

注意:這裏在測試時,咱們使用一個新的tomcat,進行測試,後面再對其進行優化調整,再測試。

查看服務器信息
說明一下個人測試服務器配置,不一樣的服務器配置對Tomcat的性能會有所影響。

配置參數 參數值
Linux版本 CentOS Linux release 7.2.1511 (Core)
查看邏輯cpu個數 4
查看物理cpu個數 4
總內存 8G
CentOS7服務器環境信息查看命令

查看Linux版本

查看Linux版本:cat /etc/centos-release

查看CPU個數

查看邏輯cpu個數:cat /proc/cpuinfo | grep 「processor」 | wc -l

查看物理cpu個數:cat /proc/cpuinfo | grep 「physical id」 | sort | uniq | wc -l

查看每一個物理cpu的核數cores:cat /proc/cpuinfo | grep 「cpu cores」

若是全部物理cpu的cores個數加起來小於邏輯cpu的個數,則該cpu使用了超線程技術。查看每一個物理cpu中邏輯cpu的個數:cat /proc/cpuinfo | grep 「siblings」

查看內存使用狀況

查看內存佔用狀況:free -m

參數說明

Mem:內存的使用狀況總覽表。

total:機器總的物理內存 單位爲:M

used:用掉的內存。

free:空閒的物理內存。

[root@localhost ~]# cat /etc/centos-release
CentOS Linux release 7.2.1511 (Core)

[root@localhost ~]# cat /proc/cpuinfo | grep "processor" | wc -l
4
[root@localhost ~]# cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l
4

[root@localhost ~]# cat /proc/cpuinfo | grep "cpu cores"
cpu cores : 1
cpu cores : 1
cpu cores : 1
cpu cores : 1

[root@localhost ~]# free -m
total used free shared buff/cache available
Mem: 7825 850 6241 9 733 6714
Swap: 8063 0 8063
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
部署web應用
上傳war包到linux服務器,而後進行部署

個人web應用的名字叫tomcat-optimization,主要是提供了一個查詢用戶列表的接口,該接口會去阿里雲數據庫查詢用戶列表,沒有任務業務邏輯的處理。

# 刪除tomcat的/webapps/ROOT目錄的全部文件
cd /webapps/ROOT
rm -rf *

# 上傳war包到tomcat的/webapps/ROOT,而後解壓
jar -xvf tomcat-optimization.war
rm -rf tomcat-optimization.war

# 進入tomcat的/bin目錄重啓tomcat
cd /bin
./shutdown.sh
./startup.sh
1
2
3
4
5
6
7
8
9
10
11
12
訪問接口地址: http://10.172.0.202:8080/user/listUser

[{
"id": 1,
"account": "lilei",
"password": "123456",
"userName": "李雷",
"gender": 1,
"age": 15,
"birthday": "2001-01-01 01:01:38",
"createTime": "2016-03-01 19:09:55"
}, {
"id": 2,
"account": "hanmeimei",
"password": "123456",
"userName": "韓梅梅",
"gender": 0,
"age": 14,
"birthday": "2002-01-01 01:01:38",
"createTime": "2016-03-01 19:09:55"
}, {
"id": 3,
"account": "lucy",
"password": "123456",
"userName": "露西",
"gender": 0,
"age": 13,
"birthday": "2003-01-01 01:01:38",
"createTime": "2016-03-01 19:09:55"
}]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
使用Apache JMeter進行性能測試
Apache JMeter是Apache組織開發的基於Java的壓力測試工具。 咱們藉助於此工具進行測試,將測試出tomcat的吞吐量等信息。

下載安裝
下載地址:http://jmeter.apache.org/download_jmeter.cgi

 

注意:這裏須要先安裝好jdk8及其以上版本的環境,能夠參考JDK安裝與環境變量配置

直接將下載好的zip壓縮包進行解壓便可。

 

進入bin目錄,找到jmeter.bat文件,雙機打開便可啓動。

 

JMeter啓動頁面

 

JMeter主頁面

 

修改語言
默認的主題是黑色風格的主題而且語言是英語,這樣不太方便使用,因此須要修改下語言。

設置語言爲簡體中文。

 

修改語言完成的界面

 

建立接口的測試用例
測試接口以前須要調整Windows環境配置,否則會報以下錯誤

JMeter java.net.BindException: Address already in use: connect
1
出現緣由:
TCP/IP鏈接數不夠或TIME_WAIT中存在不少連接,致使吞吐量低。

解決方案:
從問題的緣由分析,有兩種解決方案,一是增長預留給TCP/IP服務的臨時端口的數量,二是加快被佔用端口的釋放速度。

解決辦法:
一、打開註冊表:regedit
二、HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ Services\TCPIP\Parameters
三、新建 DWORD值,name:TCPTimedWaitDelay,value:30(十進制) –> 設置爲30秒,默認是240秒
四、新建 DWORD值,name:MaxUserPort,value:65534(十進制) –> 設置最大鏈接數65534
五、重啓系統

第一步:設置測試計劃的名稱

 

第二步:添加線程組,使用線程模擬用戶的併發

 

 

1000個線程,每一個線程循環10次,也就是tomcat會接收到10000個請求。

第三步:添加http請求

 

設置http請求

 

第四步:添加請求監控

 

啓動與進行接口測試


查看測試報告
在聚合報告中,重點看吞吐量。

 

調整Tomcat參數進行優化
經過上面測試能夠看出,tomcat在不作任何調整時,吞吐量爲697次/秒。這個吞吐量跟接口的業務邏輯關係很大,若是業務邏輯複雜,須要比較長時間計算的,可能吞吐量只有幾十次/秒,我這裏測試的時候沒有添加任務業務邏輯,纔會出現吞吐量爲697次/秒的狀況。這裏的吞吐量最好是通過屢次測試取平均值,由於單次測試具備必定的隨機性

禁用AJP鏈接
修改conf下的server.xml文件,將AJP服務禁用掉便可。

<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->
1

 


這裏通過9次測試,測試結果以下704 730 736 728 730 727 714 708 735 平均是723

能夠看到,禁用AJP服務後,吞吐量會有所提高。

固然了,測試不必定準確,須要多測試幾回才能看出是否有提高。

設置線程池
經過設置線程池,調整線程池相關的參數進行測試tomcat的性能。有關線程池更多更詳細的配置參考Tomcat官網提供的配置詳解

最大線程數爲150,初始爲4
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4" prestartminSpareThreads="true"/>

<!--在Connector中設置executor屬性指向上面的執行器-->
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
1
2
3
4
5
6
7


通過9次測試,測試結果以下705 725 702 729 733 738 735 728 平均是724

最大線程數爲500,初始爲50
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="500" minSpareThreads="50" prestartminSpareThreads="true"/>

<!--在Connector中設置executor屬性指向上面的執行器-->
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
1
2
3
4
5
6
7
測試結果:733 724 718 728 734 721 720 723 平均725

吞吐量爲725次/秒,性能有所提高。

最大線程數爲1000,初始爲200
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="1000" minSpareThreads="200" prestartminSpareThreads="true"/>

<!--在Connector中設置executor屬性指向上面的執行器-->
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
1
2
3
4
5
6
7
吞吐量爲732,性能有所提高。

測試結果 737 729 730 738 735 726 725 740 平均732

最大線程數爲5000,初始爲1000
是不是線程數最多,速度越快呢? 咱們來測試下。

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="5000" minSpareThreads="1000" prestartminSpareThreads="true"/>

<!--在Connector中設置executor屬性指向上面的執行器-->
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
1
2
3
4
5
6
7
測試結果 727 733 728 725 738 729 737 735 739 平均732

能夠看到,雖然最大線程已經設置到5000,可是實際測試效果並不理想,而且平均的響應時間也邊長了,因此單純靠提高線程數量是不能一直獲得性能提高的。

設置最大等待隊列數
默認狀況下,請求發送到tomcat,若是tomcat正忙,那麼該請求會一直等待。這樣雖然能夠保證每一個請求都能請求到,可是請求時間就會邊長。

有些時候,咱們也不必定要求請求必定等待,能夠設置最大等待隊列大小,若是超過就不等待了。這樣雖然有些請求是失敗的,可是請求時間會雖短。典型的應用:12306。

<!--最大等待數爲100-->
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="500" minSpareThreads="100" prestartminSpareThreads="true" maxQueueSize="100"/>

<!--在Connector中設置executor屬性指向上面的執行器-->
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
1
2
3
4
5
6
7
8


測試結果:

平均響應時間:0.438秒,響應時間明顯縮短
錯誤率:43.07%,錯誤率超過40%,也能夠理解,最大線程爲500,測試的併發爲1000
吞吐量:1359次/秒,吞吐量明顯提高
結論:響應時間、吞吐量這2個指標須要找到平衡才能達到更好的性能。

設置nio2的運行模式
將最大線程設置爲500進行測試:

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="500" minSpareThreads="100" prestartminSpareThreads="true"/>

<!-- 設置nio2 -->
<Connector executor="tomcatThreadPool" port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
connectionTimeout="20000"
redirectPort="8443" />
1
2
3
4
5
6
7
從測試結果能夠看到,平均響應時間有縮短,吞吐量有提高,能夠得出結論:nio2的性能要高於nio。

參數說明與最佳實踐
具體參數參考官網說明

執行器參數說明(加粗是重點)
Attribute Description
threadPriority (優先級) (int) 執行程序中線程的線程優先級,默認值爲 5(Thread.NORM_PRIORITY常量的值)
daemon(守護進程) (布爾) 線程是否應該是守護程序線程,默認值爲 true
namePrefix(名稱前綴) (String) 執行程序建立的每一個線程的名稱前綴。單個線程的線程名稱將爲namePrefix+threadNumber
maxThreads(最大線程數) (int) 此池中活動線程的最大數量,默認爲 200
minSpareThreads(最小活躍線程數) (int) 始終保持活動狀態的最小線程數(空閒和活動),默認值爲 25
maxIdleTime(空閒線程等待時間) (int) 空閒線程關閉以前的毫秒數,除非活動線程的數目小於或等於minSpareThreads。默認值爲60000(1分鐘)
maxQueueSize(最大的等待隊裏數,超過則請求拒絕) (int) 在咱們拒絕執行以前能夠排隊等待執行的可運行任務的最大數量。默認值爲Integer.MAX_VALUE
prestartminSpareThreads(是否在啓動時就生成minSpareThreads個線程) (boolean) 在啓動執行程序時是否應啓動minSpareThreads,默認值爲 false
threadRenewalDelay(重建線程的時間間隔) (long) 若是配置了ThreadLocalLeakPreventionListener,它將通知該執行程序已中止的上下文。上下文中止後,池中的線程將更新。爲避免同時更新全部線程,此選項設置了任意兩個線程之間的延遲。該值以毫秒爲單位,默認值爲1000ms。若是值爲負,則不更新線程。
執行器最佳實踐
此最佳配置僅供參考

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="800" minSpareThreads="100" maxQueueSize="100" prestartminSpareThreads="true"/>
1
2
鏈接器參數說明
能夠看到除了這幾個基本配置外並沒有特殊功能,因此咱們須要對 Connector 進行擴展。

其中Connector 支持參數屬性能夠參考Tomcat官方網站,本文就只介紹些經常使用的。

通用屬性(加粗是重點)
Attribute Description
allowTrace 若是須要服務器可以處理用戶的HAED/TRACE請求,這個值應該設置爲true,默認值是false
asyncTimeout 默認超不時候以毫秒爲單位的異步懇求。如果沒有指定,該屬性被設置爲10000(10秒)
enableLookups 設置爲true是否要調用以 request.getRemoteHost()執行DNS查找以返回遠程客戶端的實際主機名。設置爲false跳過DNS查找並改成以字符串形式返回IP地址(從而提升性能)。默認狀況下,DNS查找被禁用。
maxHeaderCount 容器容許的請求頭字段的最大數目。請求中包含比指定的限制更多的頭字段將被拒絕。值小於0表示沒有限制。若是沒有指定,默認設置爲100。
maxParameterCount 將被容器自動解析的最大數量的參數和值對(GET加上POST)。參數值對超出此限制將被忽略。值小於0表示沒有限制。若是沒有指定,默認爲10000。請注意, FailedRequestFilter 過濾器能夠用來拒絕達到了極限值的請求。
maxPostSize 容器FORM URL參數解析將處理的POST的最大大小(以字節爲單位)。能夠經過將此屬性設置爲小於零的值來禁用該限制。若是未指定,則此屬性設置爲2097152(2兆字節)。請注意, FailedRequestFilter 可使用拒絕超過此限制的請求。
maxSavePostSize 將被容器在FORM或CLIENT-CERT認證中保存/緩衝的POST的最大尺寸(以字節爲單位)。對於這兩種類型的身份驗證,在用戶身份驗證之 前,POST將被保存/緩衝。對於POST CLIENT-CERT認證,處理該請求的SSL握手和緩衝清空期間,POST將被緩存。對於Form認證,POST將被保存,同時用戶將被重定向到登錄 表單。POST將被一直保留直到用戶成功認證或者認證請求關聯的會話超時。將此屬性設置爲-1能夠禁用此限制。將此屬性設置爲0,POST數據在身份驗證 過程當中將不被保存。若是沒有指定,該屬性設置爲4096(4千字節)。
parseBodyMethods 以逗號分隔的HTTP方法列表,經過方法列表,等同於POST方法,request 正文將被解析成請求參數。這在RESTful應用程序要支持以POST式的語義解析PUT請求中是很是有用的。須要注意的是設置其餘值(不是POST)會致使Tomcat的行爲違反servlet規範的目的。在這裏爲了符合HTTP規範明確禁止HTTP方法TRACE。默認值是POST
port 鏈接器 將在其上建立服務器套接字並等待傳入鏈接的TCP端口號。您的操做系統將僅容許一個服務器應用程序偵聽特定IP地址上的特定端口號。若是使用特殊值0(零),則Tomcat將隨機選擇一個空閒端口用於此鏈接器。這一般僅在嵌入式和測試應用程序中有用。
protocol 設置協議以處理傳入流量。默認值爲 HTTP/1.1使用自動切換機制選擇基於Java NIO的鏈接器或基於APR / native的鏈接器。若是PATH(Windows)或LD_LIBRARY_PATH(在大多數Unix系統上)環境變量包含Tomcat本機庫,而且AprLifecycleListener用於初始化APR的庫的useAprConnector屬性設置爲 true,則將使用APR /本機鏈接器。若是找不到本機庫或未配置屬性,則將使用基於Java NIO的鏈接器。請注意,APR /本機鏈接器的HTTPS設置與Java鏈接器的設置不一樣。
要使用顯式協議而不是依賴於上述自動切換機制,可使用如下值:
org.apache.coyote.http11.Http11NioProtocol-非阻塞Java NIO鏈接器
org.apache.coyote.http11.Http11Nio2Protocol-非阻塞Java NIO2鏈接器-APR
org.apache.coyote.http11.Http11AprProtocol/本地鏈接器。
也可使用自定義實現。
看看咱們的鏈接器比較表。對於Java和Java鏈接器,http和https的配置相同。
有關APR鏈接器和特定於APR的SSL設置的更多信息,請訪問APR文檔
proxyName 若是這個鏈接正在使用的代理服務器配置,配置該屬性指定的服務器的名稱,能夠調用request.getServerName()返回。有關更多信息,請參見代理支持。
proxyPort 若是這個鏈接正在使用的代理服務器配置,配置該屬性指定服務器端口,能夠調用request.getServerPort()返回。有關更多信息,請參見代理支持。
redirectPort 若是該鏈接器支持非SSL請求,而且接收到的請求爲知足安全約束須要SSL傳輸, Catalina 將自動將請求重定向到指定的端口號。
scheme 將該屬性設置爲你想調用request.getScheme()返回的協議的名稱。例如,對於SSL鏈接器,你會將此屬性設置爲「HTTPS 」。默認值是「 HTTP 」。
secure 若是你想調用request.isSecure()收到此鏈接器的請求返回true,請該該屬性設置爲true。您但願SSL鏈接器或非SSL鏈接器接收數據經過一個SSL加速器,像加密卡,SSL設備,甚至一個web服務器。默認值是假的。
URIEncoding 解決咱們的亂碼問題,這將指定使用的字符編碼,來解碼URI字符。若是沒有指定,ISO-8859-1將被使用。
useBodyEncodingForURI 這指定是否應該用於URI查詢參數,而不是使用URIEncoding contentType中指定的編碼。此設置兼容性Tomcat 4.1.x版(該版在contentType中指定編碼,或者使用request.setCharacterEncoding的方法顯式設置(參數爲 URL傳來的值)。默認值false。
useIPVHosts 將該屬性設置爲true會致使Tomcat使用收到請求的IP地址,來肯定將請求發送到哪一個主機。默認值是假的。
xpoweredBy 將此屬性設置爲true會致使Tomcat支持使用Servlet規範的通知,(在規範中推薦使用頭字段)。默認值是假的。
標準實現(加粗是重點)
除了上面列出的常見的鏈接器屬性,標準的HTTP鏈接器(BIO,NIO和APR/native)都支持如下屬性。

Attribute Description
acceptCount 當全部可能的請求處理線程都在使用時,傳入鏈接請求的最大隊列長度。當隊列滿時收到的任何請求將被拒絕。默認值是100。
acceptorThreadCount 用於接受鏈接的線程的數量。在一個多CPU的機器上,增長該值,雖然你可能不會真正須要超過2個。此外,有不少非保持活動鏈接,您可能須要增長這個值。默認值是 1。
acceptorThreadPriority 接收器線程的優先級。該線程用來接受新的鏈接。默認值是5(java.lang.Thread.NORM_PRIORITY常量)。更多這個優先級是什麼意思的詳細信息,請查看java.lang.Thread的類的JavaDoc 。
address 對於擁有多個IP地址的服務器,該屬性指定哪一個地址將被用於在指定端口上監聽。默認狀況下,該端口將被用於與服務器相關聯的全部IP地址。
bindOnInit 控制鏈接器綁定時套接字的使用。缺省狀況,當鏈接器被啓動時套接字被綁定和當鏈接器被銷燬時套接字解除綁定。若是設置爲false,鏈接器啓動時套接字被綁定,鏈接器中止時套接字解除綁定。
compressableMimeType 該值是一個被用於HTTP壓縮的逗號分隔的MIME類型列表。默認值是text / html類型,爲text / xml,text / plain。
compression 一般會在ngnix裏面配置壓縮 ,開啓壓縮GZIP 爲了節省服務器帶寬,鏈接器可使用HTTP/1.1 GZIP壓縮。可接受的參數的值是「off 」(禁用壓縮),「on 」(容許壓縮,這會致使文本數據被壓縮),「force 」(強制在全部的狀況下壓縮),或者一個整數值(這是至關於爲「on」,但指定了輸出以前被壓縮的數據最小量)。若是不知道內容長度但被設置爲「on」或更積極的壓縮,輸出的數據也將被壓縮。若是沒有指定,該屬性被設置爲「關」。 注意:這是使用壓縮(節省您的帶寬)和使用sendfile功能(節省你的CPU週期)之間的權衡。若是鏈接器支持sendfile功能,例如NIO鏈接,則使用sendfile將優先於壓縮。症狀是48 KB的靜態文件將未壓縮就發送。你能夠以下文所述經過設置鏈接器的useSendfile屬性來關閉sendfile,或在默認的conf/web.xml或者你的web應用的web.xml中配置DefaultServlet來改變sendfile的使用量閾值。
compressionMinSize 若是壓縮被設置爲「on」,那麼該屬性能夠用於指定在輸出以前被壓縮的數據的最小量。若是未指定,此屬性默認爲「2048」。
connectionLinger 鏈接器的套接字被關閉時的逗留秒數。若是沒有指定,將使用默認的JVM。
connectionTimeout 在將提交的請求URI行呈現以後,鏈接器將等待接受鏈接的毫秒數。使用值-1表示沒有超時(即無限)。默認值是60000(60秒),但請注意,Tomcat的標準server.xml中,設置爲20000(即20秒)。
connectionUploadTimeout 上傳數據過程當中,指定的以毫秒爲單位超時時間。只有在設置disableUploadTimeout爲false有效。
disableUploadTimeout 此標誌容許servlet容器在數據上傳時使用不一樣的鏈接超時,一般較長。若是沒有指定,該屬性被設置爲true,禁用上傳超時。
executor 指向Executor元素的引用。若是這個屬性被設置,而且被命名的executor存在,鏈接器將使用這個executor,而其餘全部線程相關屬性將被忽略。請注意共享的executor若是沒有指定到一個鏈接器,則該鏈接器將使用一個私有的,內部的executor來提供線程池。
executorTerminationTimeoutMillis The time that the private internal executor will wait for request processing threads to terminate before continuing with the process of stopping the connector. If not set, the default is 0 (zero) for the BIO connector and 5000 (5 seconds) for the NIO and APR/native connectors.
keepAliveTimeout 此鏈接器在關閉鏈接以前將等待另外一個HTTP請求的毫秒數。默認值是使用已設置的connectionTimeout屬性的值。使用值-1表示沒有超時(即無限)。
maxConnections 在任何給定的時間服務器接受並處理的最大鏈接數。當這個數字已經達到了,服務器將不會接受任何鏈接,直到鏈接的數量降到低於此值。基於acceptCount的設置,操做系統可能仍然接受鏈接。默認值根據不一樣的鏈接器類型而不一樣。對於BIO,默認的是maxThreads的值,除非使用了Executor,在這種狀況下默認值是executor的maxThreads值 。對於NIO的默認值是10000。APR /native的默認值是8192。 須要注意的是Windows系統的APR/native,所配置的值將減小到小於或等於maxConnections的1024的倍數的最大值。這樣作是出於性能方面的考慮。若是設置的值-1,maxConnections功能被禁用,並且鏈接數將不作計算。
maxExtensionSize 限制HTTP區塊請求中區塊擴展的總長度。若是值爲-1,則不施加任何限制。若是未指定,8192將使用默認值。
maxHttpHeaderSize 請求和響應的HTTP頭的(以字節爲單位的)最大尺寸。若是沒有指定,該屬性被設置爲8192(8 KB)。
maxKeepAliveRequests HTTP請求最大長鏈接個數。將此屬性設置爲1,將禁用HTTP/1.0、以及HTTP/1.1的長鏈接。設置爲-1,不由用。若是沒有指定,該屬性被設置爲100。
maxSwallowSize Tomcat會爲停止的上載而吞下的請求正文字節的最大數量(不包括傳輸編碼開銷)。上載停止是指Tomcat知道將忽略請求主體,但客戶端仍將其發送。若是Tomcat不吞嚥該主體,則客戶端不太可能看到響應。若是未指定,將使用默認值2097152(2兆字節)。小於零的值表示不該強制執行任何限制。
maxThreads 最多同時處理的鏈接數,Tomcat使用線程來處理接收的每一個請求。這個值表示Tomcat可建立的最大的線程數。若是沒有指定,該屬性被設置爲200。若是使用了execute將忽略此鏈接器的該屬性,鏈接器將使用execute,而不是一個內部線程池來處理請求。
maxTrailerSize 限制一個分塊的HTTP請求中的最後一個塊的尾隨標頭的總長度。若是該值是-1,沒有限制的被強加。若是沒有指定,默認值是8192。
minSpareThreads 始終保持運行最小線程數。若是沒有指定,則默認爲10。
noCompressionUserAgents 該值是一個正則表達式(使用java.util.regex),匹配不該該使用壓縮的HTTP客戶端的用戶代理標頭。由於這些客戶端,雖然他們宣稱支持壓縮功能,但實現不完整。默認值是一個空字符串(正則表達式匹配禁用)。
processorCache 協議處理器緩存Processor對象以提升性能。此設置規定了這些對象有多少能獲得緩存。-1意味着無限制,默認爲200。若是不使用Servlet 3.0的異步處理,一個好的默認是使用maxThreads設置。若是使用Servlet 3.0的異步處理,一個好的默認是使用maxThreads和最大預期的併發請求(同步和異步)的最大值中的較大值。
restrictedUserAgents 該值是一個正則表達式(使用java.util.regex),匹配用戶代理頭的HTTP瀏覽器將不能使用HTTP/1.1或HTTP/1.0長鏈接,即便該瀏覽器宣稱支持這些功能的。默認值是一個空字符串(正則表達式匹配禁用)。
server 覆蓋服務器的HTTP響應頭。若是設置了這個屬性的值將覆蓋Web應用程序設置的Tomcat的默認頭和任何服務器頭。若是沒有設置,應用程序指定的任何值將被使用。若是應用程序沒有指定一個值,那麼Apache-Coyote/1.1將被使用。除非你是偏執狂,你將再也不須要此功能。
socketBuffer 爲套接字輸出緩衝而提供的緩衝區的大小(以字節爲單位)。-1能夠被指定來禁止使用的緩衝區。默認狀況下,一個9000個字節的緩衝區將被使用。
SSLEnabled 在鏈接器上使用此屬性來啓用SSL加密傳輸。若是要打開SSL握手/加密/解密,請設置true。默認值是false。當設置這個值爲true時,爲了傳遞正確的request.getScheme()和 request.isSecure()到servlets,你須要設置scheme和secure屬性。更多信息請查看SSL支持。
tcpNoDelay 若是設置爲true,TCP_NO_DELAY選項將被設置在服務器上的套接字上,在大多數狀況下,這樣能夠提升性能。默認設置爲true。
threadPriority 在JVM中請求處理線程的優先級。默認值是5(java.lang.Thread.NORM_PRIORITY常量值)。關於優先級的更多詳細信息,請查看java.lang.Thread的類的JavaDoc
upgradeAsyncWriteBufferSize The default size of the buffer to allocate to for asynchronous writes that can not be completed in a single operation. Data that can’t be written immediately will be stored in this buffer until it can be written. If more data needs to be stored than space is available in the buffer than the size of the buffer will be increased for the duration of the write. If not specified the default value of 8192 will be used.
鏈接器最佳實踐
此最佳配置僅供參考

<Connector executor="tomcatThreadPool" port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
connectionTimeout="20000" redirectPort="8443"
enableLookups="false" maxPostSize="10485760" URIEncoding="UTF-8" acceptCount="100" acceptorThreadCount="2" disableUploadTimeout="true" maxConnections="10000" SSLEnabled="false"/>
1
2
3
調整JVM參數進行優化
接下來,經過設置jvm參數進行優化,爲了測試一致性,依然將最大線程數設置爲500,啓用nio2運行模式

設置並行垃圾回收器
在/bin/catalina.sh文件第一行添加以下參數,gc日誌輸出到/logs/gc.log

#年輕代、老年代均使用並行收集器,初始堆內存64M,最大堆內存512M
JAVA_OPTS="-XX:+UseParallelGC -XX:+UseParallelOldGC -Xms64m -Xmx512m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:../logs/gc.log"
1
2


測試結果與默認的JVM參數結果接近。

查看gc日誌文件
將gc.log文件上傳到gceasy.io查看gc中是否存在問題。上傳文件後須要等待一段時間,須要耐心等待。

 

問題一:系統所消耗的時間大於用戶時間

 

若是在報告中顯示System Time greater than User Time,系統所消耗的時間大於用戶時間,這反應出的服務器的性能存在瓶頸,調度CPU等資源所消耗的時間要長一些。

問題二:線程暫停時間有點長

 

能夠關鍵指標中能夠看出,吞吐量表現不錯,可是gc時,線程的暫停時間稍有點長。

問題三:GC總次數過多

 

經過GC的統計能夠看出:

年輕代的gc有100次,次數有點多,說明年輕代設置的大小不合適,須要調整
FullGC有7次,說明堆內存的大小不合適,須要調整
問題四:年輕代內存不足致使GC

 

從GC緣由的能夠看出,年輕代大小設置不合理,致使了屢次GC。

調全年輕代大小
調整jvm配置參數

JAVA_OPTS="-XX:+UseParallelGC -XX:+UseParallelOldGC -Xms128m -Xmx1024m -XX:NewSize=64m -XX:MaxNewSize=256m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:../logs/gc.log"
1
將初始堆大小設置爲128m,最大爲1024m,初始年輕代大小64m,年輕代最大256m

 

從測試結果來看,吞吐量以及響應時間均有提高。

查看gc日誌

 

能夠看到GC次數要明顯減小,說明調整是有效的。

 

GC次數有所減小

 

設置G1垃圾回收器
#設置了最大停頓時間100毫秒,初始堆內存128m,最大堆內存1024m
JAVA_OPTS="-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -Xms128m -Xmx1024m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:../logs/gc.log"
1
2
測試結果

 

能夠看到,吞吐量有所提高,評價響應時間也有所縮短。

 

G1集合階段統計

 

JVM配置最佳實踐
此最佳配置僅供參考

JAVA_OPTS="-Dfile.encoding=UTF-8-server -Xms1024m -Xmx2048m -XX:NewSize=512m -XX:MaxNewSize=1024m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:MaxTenuringThreshold=10-XX:NewRatio=2 -XX:+DisableExplicitGC"
1
參數說明:

file.encoding 默認文件編碼

-Xmx1024m 設置JVM最大可用內存爲1024MB

-Xms1024m 設置JVM最小內存爲1024m。此值能夠設置與-Xmx相同,以免每次垃圾回收完成後JVM從新分配內存。

-XX:NewSize 設置年輕代大小

-XX:MaxNewSize 設置最大的年輕代大小

-XX:PermSize 設置永久代大小

-XX:MaxPermSize 設置最大永久代大小

-XX:NewRatio=4 設置年輕代(包括Eden和兩個Survivor區)與終身代的比值(除去永久代)。設置爲4,則年輕代與終身代所佔比值爲1:4,年輕代佔整個堆棧的1/5

-XX:MaxTenuringThreshold=0 設置垃圾最大年齡,默認爲:15。若是設置爲0的話,則年輕代對象不通過Survivor區,直接進入年老代。對於年老代比較多的應用,能夠提升效率。若是將此值設置爲一個較大值,則年輕代對象會在Survivor區進行屢次複製,這樣能夠增長對象再年輕代的存活時間,增長在年輕代即被回收的概論。

-XX:+DisableExplicitGC 這個將會忽略手動調用GC的代碼使得System.gc()的調用就會變成一個空調用,徹底不會觸發任何GC。

總結
經過上述的測試,能夠總結出,對tomcat性能優化就是須要不斷的進行調整參數,而後測試結果,可能會調優也可能會調差,這時就須要藉助於gc的可視化工具來看gc的狀況。再幫我咱們作出決策應該調整哪些參數。

再次重申本博客的目的不在於給出最佳配置,而是帶領開發者,可以從實際狀況出發,經過不斷的調節tomcat和jvm參數,去發現吞吐量,平均響應時間和錯誤率等信息的變化,同時根據服務器的cpu和內存等信息,結合接口的業務邏輯,最好是測試使用率最高,併發最大,或者是最重要的接口(好比下單支付接口),設置最優的tomcat和jvm配置參數。————————————————版權聲明:本文爲CSDN博主「ThinkWon」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接及本聲明。原文連接:https://blog.csdn.net/ThinkWon/article/details/102744033

相關文章
相關標籤/搜索