一.Tomcat內存優化
1.JAVA_OPTS參數說明
Tomcat內存優化主要是對 tomcat 啓動參數優化,咱們能夠在 tomcat 的啓動腳本 catalina.sh 中設置 JAVA_OPTS參數。javascript
服務器參數配置php
![](http://static.javashuo.com/static/loading.gif)
配置完成後可重啓Tomcat ,經過如下命令進行查看配置是否生效:css
1. 首先查看Tomcat 進程號:html
ps -ef|grep java
![點擊查看原始大小圖片](http://static.javashuo.com/static/loading.gif)
咱們能夠看到Tomcat 進程號是 12222 。前端
1. 查看是否配置生效:java
sudo jmap -heap 12222
![](http://static.javashuo.com/static/loading.gif)
咱們能夠看到MaxHeapSize 等參數已經生效。linux
優化 server.xml
Tomcat的主配置文件,該文件中包含不少主要元素,好比Service、Connector、Host等,這些元素都會建立軟件"對象"、排序及進程管道中設置的這些元素嵌套方,使咱們能夠執行過濾、分組等工做。nginx
若是要對該文件作優化,咱們須要先了解該文件的結構!web
server.xml的結構圖:shell
![](http://static.javashuo.com/static/loading.gif)
該文件描述瞭如何啓動Tomcat Server
<Server>
<Listener />
<GlobaNamingResources>
</GlobaNamingResources
<Service>
<Connector />
<Engine>
<Logger />
<Realm />
<host>
<Logger />
<Context />
</host>
</Engine>
</Service>
</Server>
針對該文件,咱們須要優化的點有以下:
一、 maxThreads 鏈接數限制
maxThreads 是 Tomcat 所能接受最大鏈接數。通常設置不要超過8000以上,若是你的網站訪問量很是大可能使用運行多個Tomcat實例的方法, 即,在一個服務器上啓動多個tomcat而後作負載均衡處理。
這裏還須要注意的一點是,tomcat 和 php 不一樣。php能夠按照cpu和內存的狀況去配置鏈接數,上萬很正常。而 java 還須要注意 jvm 的參數配置。若是不注意就會由於jvm參數太小而崩潰。
二、多虛擬主機
強烈建議不要使用 Tomcat 的虛擬主機,推薦每一個站點使用一個實例。即,能夠啓動多個 Tomcat,而不是啓動一個 Tomcat 裏面包含多個虛擬主機。由於 Tomcat是多線程,共享內存,任何一個虛擬主機中的應用崩潰,都會影響到全部應用程序。雖然採用多實例的方式會產生過多的開銷,但至少保障了應用程序的隔離和安全。
三、壓錯傳輸
tomcat做爲一個應用服務器,也是支持 gzip 壓縮功能的。咱們能夠在 server.xml 配置文件中的 Connector 節點中配置以下參數,來實現對指定資源類型進行壓縮。
compression="on" # 打開壓縮功能
compressionMinSize="50" # 啓用壓縮的輸出內容大小,默認爲2KB
noCompressionUserAgents="gozilla, traviata" # 對於如下的瀏覽器,不啓用壓縮
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" # 哪些資源類型須要壓縮
提示:
Tomcat 的壓縮是在客戶端請求服務器對應資源後,從服務器端將資源文件壓縮,再輸出到客戶端,由客戶端的瀏覽器負責解壓縮並瀏覽。相對於普通的瀏覽過程 HTML、CSS、Javascript和Text,它能夠節省40% 左右的流量。更爲重要的是,它能夠對動態生成的,包括CGI、PHP、JSP、ASP、Servlet,SHTML等輸出的網頁也能進行壓縮,壓縮效率也很高。可是, 壓縮會增長 Tomcat 的負擔,所以最好採用Nginx + Tomcat 或者 Apache + Tomcat 方式,將壓縮的任務交由 Nginx/Apache 去作。
一旦啓用了這個壓縮功能後,咱們怎麼來測試壓縮是否有效呢?首先Tomcat是根據瀏覽器請求頭中的accept-encoding來判斷瀏覽器是否支持 壓縮功能,若是這個值包含有gzip,就代表瀏覽器支持gzip壓縮內容的瀏覽,因此咱們能夠用httpclient來寫一個這樣的簡單測試程序
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
public class HttpTester {
public static void main(String[] args) throws Exception{
HttpClient http = new HttpClient();
GetMethod get = new GetMethod("http://www.dlog.cn/js/prototype.js");
try{
get.addRequestHeader("accept-encoding", "gzip,deflate");
get.addRequestHeader("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Alexa Toolbar; Maxthon 2.0)");
int er = http.executeMethod(get);
if(er==200){
System.out.println(get.getResponseContentLength());
String html = get.getResponseBodyAsString();
System.out.println(html);
System.out.println(html.getBytes().length);
}
}finally{
get.releaseConnection();
}
}
}
執行這個測試程序,看看它所輸出的是什麼內容,若是輸出的是一些亂碼,以及打印內容的長度遠小於實際的長度,那麼恭喜你,你的配置生效了,你會發現你網站的瀏覽速度比之前快多了。
四、管理AJP端口
AJP是爲 Tomcat 與 HTTP 服務器之間通訊而定製的協議,能提供較高的通訊速度和效率。若是tomcat前端放的是apache的時候,會使用到AJP這個鏈接器。因爲咱們公司前端是由nginx作的反向代理,所以不使用此鏈接器,所以須要註銷掉該鏈接器。
<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->
五、更改關閉 Tomcat 實例的指令
server.xml中定義了能夠直接關閉 Tomcat 實例的管理端口。咱們經過 telnet 鏈接上該端口以後,輸入 SHUTDOWN (此爲默認關閉指令)便可關閉 Tomcat 實例(注意,此時雖然實例關閉了,可是進程仍是存在的)。因爲默認關閉 Tomcat 的端口和指令都很簡單。默認端口爲8005,指令爲SHUTDOWN 。所以咱們須要將關閉指令修改複雜一點。
固然,在新版的 Tomcat 中該端口僅監聽在127.0.0.1上,所以你們也沒必要擔憂。除非黑客登錄到tomcat本機去執行關閉操做。
修改實例:
<Server port="8005" shutdow n="9SDKJ29jksjf23sjf0LSDF92JKS9DKkjsd">
六、更改 Tomcat 的服務監聽端口
通常公司的 Tomcat 都是放在內網的,所以咱們針對 Tomcat 服務的監聽地址都是內網地址。
修改實例:
<Connector port="8080" address="172.16.100.1" />
七、關閉war自動部署
默認 Tomcat 是開啓了對war包的熱部署的。爲了防止被植入木馬等惡意程序,所以咱們要關閉自動部署。
修改實例:
<Host name="localhost" appBase=""
unpackWARs="false" autoDeploy="false">
二.Tomcat併發優化
1.調整鏈接器connector的併發處理能力
在Tomcat 配置文件 server.xml 中的 <Connector ... /> 配置中
1.參數說明
maxThreads 客戶請求最大線程數
minSpareThreads Tomcat初始化時建立的 socket 線程數
maxSpareThreads Tomcat鏈接器的最大空閒 socket 線程數
minProcessors:最小空閒鏈接線程數,用於提升系統處理性能,默認值爲 10
maxProcessors:最大鏈接線程數,即:併發處理的最大請求數,默認值爲 75
acceptCount:容許的最大鏈接數,應大於等於 maxProcessors ,默認值爲 100
enableLookups:是否反查域名,取值爲: true 或 false 。爲了提升處理能力,應設置爲 false
redirectPort 在須要基於安全通道的場合,把客戶請求轉發到基於SSL 的 redirectPort 端口
acceptAccount 監聽端口隊列最大數,滿了以後客戶請求會被拒絕(不能小於maxSpareThreads )
connectionTimeout:網絡鏈接超時,單位:毫秒。設置爲 0 表示永不超時,這樣設置有隱患的。一般可設置爲30000 毫秒。
URIEncoding URL統一編碼
其中和最大鏈接數相關的參數爲maxProcessors 和 acceptCount 。若是要加大併發鏈接數,應同時加大這兩個參數。
web server容許的最大鏈接數還受制於操做系統的內核參數設置,一般 Windows 是 2000 個左右, Linux 是1000 個左右。
2.Tomcat中的配置示例
<Connector port="9027"
protocol="HTTP/1.1"
maxHttpHeaderSize="8192"
maxThreads="1000"
minSpareThreads="100"
maxSpareThreads="1000"
minProcessors="100"
maxProcessors="1000"
enableLookups="false"
URIEncoding="utf-8"
acceptCount="1000"
redirectPort="8443"
disableUploadTimeout="true"/>
3.Tomcat緩存優化
tomcat的maxThreads、acceptCount(最大線程數、最大排隊數)
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="800" acceptCount="1000"/>
tomcate -->config --> server.xml
其中最後兩個參數意義以下:
maxThreads:tomcat起動的最大線程數,即同時處理的任務個數,默認值爲200
acceptCount:當tomcat起動的線程數達到最大時,接受排隊的請求個數,默認值爲100
這兩個值如何起做用,請看下面三種狀況
狀況1:接受一個請求,此時tomcat起動的線程數沒有到達maxThreads,tomcat會起動一個線程來處理此請求。
狀況2:接受一個請求,此時tomcat起動的線程數已經到達maxThreads,tomcat會把此請求放入等待隊列,等待空閒線程。
狀況3:接受一個請求,此時tomcat起動的線程數已經到達maxThreads,等待隊列中的請求個數也達到了acceptCount,此時tomcat會直接拒絕這次請求,返回connection refused
maxThreads如何配置
通常的服務器操做都包括量方面:1計算(主要消耗cpu),2等待(io、數據庫等)
第一種極端狀況,若是咱們的操做是純粹的計算,那麼系統響應時間的主要限制就是cpu的運算能力,此時maxThreads應該儘可能設的小,下降同一時間內爭搶cpu的線程個數,能夠提升計算效率,提升系統的總體處理能力。
第二種極端狀況,若是咱們的操做純粹是IO或者數據庫,那麼響應時間的主要限制就變爲等待外部資源,此時maxThreads應該儘可能設的大,這樣才能提升同時處理請求的個數,從而提升系統總體的處理能力。此狀況下由於tomcat同時處理的請求量會比較大,因此須要關注一下tomcat的虛擬機內存設置和linux的open file限制。
我在測試時遇到一個問題,maxThreads我設置的比較大好比3000,當服務的線程數大到必定程度時,通常是2000出頭,單次請求的響應時間就會急劇的增長,
百思不得其解這是爲何,四處尋求答案無果,最後我總結的緣由多是cpu在線程切換時消耗的時間隨着線程數量的增長愈來愈大,
cpu把大多數時間都用來在這2000多個線程直接切換上了,固然cpu就沒有時間來處理咱們的程序了。
之前一直簡單的認爲多線程=高效率。。其實多線程自己並不能提升cpu效率,線程過多反而會下降cpu效率。
當cpu核心數<線程數時,cpu就須要在多個線程直接來回切換,以保證每一個線程都會得到cpu時間,即一般咱們說的併發執行。
因此maxThreads的配置絕對不是越大越好。
現實應用中,咱們的操做都會包含以上兩種類型(計算、等待),因此maxThreads的配置並無一個最優值,必定要根據具體狀況來配置。
最好的作法是:在不斷測試的基礎上,不斷調整、優化,才能獲得最合理的配置。
acceptCount的配置,我通常是設置的跟maxThreads同樣大,這個值應該是主要根據應用的訪問峯值與平均值來權衡配置的。
若是設的較小,能夠保證接受的請求較快相應,可是超出的請求可能就直接被拒絕
若是設的較大,可能就會出現大量的請求超時的狀況,由於咱們系統的處理能力是必定的。
提示
不少作過php運維的朋友在這裏會犯一個大錯誤,php優化服務器一般怎作法是安裝cpu以及內存的狀況配置鏈接數,鏈接數過萬都很正常,但java不一樣jvm配置要很是當心,稍有差錯就會崩潰。
maxThreads 配置要結合 JVM -Xmx 參數調整,也就是要考慮內存開銷。
在線上環境中咱們是採用了tomcat做爲Web服務器,它的處理性能直接關係到用戶體驗,在平時的工做和學習中,概括出如下七種調優經驗。
1. 服務器資源
服務器所能提供CPU、內存、硬盤的性能對處理能力有決定性影響。
(1) 對於高併發狀況下會有大量的運算,那麼CPU的速度會直接影響處處理速度。
(2) 內存在大量數據處理的狀況下,將會有較大的內存容量需求,能夠用-Xmx -Xms -XX:MaxPermSize等參數對內存不一樣功能塊進行劃分。咱們以前就遇到過內存分配不足,致使虛擬機一直處於full GC,從而致使處理能力嚴重降低。
(3) 硬盤主要問題就是讀寫性能,當大量文件進行讀寫時,磁盤極容易成爲性能瓶頸。最好的辦法仍是利用下面提到的緩存。
2. 利用緩存和壓縮
對於靜態頁面最好是可以緩存起來,這樣就沒必要每次從磁盤上讀。這裏咱們採用了Nginx做爲緩存服務器,將圖片、css、js文件都進行了緩存,有效的減小了後端tomcat的訪問。
另外,爲了能加快網絡傳輸速度,開啓gzip壓縮也是必不可少的。但考慮到tomcat已經須要處理不少東西了,因此把這個壓縮的工做就交給前端的Nginx來完成。能夠參考以前寫的《利用nginx加速web訪問》。
除了文本能夠用gzip壓縮,其實不少圖片也能夠用圖像處理工具預先進行壓縮,找到一個平衡點可讓畫質損失很小而文件能夠減少不少。曾經我就見過一個圖片從300多kb壓縮到幾十kb,本身幾乎看不出來區別。
3. 採用集羣
單個服務器性能老是有限的,最好的辦法天然是實現橫向擴展,那麼組建tomcat集羣是有效提高性能的手段。咱們仍是採用了Nginx來做爲請求分流的服務器,後端多個tomcat共享session來協同工做。能夠參考以前寫的《利用nginx+tomcat+memcached組建web服務器負載均衡》。
4. 優化tomcat參數
這裏以tomcat7的參數配置爲例,須要修改conf/server.xml文件,主要是優化鏈接配置,關閉客戶端dns查詢。
<Connector port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="500"
minSpareThreads="20"
acceptCount="100"
disableUploadTimeout="true"
enableLookups="false"
URIEncoding="UTF-8" />
5. 改用APR庫
tomcat默認採用的BIO模型,在幾百併發下性能會有很嚴重的降低。tomcat自帶還有NIO的模型,另外也能夠調用APR的庫來實現操做系統級別控制。
<Connector port="80" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
修改成:
<Connector port="80" protocol="org.apache.coyote.http11.Http11NioProtocol " connectionTimeout="20000" redirectPort="8443" />
NIO模型是內置的,調用很方便,只須要將上面配置文件中protocol修改爲org.apache.coyote.http11.Http11NioProtocol,重啓便可生效。上面配置我已經改過了,默認的是HTTP/1.1。
APR則須要安裝第三方庫,在高併發下會讓性能有明顯提高。具體安裝辦法能夠參考http://www.cnblogs.com/huangjingzhou/articles/2097241.html。安裝完成後重啓便可生效。如使用默認protocal就是apr,但最好把將protocol修改爲org.apache.coyote.http11.Http11AprProtocol,會更加明確。
在官方找到一個表格詳細說明了這三種方式的區別:
|
Java Blocking Connector |
Java Nio Blocking Connector |
APR/native Connector |
|
BIO |
NIO |
APR |
Classname |
AjpProtocol |
AjpNioProtocol |
AjpAprProtocol |
Tomcat Version |
3.x onwards |
7.x onwards |
5.5.x onwards |
Support Polling |
NO |
YES |
YES |
Polling Size |
N/A |
maxConnections |
maxConnections |
Read Request Headers |
Blocking |
Sim Blocking |
Blocking |
Read Request Body |
Blocking |
Sim Blocking |
Blocking |
Write Response |
Blocking |
Sim Blocking |
Blocking |
Wait for next Request |
Blocking |
Non Blocking |
Non Blocking |
Max Connections |
maxConnections |
maxConnections |
maxConnections |
6. 優化網絡
Joel也明確提出了優化網卡驅動能夠有效提高性能,這個對於集羣環境工做的時候尤其重要。因爲咱們採用了linux服務器,因此優化內核參數也是一個很是重要的工做。給一個參考的優化參數:
1. 修改/etc/sysctl.cnf文件,在最後追加以下內容:
net.core.netdev_max_backlog = 32768
net.core.somaxconn = 32768
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.ip_local_port_range = 1024 65000 net.ipv4.route.gc_timeout = 100
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000 net.ipv4.tcp_max_orphans = 3276800 net.ipv4.tcp_max_syn_backlog = 65536
2. 保存退出,執行sysctl -p生效
7. 讓測試說話
優化系統最忌諱的就是隻調優不測試,有時不適當的優化反而會讓性能更低。以上全部的優化方法都要在本地進行性能測試事後再不斷調整參數,這樣最終才能達到最佳的優化效果。
補充Bio、Nio、Apr模式的測試結果:
對於這幾種模式,我用ab命令模擬1000併發測試10000詞,測試結果比較意外,爲了確認結果,我每種方式反覆測試了10屢次,而且在兩個服務器上都測試了一遍。結果發現Bio和Nio性能差異很是微弱,難怪默認竟然仍是Bio。可是採用apr,鏈接創建的速度會有50%~100%的提高。直接調用操做系統層果真神速啊,這裏強烈推薦apr方式!
Tomcat從5.5版本開始,支持如下四種Connector的配置分別爲:
<Connector port="8081" protocol="org.apache.coyote.http11.Http11NioProtocol" connectionTimeout="20000" redirectPort="8443"/>
<Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000"
redirectPort="8443"/>
<Connector executor="tomcatThreadPool"
port="8081" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector executor="tomcatThreadPool"
port="8081" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
redirectPort="8443" />
咱們姑且把上面四種Connector按照順序命名爲 NIO, HTTP, POOL, NIOP
爲了避免讓其餘因素影響測試結果,咱們只對一個很簡單的jsp頁面進行測試,這個頁面僅僅是輸出一個Hello World。假設地址是 http://tomcat1/test.jsp
咱們依次對四種Connector進行測試,測試的客戶端在另一臺機器上用ab命令來完成,測試命令爲: ab -c 900 -n 2000 http://tomcat1/test.jsp ,最終的測試結果以下表所示(單位:平均每秒處理的請求數):
NIO HTTP POOL NIOP
281 |
65 |
208 |
365 |
666 |
66 |
110 |
398 |
692 |
65 |
66 |
263 |
256 |
63 |
94 |
459 |
440 |
67 |
145 |
363 |
由這五組數據不難看出,HTTP的性能是很穩定,可是也是最差的,而這種方式就是Tomcat的默認配置。NIO方式波動很大,但沒有低於280 的,NIOP是在NIO的基礎上加入線程池,多是程序處理更復雜了,所以性能不見得比NIO強;而POOL方式則波動很大,測試期間和HTTP方式同樣,不時有停滯。
因爲linux的內核默認限制了最大打開文件數目是1024,所以這次併發數控制在900。
儘管這一個結果在實際的網站中由於各方面因素致使,可能差異沒這麼大,例如受限於數據庫的性能等等的問題。但對咱們在部署網站應用時仍是具備參考價值的。
1. JVM