Tomcat并發(fā)量與其配置息息相關(guān), 一般的機(jī)器幾百的并發(fā)量足矣, 如果設(shè)置太高可能引發(fā)各種問題, 內(nèi)存、網(wǎng)絡(luò)等問題也能在高并發(fā)下暴露出來, 因此, 配置參數(shù)的設(shè)置非常重要.
1 Tomcat的3種運(yùn)行模式
1.1 BIO – 同步阻塞IO模式
BIO, 同步阻塞IO, 性能低, 沒有經(jīng)過任何優(yōu)化處理和支持.
服務(wù)器實(shí)現(xiàn)模式為一個連接一個線程, 即客戶端有連接請求時服務(wù)器端就需要啟動一個線程進(jìn)行處理, 如果這個連接不做任何事情會造成不必要的線程開銷, 當(dāng)然可以通過 線程池 機(jī)制改善.
適用場景: BIO方式適用于連接數(shù)比較小且固定的架構(gòu), 這種方式對服務(wù)器資源要求比較高, 有并發(fā)局限, JDK1.4之前的唯一選擇.
1.2 NIO – 同步非阻塞IO模式
是Java SE 1.4及后續(xù)版本提供的一種新的IO操作方式(即java.nio包及其子包). Java NIO是一個基于緩沖區(qū)、并能提供非阻塞IO操作的Java API, 因此NIO也被看成是non-blocking IO(非阻塞式IO)的縮寫, 它擁有比傳統(tǒng)BIO操作更好的并發(fā)性能.
服務(wù)器實(shí)現(xiàn)模式為一個請求一個線程, 即客戶端發(fā)送的連接請求都會注冊到多路復(fù)用器上, 多路復(fù)用器輪詢到連接有IO請求時才啟動一個線程進(jìn)行處理.
適用場景: 適用于連接數(shù)較多且連接比較時間短(輕操作)的架構(gòu), 比如聊天服務(wù)器. 這種方式的并發(fā)性能局限于應(yīng)用中, 編程比較復(fù)雜.
目前Tomcat 8.x默認(rèn)運(yùn)行在NIO模式下.
1.3 APR – 可移植運(yùn)行時模式
APR(Apache Portable Runtime, Apache可移植運(yùn)行時), 是Apache HTTP服務(wù)器的一個支持庫, 它提供了一組映射到底層操作系統(tǒng)的API, 如果操作系統(tǒng)不支持特定功能, APR庫將提供仿真. 因此開發(fā)人員可以使用APR使程序真正跨平臺移植.
此模式的安裝步驟比較繁瑣, 但卻從操作系統(tǒng)層面解決了異步IO的問題, 能大幅度提高應(yīng)用性能.
APR的本質(zhì)是使用 JNI 技術(shù)調(diào)用操作系統(tǒng)底層的IO接口, 所以需要提前安裝必要的依賴, 具體方式后續(xù)給出.
2 Tomcat的并發(fā)配置(配置Connector)
Tomcat的Connector是其接收HTTP請求的關(guān)鍵模塊, 可以通過它來指定IO處理模式, 指定處理該Connector接收到的請求的線程數(shù), 以及其他常用的HTTP策略.
配置路徑: 在 ${TOMCAT_HOME}/conf/server.xml 文件的節(jié)點(diǎn)中進(jìn)行配置.
2.1 使用線程池處理請求
使用線程池, 通過較少的線程資源來處理更多的請求, 從而提高Tomcat的請求處理能力.
前提: 要提前配置至少一個線程池來處理請求, 配置文件為${TOMCAT_HOME}/conf/server.xml.
其中Executor與Connector同級, 多個Connector可以使用同一個線程池來處理請求.
(1) 參考默認(rèn)連接池配置:
<Executor name=”tomcatThreadPool” namePrefix=”catalina-exec-“
maxThreads=”150″ minSpareThreads=”4″/>
(2) 自定義線程池示例:
<Executor name=”tomcatThreadPool” namePrefix=”catalina-exec-”
maxThreads=”200″ minSpareThreads=”10″ maxIdleTime=”600000″
prestartminSpareThreads=”true” maxQueueSize=”100″ />
(3) 線程池參數(shù)說明:
name: 線程池名稱.
namePrefix: 創(chuàng)建的每個線程的名稱前綴, 單獨(dú)的線程名稱為 namePrefix + threadNumber.
maxThreads: 線程池中最大并發(fā)線程數(shù), 默認(rèn)值為200, 一般建議設(shè)置400~ 800 , 要根據(jù)服務(wù)器配置和業(yè)務(wù)需求而定.
minSpareThreads: 最小活躍線程數(shù), 也就是核心線程數(shù), 不會被銷毀, 會一直存在.
prestartminSpareThreads: 是否在啟動程序時就生成minSpareThreads個線程, 默認(rèn)為false, 即不啟動. 若不設(shè)置為true, 則minSpareThreads的設(shè)置就不起作用了.
maxIdleTime: 線程最大空閑時間, 超過該時間后, 空閑線程會被銷毀, 默認(rèn)值為6000, 單位為毫秒.
maxQueueSize: 最大的等待隊(duì)列數(shù), 超過則拒絕請求. 默認(rèn)值為int類型的最大值(Integer.MAX_VALUE), 等同于無限大. 一般不作修改, 避免發(fā)生部分請求未能被處理的情況.
threadPriority: 線程池中線程的優(yōu)先級, 默認(rèn)值為5, 取值范圍: 1 ~ 10.
className:線程池的實(shí)現(xiàn)類, 未指定情況下, 默認(rèn)實(shí)現(xiàn)類為 org.apache.catalina.core.StandardThreadExecutor. 要自定義線程池就需要實(shí)現(xiàn) org.apache.catalina.Executor 接口.
2.2 在Connector中使用線程池
Connector是Tomcat接收請求的入口, 每個Connector都有自己專屬的監(jiān)聽端口.
<Connector executor=”tomcatThreadPool”
port=”8080″ protocol=”HTTP/1.1″
connectionTimeout=”20000″
redirectPort=”8443″ />
(1) Connector的參數(shù)說明:
redirectPort=”8443″ # 基于SSL的端口, 在需要基于安全通道的場合, 比如當(dāng)客戶端的請求協(xié)議是HTTPS時, 將該請求轉(zhuǎn)發(fā)到此端口.
minSpareThreads=”25″ # Tomcat連接器的最小空閑Socket線程數(shù), 默認(rèn)值為25. 如果當(dāng)前沒有空閑線程, 且沒有超過maxThreads, 將一次性創(chuàng)建的空閑線程數(shù)量. Tomcat初始化時創(chuàng)建的線程數(shù)量也是此值.
maxSpareThreads=”75″ # 最大空閑線程數(shù), 一旦創(chuàng)建的線程超過此值, Tomcat就會關(guān)閉不再需要的Socket線程, 默認(rèn)值為50. 線程數(shù)可以大致用 “同時在線用戶數(shù)、用戶每秒操作次數(shù)、系統(tǒng)平均操作時間” 來計(jì)算.
keepAliveTimeout=”6000″ # 下次請求到來之前, Tomcat保持該連接6000ms.
maxKeepAliveRequests=”10″ # 該連接最大支持的請求數(shù), 超過該請求數(shù)的連接也將被關(guān)閉(此時就會返回一個Connection: close頭給客戶端). 1表示禁用長連接, -1表示不限制連接個數(shù), 默認(rèn)為100, 一般設(shè)置在100~200之間.
acceptorThreadCount=”1″ # 用于接收連接的線程的數(shù)量, 默認(rèn)值是1. 一般如果服務(wù)器是多核CPU時, 需要改配置為 2.
enableLookups=”false” # 是否支持反查域名(即DNS解析), 默認(rèn)為true. 為提高處理能力, 應(yīng)設(shè)置為false.
disableUploadTimeout=”true” # 上傳時是否啟用超時機(jī)制, 若為true, 則禁用上傳超時.
connectionTimeout=”20000″ # 網(wǎng)絡(luò)連接超時時間, 默認(rèn)值為20000ms, 設(shè)置為0表示永不超時 —— 存在隱患. 通常可設(shè)置為30000ms.
URIEncoding=”UTF-8″ # 指定Tomcat容器的URL編碼格式.
maxHttpHeaderSize=”8192″ # HTTP請求頭信息的最大程度, 超過此長度的部分不予處理. 一般設(shè)置為8K即可.
maxPostSize=”10485760″ # 指定POST請求的內(nèi)容大小, 單位為Byte, 默認(rèn)大小為2097152(2MB), 10485760為10M. 如果要禁用限制, 可設(shè)置為-1.
compression=”on” # 打開傳輸時壓縮功能.
compressionMinSize=”10240″ # 啟用壓縮的輸出內(nèi)容大小, 默認(rèn)為2048, 即2KB.
noCompressionUserAgents=”gozilla, traviata” # 設(shè)置不啟用壓縮的瀏覽器
compressableMimeType=”text/html,text/xml,text/javascript,text/css,text/plain” # 壓縮的資源類型
(2) 補(bǔ)充說明:
① Tomcat 的壓縮是在客戶端請求服務(wù)器對應(yīng)資源后, 從服務(wù)器端將資源文件壓縮, 再輸出到客戶端, 由客戶端的瀏覽器負(fù)責(zé)解壓縮并瀏覽. 相對于普通的瀏覽過程(如瀏覽HTML、CSS、Javascript和Text), 它可以節(jié)省40%左右的流量. 更為重要的是, 它也可以對動態(tài)生成的網(wǎng)頁(包括CGI、PHP、JSP、ASP、Servlet、SHTML等)進(jìn)行壓縮.
② 需要注意的是, 壓縮會增加Tomcat的負(fù)擔(dān), 最好采用 Nginx + Tomcat 或 Apache + Tomcat 方式, 將壓縮交由 Nginx / Apache 去完成. 在server.xml的節(jié)點(diǎn)配置(尚未驗(yàn)證使用):
•<Service name=”Catalina” /> — 處理所有直接由Tomcat服務(wù)器接收的web客戶請求.
•<Service name=”Apache” /> — 處理所有由Apahce服務(wù)器轉(zhuǎn)發(fā)過來的Web客戶請求.
•<Service name=”Nginx” /> — 處理所有由Nginx服務(wù)器轉(zhuǎn)發(fā)過來的Web客戶端請求.
2.2 使用NIO模式處理請求
(1) 默認(rèn)配置 – BlockingIO模型:
<Connector port=”8080″ protocol=”HTTP/1.1″
connectionTimeout=”20000″
redirectPort=”8443″ />
(2) 關(guān)于NIO的說明:
•每個Web客戶端請求對服務(wù)器端來說就是一個單獨(dú)的線程, 客戶端請求數(shù)量增多, 服務(wù)器端的處理線程數(shù)量也將增加, 對CPU而言, 將會在線程切換上消耗更多的時間. 而NIO則是使用單線程(單個CPU)或只使用少量的多線程(多CPU)來接受Socket, 而由線程池來處理堵塞在 Pipe 或 Queue 中的請求. 這樣的話, 只要OS可以接受TCP連接, Web服務(wù)器就可以處理該請求 — 大大提高了Web服務(wù)器的伸縮性.
•Tomcat 8 下使用 NIO2, 即 org.apache.coyote.http11.Http11Nio2Protocol 更優(yōu).
•Tomcat 6、7 下使用 NIO, 即 org.apache.coyote.http11.Http11NioProtocol 更優(yōu).
(3) NIO模型配置:
<Connector executor=”tomcatThreadPool”
port=”8080″ protocol=”org.apache.coyote.http11.Http11Nio2Protocol”
connectionTimeout=”20000″
redirectPort=”8443″
maxPostSize=”10485760″
acceptorThreadCount=”2″ />
(4) 參數(shù)說明:
executor=”…” # 連接器使用的線程池名稱.
port=”…” # 連接端口, URL中指定此端口進(jìn)行訪問.
protocol=”…” # 連接器使用的請求處理模式.
redirectPort=”8443″ # 基于SSL的端口, 在需要基于安全通道的場合, 比如當(dāng)客戶端的請求協(xié)議是HTTPS時, 將該請求轉(zhuǎn)發(fā)到此8443端口.
2.3 使用APR模式處理請求
可以簡單地將APR模式理解為,Tomcat將以JNI的形式調(diào)用Apache HTTP服務(wù)器的核心動態(tài)鏈接庫, 進(jìn)行文件讀取或網(wǎng)絡(luò)傳輸操作, 從而大大地提高Tomcat對靜態(tài)文件的處理性能.
APR是Tomcat上運(yùn)行高并發(fā)應(yīng)用的首選模式, 同時如果使用HTTPS方式傳輸, 也可以提升SSL的處理性能.
前面已經(jīng)提到, APR模式會調(diào)用操作系統(tǒng)底層的IO接口, 所以需要安裝必要的依賴.
(1) 安裝OpenSSL:
安裝命令如下:
yum -y install openssl-devel
(2) 安裝APR組件:
•第一步: 下載apr與apr-util安裝包:
下載地址: http://apr.apache.org/download.cgi. 這里下載apr-1.6.3.tar.gz和apr-util-1.6.1.tar.gz, 然后將安裝包上傳至服務(wù)器, 這里上傳至 /usr/local 目錄下.
•第二步: 安裝apr:
cd /usr/local
tar -zxf apr-1.6.3.tar.gz
cd apr-1.6.3
# 配置安裝路徑
./configure –prefix=/usr/local/apr
# 編譯安裝
make
make install
•第三步: 安裝apr-util:
cd /usr/local
tar -zxf apr-util-1.6.1.tar.gz
cd apr-util-1.6.1
# 配置安裝路徑
./configure –prefix=/usr/local/apr-util–with-apr=/usr/local/apr
# 編譯安裝
make
make install
錯誤提示:
可能出現(xiàn)gcc依賴沒有安裝的錯誤, 可通過 yum install gcc 命令安裝.
如果make過程中出錯, 解決錯誤后重新安裝前需要執(zhí)行清理: make clean, 然后再次嘗試make及make install過程.
如果拋出 xml/apr_xml.c:35:19: error: expat.h: No such file or directory, 說明缺少了expat庫, 可執(zhí)行下屬命令安裝: yum install expat-devel.
•第四步: 配置環(huán)境變量:
上面安裝完后設(shè)置下環(huán)境變量:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/apr/lib
或者, 將/usr/local/apr/lib包路徑添加到/etc/ld.so.conf文件中:
echo “/usr/local/apr/lib” >> /etc/ld.so.conf
(3) 安裝tomcat-native組件:
tomcat-native組件可以看作是Tomcat與APR交互的中間環(huán)節(jié).
•第一步: 下載并解壓native安裝包:
前往 ${TOMCAT_HOME}/bin 目錄下找到tomcat-native.tar.gz, 也可前往官網(wǎng)(http://tomcat.apache.org/download-native.cgi)下載其他版本, 推薦使用Tomcat自帶的版本, 兼容性有更大保證.
解壓tomcat-native組件并安裝, 或上傳自己下載的native組件至服務(wù)器后, 再執(zhí)行下述過程:
cd /usr/local/tomcat/bin/
tar -zxf tomcat-native.tar.gz
cd tomcat-native-1.2.14-src/native/
注意: 1.1.x版本中的目錄是tomcat-native-1.1.x-src/jni/native.
•第二步: 安裝組件:
# 配置安裝參數(shù), 其中java-home可使用默認(rèn)環(huán)境變量中的配置
./configure –with-apr=/usr/local/apr –with-ssl=yes
make
make install
(4) Tomcat整合APR:
•第一步: 修改啟動腳本catalina.sh:
在${TOMCAT_HOME}/bin/catalina.sh 文件的 cygwin=false 前(110行左右)加入下述啟動參數(shù):
JAVA_OPTS=”$JAVA_OPTS -Djava.library.path=/usr/local/apr/lib”
•第二步: 修改容器配置文件server.xml:
查看 ${TOMCAT_HOME}/conf/server.xml 文件, 確保如下監(jiān)聽器沒有被注釋掉:
<Listener className=”org.apache.catalina.core.AprLifecycleListener” SSLEngine=”on” />
•修改Connector選項(xiàng):
<Connector port=”8443″
protocol=”org.apache.coyote.http11.Http11AprProtocol”
maxThreads=”150″ SSLEnabled=”true” >
</Connector>
(5) 驗(yàn)證配置是否成功:
啟動Tomcat, 在 ${TOMCAT_HOME}/logs/catalina.out 文件中查看日志信息:
•如果出現(xiàn)下述內(nèi)容, 說明APR組件安裝不成功:
Sep 14, 2018 19:11:20 PM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path:…
•如果出現(xiàn)下述內(nèi)容, 說明APR組件安裝成功:
Sep 14, 2018 19:19:47 PM org.apache.catalina.core.AprLifecycleListener init
INFO: Loaded APR based Apache Tomcat Native library 1.1.27 using APR version 1.6.3.
Sep 14, 2018 19:19:47 PM org.apache.catalina.core.AprLifecycleListener init
INFO: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
Sep 14, 2018 19:19:47 PM org.apache.catalina.core.AprLifecycleListener initializeSSL
INFO: OpenSSL successfully initialized (OpenSSL 1.0.1e-fips 11 Feb 2013)
Sep 14, 2018 19:19:47 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler [“http-apr-8080”]
Sep 14, 2018 19:19:47 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler [“ajp-apr-8009”]
•Tomcat通過APR模式成功啟動:
Sep 14, 2018 19:19:56 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler [“http-apr-8986”]
Sep 14, 2018 19:19:56 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler [“ajp-apr-8915”]
Sep 14, 2018 19:19:56 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 9421 ms
3 配置AJP連接器
AJP(Apache JServer Protocol)是為 Tomcat 與 HTTP 服務(wù)器之間通信而定制的協(xié)議, 能提供較高的通信速度和效率.
與案例說明: AJP v13 協(xié)議是面向包的, Web服務(wù)器和Servlet容器通過TCP連接來交互, 為了節(jié)省 創(chuàng)建Socket的昂貴代價, Web服務(wù)器會嘗試維護(hù)一個永久的TCP連接到Servlet容器, 并在多個請求與響應(yīng)周期過程內(nèi)重用該TCP連接.
如果使用Apache架構(gòu), 就要用AJP連接器, 當(dāng)Apache接收到動態(tài)網(wǎng)頁請求時, 通過在配置中指定的端口號將請求發(fā)送給在此端口號上監(jiān)聽的AJP連接器組件.
如果不使用Tomcat + Apache, 而是用其他架構(gòu), 如Tomcat + Nginx, 就需要注銷掉該連接器.
<!– <Connector port=”8009″ protocol=”AJP/1.3″ redirectPort=”8443″ /> –>