史上最强Tomcat8性能优化
文章目錄
- 授人以魚不如授人以漁
- 目的
- 服務器資源
- 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配置參數。
目的
通過Tomcat性能優化可以提高網站的并發能力。
Tomcat服務器在JavaEE項目中使用率非常高,所以在生產環境對Tomcat的優化也變得非常重要了。
對于Tomcat的優化,主要是從2個方面入手,一是Tomcat自身的配置,另一個是Tomcat所運行的jvm虛擬機的調優。
服務器資源
服務器所能提供CPU、內存、硬盤的性能對處理能力有決定性影響。硬件我們不說了,這個方面是錢越多越好是吧。
Tomcat配置優化
Linux環境安裝運行Tomcat8
具體的安裝步驟可以參考Linux(CentOS7)安裝Tomcat與設置Tomcat為開機啟動項
如果需要登錄系統,必須配置tomcat用戶,在安裝完Tomcat后,進行如下操作
在/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"/>如果是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>打開瀏覽器進行訪問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" /> -->重啟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" />保存退出,重啟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官網說明
| 類名 | 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" />可以看到已經設置為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 -mtotal used free shared buff/cache available Mem: 7825 850 6241 9 733 6714 Swap: 8063 0 8063部署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訪問接口地址: 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" }]使用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出現原因:
TCP/IP連接數不夠或TIME_WAIT中存在很多鏈接,導致吞吐量低。
解決方案:
從問題的原因分析,有兩種解決方案,一是增加預留給TCP/IP服務的臨時端口的數量,二是加快被占用端口的釋放速度。
解決辦法:
1、打開注冊表:regedit
2、HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ Services\TCPIP\Parameters
3、新建 DWORD值,name:TCPTimedWaitDelay,value:30(十進制) –> 設置為30秒,默認是240秒
4、新建 DWORD值,name:MaxUserPort,value:65534(十進制) –> 設置最大連接數65534
5、重啟系統
第一步:設置測試計劃的名稱
第二步:添加線程組,使用線程模擬用戶的并發
1000個線程,每個線程循環10次,也就是tomcat會接收到10000個請求。
第三步:添加http請求
設置http請求
第四步:添加請求監控
啟動與進行接口測試
查看測試報告
在聚合報告中,重點看吞吐量。
調整Tomcat參數進行優化
通過上面測試可以看出,tomcat在不做任何調整時,吞吐量為697次/秒。這個吞吐量跟接口的業務邏輯關系很大,如果業務邏輯復雜,需要比較長時間計算的,可能吞吐量只有幾十次/秒,我這里測試的時候沒有添加任務業務邏輯,才會出現吞吐量為697次/秒的情況。這里的吞吐量最好是經過多次測試取平均值,因為單次測試具有一定的隨機性
禁用AJP連接
修改conf下的server.xml文件,將AJP服務禁用掉即可。
<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->這里經過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" />經過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" />測試結果: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" />吞吐量為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" />測試結果 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" />測試結果:
- 平均響應時間: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" />從測試結果可以看到,平均響應時間有縮短,吞吐量有提升,可以得出結論:nio2的性能要高于nio。
參數說明與最佳實踐
具體參數參考官網說明
執行器參數說明(加粗是重點)
| 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"/>連接器參數說明
可以看到除了這幾個基本配置外并無特殊功能,所以我們需要對 Connector 進行擴展。
其中Connector 支持參數屬性可以參考Tomcat官方網站,本文就只介紹些常用的。
通用屬性(加粗是重點)
| 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)都支持以下屬性。
| 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"/>調整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"測試結果與默認的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"將初始堆大小設置為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"測試結果
可以看到,吞吐量有所提升,評價響應時間也有所縮短。
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"參數說明:
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配置參數。
總結
以上是生活随笔為你收集整理的史上最强Tomcat8性能优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 需求分析挑战之旅(疯狂的订餐系统)(3)
- 下一篇: 2019浦发春招续