程式猿必須知道的關於 Tomcat 的知識點
序
身為 Java
程式設計師,Tomcat
應該算是我們接觸的最多的 web
容器了。同時,作為企業生產工具的 “八阿哥”
們,平常只顧著埋頭寫 BUG
,哪有什麼時間整理用過的知識點。今天,我將和大家一起梳理一下關於 Tomcat
的相關內容,由淺入深,從入門到放棄。奧利給~!
一、HTTP 請求處理流程
如上圖所示:
- 使用者通過瀏覽器發起請求。
- 瀏覽器向目標伺服器發起
TCP
連線請求。 - 經過三次握手後客戶端瀏覽器與目標伺服器成功建立
TCP
連線。(基於Socket
實現) - 瀏覽器生成
HTTP
格式的資料包。 - 瀏覽器傳送
TCP
請求資料包。(這個資料包的請求頭為TCP
格式的請求頭,上一步封裝的HTTP
格式的資料包被作為TCP
請求體傳送至伺服器) - 伺服器解析
TCP
請求體中的HTTP
資料包。 - 伺服器處理請求,完成相關業務邏輯。
- 伺服器生成
HTTP
格式的響應資料包。 - 伺服器將響應資料包傳送至客戶端瀏覽器。
- 瀏覽器解析
HTTP
格式的響應資料包。(解析出的資料為靜態資料如:HTML
、CSS
、JS
、圖片等) - 瀏覽器渲染響應結果,呈現靜態資料給使用者。
二、Tomcat 總體架構說明
Tomcat
作為 Servlet
容器從軟體執行角度看,主要可以分為兩大模組,一個是 Http
請求接收、響應模組(Coyote
),另一個是請求處理模組,即從 Servlet
容器中獲取與請求對應的處理方法並執行(Catalina
)。
Coyote
聯結器包含以下兩個模組:
-
ProtocolHandler
協議處理介面。這個介面通過Endpoint
和Processor
,實現針對具體協議的處
理能⼒。Tomcat
按照協議和I/O
提供了6個實現類 :AjpNioProtocol
,AjpAprProtocol
,AjpNio2Protocol
,Http11NioProtocol
,Http11Nio2Protocol
,Http11AprProtocol
-
EndPoint
是用來實現TCP/IP
協議的,是Coyote
通訊的端點,即通訊監聽的接⼝。是具體Socket
接收和傳送處理器。EndPoint
是對傳輸層的抽象。 -
Processor
⽤來實現HTTP
協議,可將來⾃EndPoint
的Socket
,讀取位元組流解析成Tomcat
自己定義的Request
和Response
物件。Processor
是對應⽤層協議的抽象(注意:這裡的Tomcat Request
和Response
物件,還不是我們在Servlet
中所用到的ServletRequest
和ServletResponse
物件。)
-
-
Adapter
由於請求協議的不同,客戶端傳送至後臺的請求資訊也不盡相同。為了能夠轉換成統一的ServletRequest
和ServletResponse
物件方便Servlet
容器處理業務,則需要該介面的實現類,對傳送至Tomcat
的請求進行統一的適配處理。進而使呼叫Servlet
容器中的方法變的簡單。
Servlet
容器又名 Catalina
。一個 Catalina
例項只能擁有一個 Server
例項,一個 Server
例項可以包含多個 Service
例項。而每一個 Service
例項又可以包含多個 Connector
和一個 Container
。一個 Container
只能有一個 Engine
,一個 Engine
可以有多個 Host
,每個 Host
可以包含多個 Context
(網站),每個 Context
中可以有多個 Wrapper
(Servlet
)。
Catalina
例項可以被看成就是一個Tomcat
例項。該例項用以解析server.xml
配置檔案, 以此來建立伺服器Server元件並進⾏管理。Server
表示整個Catalina Servlet
容器以及其它元件,負責組裝並啟動Servlaet
引擎,Tomcat
聯結器。Service
是Server
內部的元件,⼀個Server
包含多個Service
。它將若⼲個Connector
元件繫結到⼀個Container
。(通常情況下只用一個Service
就夠了)Container
負責處理⽤戶的servlet
請求,並將處理結果返回給使用者。Engine
是整個Catalina
的Servlet
引擎,⽤來管理多個虛擬站點,⼀個Service
最多隻能有⼀個Engine
,但是⼀個Engine
可包含多個Host
。Host
代表⼀個虛擬主機,或者說⼀個站點,可以給Tomcat
配置多個虛擬主機地址。⽽⼀個虛擬主機下可包含多個Context
。Context
表示⼀個Web
應⽤程式, ⼀個Web
應⽤可包含多個Wrapper
。Wrapper
表示⼀個Servlet
。Wrapper
作為容器中的最底層,不能包含⼦容器。
Tips:
上述元件的配置其實就體現在 Tomcat
軟體中的 conf/server.xml
裡。
三、Tomcat 核心配置檔案 server.xml
問個實在的問題:當你第一次甚至說上一次看 Tomcat
的配置檔案 server.xml
時,你的第一感受是啥?反正我最真切的感受就是:“我靠,英文真多~!”。不過靜下心來再看,更多的都是說明性文字。刪除註釋後再看,就跟被拔光毛的雞一樣,也就那樣。不信你看
<?xml version="1.0" encoding="UTF-8"?>
<!-- port:關閉伺服器的監聽端⼝ shutdown:關閉伺服器的指令字串 -->
<Server port="8005" shutdown="SHUTDOWN">
<!-- 以⽇志形式輸出伺服器 、作業系統、JVM的版本資訊 -->
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<!-- 載入(伺服器啟動)和銷燬(伺服器停⽌)APR。如果找不到 APR 庫,則會輸出⽇志,但並不影響 Tomcat 啟動 -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!-- 避免JRE記憶體洩漏問題 -->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<!-- 載入(伺服器啟動)和銷燬(伺服器停⽌)全域性命名服務 -->
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<!-- 在Context停⽌時重建 Executor 池中的執行緒,以避免 ThreadLocal 相關的記憶體洩漏 -->
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<!-- 全域性命名服務,定義伺服器的全域性 JNDI 資源 -->
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<!-- 處理 HTTP/1.1 協議的請求 -->
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000"
redirectPort="8443" />
<!-- 處理 AJP/1.3 協議的請求 用不到的話可以註釋掉 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase" />
</Realm>
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
這麼一整理是不是瞬間清爽了很多。需要注意的是,通常情況下,上面配置檔案裡新增了註釋的部分,除了 Connector
標籤中的引數,其他標籤的內容一般不需要修改,保持預設即可。
四、核心配置檔案進階
4-1 <Service> 標籤
<Service name="Catalina">
...
</Service>
該標籤⽤於建立 Service
例項,預設使⽤ org.apache.catalina.core.StandardService
物件。預設情況下,Tomcat
僅指定了 Service
的名稱, 值為 “Catalina
”。
Service
⼦標籤有 : Listener
、Executor
、Connector
、Engine
。其中:
Listener
⽤於為Service
新增⽣命週期監聽器(用的比較少,故下文不做說明)Executor
⽤於配置Service
共享執行緒池Connector
⽤於配置Service
包含的連結器Engine
⽤於配置Service
中連結器對應的Servlet
容器引擎
4-2 <Executor> 標籤
該標籤用於為 Service
新增執行緒池。預設情況下,在 server.xml
檔案中,該標籤是被註釋掉的,即未開啟執行緒池的。如果想開啟,則開啟註釋,並配置相關屬性即可。
<Executor name="commonThreadPool"
namePrefix="thread-exec-"
maxThreads="200"
minSpareThreads="100"
maxIdleTime="60000"
maxQueueSize="Integer.MAX_VALUE"
prestartminSpareThreads="false"
threadPriority="5"
className="org.apache.catalina.core.StandardThreadExecutor"/>
<Executor> 標籤屬性含義:
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
接⼝。
4-3 <Connector> 標籤
該⽤於建立連結器例項預設情況下,server.xml
配置了兩個連結器,⼀個⽀持 HTTP
協議,⼀個⽀持 AJP
協議⼤多數情況下,我們並不需要新增連結器配置,只是根據需要對已有連結器進⾏優化。
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
executor="commonThreadPool"
URIEncoding="UTF-8"
minSpareThreads="100"
maxThreads="1000"
acceptCount="1000"
maxConnections="1000"
compression="on"
compressionMinSize="2048"
disableUploadTimeout="true"
/>
<Connector> 標籤屬性含義:
port
:端⼝號,Connector
⽤於建立服務端Socket
並進⾏監聽, 以等待客戶端請求連結。如果該屬性設定為0
,Tomcat
將會隨機選擇⼀個可⽤的端⼝號給當前Connector
使⽤。protocol
:當前Connector
⽀持的訪問協議。 預設為HTTP/1.1
,並採⽤⾃動切換機制選擇⼀個基於JAVA NIO
的連結器或者基於本地APR
的連結器。(若想使用APR
提高Tomcat
的併發效能,則需要安裝相關執行庫後,再進行配置修改)connectionTimeOut
:Connector
接收連結後的等待超時時間, 單位為 毫秒。 -1 表示不超時。redirectPort
:當前Connector
不⽀持SSL
請求。如果接收到了⼀個請求, 且同時符合security-constraint
約束,需要SSL
傳輸,Catalina
則會⾃動將請求重定向到指定的端⼝。executor
:指定要使用的共享執行緒池的名稱。URIEncoding
:⽤於指定編碼URI
的字元編碼,Tomcat8.x
版本預設的編碼為UTF-8
,Tomcat7.x
版本預設為ISO-8859-1
。- 當我們不使用共享執行緒池(即不新增
executor
屬性),選擇讓每一個Connector
單獨維護自己的執行緒池時可通過maxThreads
、minSpareThreads
、acceptCount
、maxConnections
進行Connector
執行緒池的配置。需要注意的是maxThreads
、acceptCount
、maxConnections
這三個屬性的值通常保持一致。 compression
:是否開啟資料請求等的gzip
格式壓縮。compressionMinSize
:最小壓縮大小,即當資料請求超過指定值後才會進行壓縮。disableUploadTimeout
:允許Servlet
容器,使用較長的連線超時值,以使Servlet
有較長的時間來完成它的執行,預設值為false
。
4-4 <Engine> 標籤
<Engine name="Catalina" defaultHost="localhost">
...
</Engine>
該標籤表示 Servlet
引擎。其屬性 name
⽤於指定 Engine
的名稱, 預設為Catalina
。defaultHost
屬性用於指定預設使⽤的虛擬主機名稱,當客戶端請求指向的主機⽆效時,將交由預設的虛擬主機處理,預設為值 localhost
。
4-5 <Host> 標籤
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
...
</Host>
該標籤用於配置⼀個虛擬主機。
name
:指定虛擬主機的名稱。appBase
:指定引用基礎目錄。unpackWARs
:是否自動解壓war
包。autoDeploy
:當資源有變更時是否自動部署。
4-6 <Context> 標籤
<Host name="www.abc.com" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Context docBase="/Users/yingdian/web_demo" path="/web_demo"></Context>
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host>
標籤中的 <Context>
標籤用於配置一個 Web
應用。
docBase
:指定Web
應⽤⽬錄或者War
包的部署路徑。可以是絕對路徑,也可以是相對於Host appBase
的相對路徑。(appBase
的子目錄)path
:Web
應⽤的URL
訪問路徑。如上所示,我們Host
名為www.abc.com
, 則該Web
應⽤訪問的根路徑為:http://www.abc.com:8080/web_demo
。
五、Tomcat 配置 HTTPS
-
使⽤
JDK
中的keytool
⼯具⽣成免費的祕鑰庫⽂件(證照)。keytool -genkey -alias SupremeSir -keyalg RSA -keystore supreme.keystore
- 配置 server.xml
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" schema="https" secure="true" SSLEnabled="true">
<SSLHostConfig>
<Certificate certificateKeystoreFile="E:\**\apache-tomcat\bin\supreme.keystore" certificateKeystorePassword="123456" type="RSA"/>
</SSLHostConfig>
</Connector>
certificateKeystoreFile
:指定證照所在位置。
certificateKeystorePassword
:指定證照祕鑰庫口令。
六、Tomcat 效能優化
Tomcat
優化沒有明確的引數值可以直接去使⽤,必須根據⾃⼰的真實⽣產環境來進⾏調整,調優是⼀個過程。調優主要從兩個⽅⾯進⾏:
JVM
虛擬機器優化(優化記憶體模型)Tomcat
⾃身配置的優化
6-1 Java 虛擬機器記憶體相關引數
引數 | 引數作用 | 優化建議 |
---|---|---|
-server | 啟動Server,以服務端模式運⾏ | 服務端模式建議開啟 |
-Xms | 最⼩堆記憶體 | 建議與-Xmx設定相同 |
-Xmx | 最⼤堆記憶體 | 建議設定為可⽤記憶體的80% |
-XX:MetaspaceSize | 元空間初始值 | |
-XX:MaxMetaspaceSize | 元空間最⼤記憶體 | 預設⽆限 |
-XX:NewRatio | 年輕代和⽼年代⼤⼩⽐值,取值為整數,預設為2 | 不需要修改 |
-XX:SurvivorRatio | Eden區與Survivor區⼤⼩的⽐值,取值為整數,預設為8 | 不需要修改 |
在 bin/catalina.sh
的指令碼中 , 追加如下配置
JAVA_OPTS="-server -Xms2048m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
6-2 垃圾收集器
-
串⾏收集器(
Serial Collector
)單執行緒執⾏所有的垃圾回收⼯作, 適⽤於單核CPU伺服器。
-
並⾏收集器(
Parallel Collector
)⼜稱為吞吐量收集器(關注吞吐量), 以並⾏的⽅式執⾏年輕代的垃圾回收, 該⽅式可以顯著降
低垃圾回收的開銷(指多條垃圾收集執行緒並⾏⼯作,但此時⽤戶執行緒仍然處於等待狀態)。適⽤於多
處理器或多執行緒硬體上運⾏的資料量較⼤的應⽤。 -
併發收集器(
Concurrent Collector
)以併發的⽅式執⾏⼤部分垃圾回收⼯作,以縮短垃圾回收的暫停時間。適⽤於那些響應時間優先於
吞吐量的應⽤, 因為該收集器雖然最⼩化了暫停時間(指⽤戶執行緒與垃圾收集執行緒同時執⾏,但不⼀
定是並⾏的,可能會交替進⾏), 但是會降低應⽤程式的效能。 -
CMS 收集器(
Concurrent Mark Sweep Collector
)併發標記清除收集器, 適⽤於那些更願意縮短垃圾回收暫停時間並且負擔的起與垃圾回收共享處
理器資源的應⽤ -
G1 收集器(
Garbage-First Garbage Collector
)適⽤於⼤容量記憶體的多核伺服器, 可以在滿⾜垃圾回收暫停時間⽬標的同時, 以最⼤可能性實現
⾼吞吐量(JDK1.7
之後)垃圾回收器引數
引數 描述 -XX:+UseSerialGC 啟⽤串⾏收集器 -XX:+UseParallelGC 啟⽤並⾏垃圾收集器,配置了該選項,那麼 -XX:+UseParallelOldGC預設啟⽤ -XX:+UseParNewGC 年輕代採⽤並⾏收集器,如果設定了 -XX:+UseConcMarkSweepGC選項,⾃動啟⽤ -XX:ParallelGCThreads 年輕代及⽼年代垃圾回收使⽤的執行緒數。預設值依賴於JVM使⽤的CPU個數 -XX:+UseConcMarkSweepGC(CMS) 對於⽼年代,啟⽤CMS垃圾收集器。 當並⾏收集器⽆法滿⾜應⽤的延遲需求是,推薦使⽤CMS或G1收集器。啟⽤該選項後,-XX:+UseParNewGC⾃動啟⽤。 -XX:+UseG1GC 啟⽤G1收集器。 G1是伺服器型別的收集器, ⽤於多核、⼤記憶體的機器。它在保持⾼吞吐量的情況下,⾼概率滿⾜GC暫停時間的⽬標。 在
bin/catalina.sh
的指令碼中 , 追加如下配置:JAVA_OPTS="-XX:+UseConcMarkSweepGC"
如果存在虛擬機器記憶體相關引數配置,則直接在
JAVA_OPTS
中追加即可。
6-3 Tomcat 配置調優
-
啟用
Tomcat
執行緒池 -
調整
Tomcat
的聯結器調整
Tomcat/conf/server.xml
中關於連結器的配置可以提升應⽤伺服器的效能。引數 說明 maxConnections 最⼤連線數,當到達該值後,伺服器接收但不會處理更多的請求, 額外的請求將會阻塞直到連線數低於maxConnections 。可通過ulimit -a 檢視伺服器限制。對於CPU要求更⾼(計算密集型)時,建議不要配置過⼤ ; 對於CPU要求不是特別⾼時,建議配置在2000左右(受伺服器效能影響)。 當然這個需要伺服器硬體的⽀持 maxThreads 最⼤執行緒數,需要根據伺服器的硬體情況,進⾏⼀個合理的設定 acceptCount 最⼤排隊等待數,當伺服器接收的請求數量到達maxConnections ,此時Tomcat會將後⾯的請求,存放在任務佇列中進⾏排序, acceptCount指的就是任務佇列中排隊等待的請求數 。 ⼀臺Tomcat的最⼤的請求處理數量,是maxConnections+acceptCount -
禁⽤
AJP
聯結器
-
調整
IO
模式Tomcat8
之前的版本預設使⽤BIO
(阻塞式IO
),對於每⼀個請求都要建立⼀個執行緒來處理,不適合⾼併發;Tomcat8
以後的版本預設使⽤NIO
模式(⾮阻塞式IO
)。
當Tomcat
併發效能有較⾼要求或者出現瓶頸時,我們可以嘗試使⽤APR
模式,APR
(Apache Portable Runtime
)是從作業系統級別解決非同步IO
問題,使⽤時需要在作業系統上安裝APR
和Native
(因為APR
原理是使⽤使⽤JNI
技術調⽤作業系統底層的IO
接⼝)。 -
動靜分離
可以使⽤
Nginx + Tomcat
相結合的部署⽅案,Nginx
負責靜態資源訪問,Tomcat
負責Jsp
等動態資
源訪問處理(因為Tomcat
不擅⻓處理靜態資源)。
原始碼
------------------------------------- 保持熱愛,翻閱山海。 -------------------------------------
相關文章
- 關於Flutter 您必須知道的知識點!!!Flutter
- 關於索引必須知道的知識索引
- 關於JVM,你必須知道的這些知識點JVM
- 關於Mysql事務,你必須知道的幾個知識點!MySql
- 關於汽車一些您必須知道的知識
- 關於 Laravel 資料庫查詢鎖必須要知道的知識點Laravel資料庫
- 關於資料庫索引,必須掌握的知識點資料庫索引
- Python入門必須知道的11個知識點Python
- 初學Python必須知道的11個知識點!Python
- 前端必須掌握的知識點前端
- 大學期間必須知道的JVM知識JVM
- 你必須知道的Java基礎知識Java
- 學習 Laravel 必須理解的知識點Laravel
- 有關WebSocket必須瞭解的知識Web
- 資料分析師必須知道的知識:資料倉儲的特點
- Java培訓零基礎學員必須要知道的知識點Java
- 關於Http協議,你必須要知道的HTTP協議
- NDK之旅必須要知道的一些基本知識
- 程式猿必備的Linux基礎知識Linux
- 必須懂的mysql知識MySql
- 千萬淘寶店運營必備知識,你必須知道!
- 關於NoSQL,你必須知道的九件事SQL
- JavaScript大師必須掌握的12個知識點JavaScript
- 高階 Java 必須突破的 10 個知識點!Java
- 高階Java必須突破的10個知識點!Java
- PHP初學者必須掌握的10個知識點PHP
- 軟體工程師必須知道20個知識點你瞭解多少?軟體工程工程師
- 對於MySQL你必須要了解的鎖知識MySql
- 關於CPU Cache:程式猿需要知道的那些
- 程式猿必看的熬夜須知和技巧
- 每個Android開發者必須知道的記憶體管理知識Android記憶體
- 關於 PHP 7 你必須知道的五件事PHP
- 一個程式猿必須會玩的遊戲遊戲
- Android 之 Notification 必須掌握知識點Android
- JVM-Java工程師必須掌握的知識點JVMJava工程師
- 5G大規模商用來臨之前,你必須知道的幾個知識點
- iOS程式設計師必須知道的Android要點iOS程式設計師Android
- 做iOS自動化測試必須知道的一些知識iOS