1、描述Tomcat的架構;
核心架構圖:
架構簡介:
- Server是管理Service接口的,是Tomcat的一個頂級容器。管理著多個Service;
- Service 是服務,管理著一個Container和多個Connector,Service的存在依賴于Server;
- Container : 一個或者多個Container 可以對應一個Connector,這樣就組成了一個Service,Service生命周期的由Server進行管理;
- Container和Connector之間的交互媒介是Service,一個Service可以對應多個Connector,但是只能有一個Container容器。
核心類:
Tomcat容器結構圖:
Tomcat常用組件介紹:
- Server:tomcat實例,即運行的一個jvm進程;監聽于8005端口接收“SHUTDOWN”。各server監聽的端口不能相同;因此,一個物理主機上啟動多個server實例應該使用不同的端口;
- service:用于實現將一個或多個connector關聯至一個engine;
- connector:進入tomcat的請求可分為兩類:
- tomcat作為獨立的應用程序服務器:standalone,此時,請求將來自于瀏覽器;
- tomcat作為應用程序服務器:請求將來自于前面的反代主機;
- Engine:Servlet的一個實例,即servlet引擎,其內部可以有一個或多個Host組件來定義站點;通常需要通過defaultHost的屬性定義默認虛擬主機;
- Host組件:位于Engine容器中用于接收請求并進行相應處理的主機或虛擬主機;
- Context組件:Context在某些意義上類似于apache中的路徑別名,一個Context定義用于標識tomcat實例中的一個Web應用程序;
- Realm組件:一個Realm表示一個安全上下文,它是一個授權訪問某個給定Context的用戶列表和某用戶所允許切換的角色相關定義的列表。因此,Realm就像是一個用戶和組相關的數據庫。定義Realm時惟一必須要提供的屬性是classname,它是Realm的多個不同實現,用于表示此Realm認證的用戶及角色等認證信息的存放位置。
- Valve類似于過濾器,它可以工作于Engine和Host/Context之間、Host和Context之間以及Context和Web應用程序的某資源之間。一個容器內可以建立多個Valve,而且Valve定義的次序也決定了它們生效的次序。
Tomcat的目錄結構:
- 腳本及啟動時用到的類;
- lib:類庫;
- conf:配置文件;
- logs:日志文件;
- webapps:webapp默認的部署目錄;
- work:工作目錄;
- temp:臨時文件目錄
2、詳細解釋Tomcat的配置文件及配置文件中的參數所代表的含義;
Tomcat的配置文件:
- server.xml:主配置文件
- context.xml:每個webapp都可以有專用的配置文件,這些配置文件通常位于webapp應用程序自己的目錄下的WEB-INF目錄中;此context.xml為每個webapp提供默認配置;
- web.xml:每個webapp只有在“部署”后才能被訪問,此文件則用于為各webapps定義默認的部署方式;
- tomcat-users.xml:用戶認證的帳號和密碼文件;
- catalina.policy:當使用-security選項來啟動tomcat實例時,會讀取此配置文件來實現基于安全策略的運行方式;
- catalina.properties:java屬性的定義文件,用于設定類加載器路徑,以及一些與JVM調優相關的參數等;
- logging.propeties:日志系統相關的配置;
元素名 | 屬性 | 解釋 |
Server | className | 這個類必須是org.apache.catalina.Server的實現類,如果沒有指定類名,則使用標準實現。 |
address | 這是等待關閉命令的TCP/IP地址,如果沒有指定,默認使用localhost。 | |
port | 這個端口是用于接收關閉服務的端口,可以設置為-1來禁用。 | |
shutdown | 這個命令字符串必須通過TCP/IP端口接收,才能關閉Tomcat。 | |
Service | className | 這個類必須是org.apache.catalina.Service的實現類。 |
name | Service的展示名稱,如果使用標準的Catalina組件,這個名稱會包含在日志信息中。同一個Server下的每個Service的名稱必須唯一。 | |
Connector | allowTrace | 是否允許TRACE HTTP方法,默認false。 |
asyncTimeout | 異步請求超時時間,單位毫秒,默認10000ms(10秒)。 | |
enableLookups | 如果想使用request.getRemoteHost()方法通過DNS查找遠程請求客戶端的真實的主機名,則設置為true。設置為false會跳過DNS查找,直接返回IP地址。DNS查找默認禁用。 | |
maxHeaderCount | 一個請求允許最大的請求頭數量。如果超出限制請求會被拒絕。如果為負值,無限制。默認值100。 | |
maxParameterCount | GET和POST請求的參數(和值)的最大數量,超出的參數會被忽略。如果是0或者小于0,表示無限制。默認為10000。 | |
maxPostSize | POST請求的最大字節數。如果為負,無限制。默認2097152字節(即2Mb)。 | |
maxSavePostSize | POST請求的最大保存/緩沖字節數。-1表示無限制,0表示禁用保存/緩沖,默認為4096字節(4Kb)。 | |
port | TCP端口,用于創建Server socket并等待進入連接。操作系統允許1個服務器監聽1個IP的1個指定端口。如果值為0,Tomcat會為這個Connector選擇一個隨機的空閑端口。 | |
protocol |
通信協議。默認為HTTP/1.1,這個協議使用自動切換機制來選擇阻塞式基于Java的Connector或者基于APR/native的Connector。如果要使用明確的協議,而不是自動切換機制選擇的協議,可以選擇下面的值:
|
|
proxyName | 如果當前Connector使用代理配置,使用這個屬性指定Server名稱。這個Server名稱,可以調用request.getServerName()方法返回。 | |
proxyPort | 指定代理的Server端口。 | |
redirectPort | 如果當前Connector不支持SSL請求,但是收到的請求匹配web.xml中配置的security-constraint選項,要求使用SSL端口,那么Catalina會自動把請求轉發到這個指定端口。 | |
scheme | 給當前協議設置一個名字,這樣可以通過request.getScheme()方法獲得協議名詞,比如給SSL協議取名HTTPS。默認值為http。URIEncoding:字符編碼。用于URI字節解碼,和URL %xx部分數據的解碼。默認為ISO-8859-1。 | |
useIPVHosts | 將該屬性設置為true會導致Tomcat使用收到請求的IP地址,來決定將請求發送到哪個主機。默認false。 | |
acceptCount | 當所有的可用線程都在使用中,傳入連接請求隊列的最大長度。當隊列滿時,任何請求都會被拒絕。默認100。 | |
address | 如果服務器有多個IP,這個屬性指定使用哪個IP地址用于監聽端口。默認使用與服務器關聯的全部IP地址。 | |
compressableMimeType | HTTP壓縮的元數據類型,參數可以使用逗號間隔。默認為text/html,text/xml,text/plain,text/css,text/javascript,application/javascript。 | |
compression |
為了節省服務器帶寬,Connector可以使用HTTP/1.1 GZIP壓縮。
|
|
compressionMinSize | 當compression設置為on,指定壓縮前的最小數據量。默認為2048。 | |
connectionTimeout | 連接超時時間。-1表示無限制。默認值60000ms(60秒)。但server.xml默認配置為20000。 | |
disableUploadTimeout | 是否禁用上傳超時時間,開啟后,上傳數據的連接使用單獨的超時時間。 | |
connectionUploadTimeout | 上傳數據時,連接超時時間。 | |
executor | 指向Executor元素的引用。如果設置了這個元屬性,并且對應的Executor存在,Connector將使用這個Executor,而其他所有線程相關屬性將被忽略。如果未指定此屬性,Connector會使用一個私有的、內部Executor來提供線程池。 | |
executorTerminationTimeoutMillis | 在關閉Connector之前,那個私有的、內部Executor等待請求處理線程的終結的超時時間。BIO Connector默認值為0ms。NIO和APR/native Connector默認值為5000ms。 | |
keepAliveTimeout | 長連接超時時間。Connector在關閉連接之前,會等待另一個HTTP請求的時間。默認值是connectionTimeout的屬性值。-1無超時時間。 | |
maxKeepAliveRequests | HTTP請求最大長連接數量。如果值為1,禁用長連接。設為-1,無限制。默認值為100。 | |
maxConnections | 在任何給定的時間服務器接收并處理的最大連接數。當這個數字已經達到了,服務器將不會接受任何連接,直到連接的數量降到低于此值。基于acceptCount,操作系統可能仍然接收連接。 | |
maxHttpHeaderSize | 請求頭和響應頭的最大字節數。默認8192(8Kb) | |
maxThreads | 最多同時處理的請求的最大線程數量,這決定了同時處理請求的最大數量。默認200。 | |
minSpareThreads | 最小空閑線程數量。默認10。 | |
socketBuffer | Socket輸出緩沖區大小。單位字節。-1表示禁用緩沖區。默認值9000字節。 | |
SSLEnabled | 是否開啟SSL加密傳輸。需要配置secure和scheme屬性。 | |
Context | cookies | 是否使用cookie,可以通過cookie鑒別session。默認true。設置為false,則無法使用cookie完成session鑒證,然后必須依賴于URL重寫。 |
docBase | 應用程序文件的根目錄。如果應用程序不在Host元素的appBase路徑下,需要設置此屬性。 | |
path | 應用程序的訪問路徑(context path)。 | |
reloadable | 自動重新加載class和jar文件。設置為true,Catalina會監視/WEB-INF/classes/ 和/WEB-INF/lib目錄下的變動,如果檢測到變動就會自動重新加載應用程序。此功能非常有用但是不建議在生產環境使用。 | |
Engine | defaultHost | 默認的主機名,它必須指向一個Host元素的name屬性。 |
name | Engine的邏輯名稱,用于日志和錯誤信息。如果在一個Server中使用多個Service元素,每個Engine必須使用唯一的名稱。 | |
jvmRoute | 在負載均衡場景中使用,用以實現會話黏性,此標識在參與集群的所有節點上必須唯一; | |
Host | appBase | 此Host的webapps目錄,即存放非歸檔的web應用程序的目錄或歸檔后的WAR文件的目錄路徑;可以使用基于$CATALINA_HOME的相對路徑; |
name | 一般是虛擬主機注冊到DNS的網絡名稱。必須有一個Host的name作為Engine的defaultHost。 | |
autoDelploy | 在Tomcat處于運行狀態時放置于appBase目錄中的應用程序文件是否自動進行deploy;默認為true; | |
unpackWars | 在啟動此webapps時是否對WAR格式的文檔文件先進行展開;默認為true; | |
Realm | JAASRealm | 基于Java Authintication and Authorization Service實現用戶認證; |
JDBCRealm | 通過JDBC訪問某關系型數據庫表實現用戶認證; | |
JNDIRealm | 基于JNDI使用目錄服務實現認證信息的獲取; | |
MemoryRealm | 查找tomcat-user.xml文件實現用戶信息的獲取; | |
UserDatabaseRealm | 基于UserDatabase文件(通常是tomcat-user.xml)實現用戶認證,它實現是一個完全可更新和持久有效的MemoryRealm,因此能夠跟標準的MemoryRealm兼容;它通過JNDI實現; | |
Valve | AccessLogValve | 訪問日志Value; |
ExtendedAccessValve | 擴展功能的訪問日志Valve; | |
JDBCAccessLogValve | 通過JDBC將訪問日志信息發送到數據庫中; | |
RequestDumperValve | 請求轉儲Valve; | |
RemoteAddrValve | 基于遠程地址的訪問控制; | |
RemoteHostValve | 基于遠程主機名稱的訪問控制; | |
SemaphoreValve | 用于控制Tomcat主機上任何容器上的并發訪問數量; | |
JvmRouteBinderValve | 在配置多個Tomcat為以Apache通過mod_proxy或mod_jk作為前端的集群架構中,當期望停止某節點時,可以通過此Valve將用記請求定向至備用節點;使用此Valve,必須使用JvmRouteSessionIDBinderListener; | |
ReplicationValve | 專用于Tomcat集群架構中,可以在某個請求的session信息發生更改時觸發session數據在各節點間進行復制; | |
SingleSignOn | 將兩個或多個需要對用戶進行認證webapp在認證用戶時連接在一起,即一次認證即可訪問所有連接在一起的webapp; | |
ClusterSingleSingOn | 對SingleSignOn的擴展,專用于Tomcat集群當中,需要結合ClusterSingleSignOnListener進行工作; |
3、配置apache通過mod_proxy模塊與Tomcat連接的詳細過程;
環境:
apache代理服務器:192.168.0.20
tomcat服務器:192.168.0.22
1.后端tomcat配置
######安裝jdk###### ~]# rpm -ivh jdk-7u79-linux-x64.rpm ~]# vim /etc/profile.d/java.sh export JAVA_HOME=/usr/java/latest export PATH=$JAVA_HOME/bin:$PATH ~]# source /etc/profile ~]# java -version java version "1.7.0_79" Java(TM) SE Runtime Environment (build 1.7.0_79-b15) Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode) ######安裝tomcat###### ~]# yum install tomcat tomcat-lib tomcat-admin-webapps tomcat-webapps -y ######修改tomcat配置文件,在默認Host類中添加Context###### ~]# vim /etc/tomcat/server.xml ... <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context path="/test" docBase="testapp"/> ... #######創建webapp特有的目錄結構######### ~]# cd /var/share/tomcat/webapps/ ~]# mkdir /testapp/{classes,lib,WEB-INF,META-INF} -p #######創建jsp探測頁面######## ~]# vim testapp/index.jsp <%@ page language="java" %> <%@ page import="java.util.*" %> <html> <head> <title>JSP Test Page</title> </head> <body> <% out.println("Tomcat_A_22"); %> </body> </html> ~]# systemctl start tomcat.service ######在客戶端訪問tomcat服務器正常###### ~]# curl 192.168.0.22:8080/test/ <html> <head> <title>JSP Test Page</title> </head> <body> Tomcat_A_22 </body> </html>
2.前端apache代理配置
~]# yum install httpd -y ######請先確保httpd包含了http協議的代理模塊###### ~]# httpd -M ... proxy_http_module (shared) ######創建一個代理虛擬主機###### ~]# vim /etc/httpd/conf/httpd.conf #DocumentRoot "/var/www/html" #注釋掉該行 ~]# vim /etc/httpd/conf.d/http_tomcat.conf <VirtualHost *:80> ServerName tc1.magedu.com ProxyRequests Off ProxyVia On ProxyPreserveHost On <Proxy *> Require all granted </Proxy> ProxyPass / http://192.168.0.22:8080/ ProxyPassReverse / http://192.168.0.22:8080/ <Location /> Require all granted </Location> </VirtualHost> ~]# systemctl start httpd.service ######在客戶端訪問apache代理###### ~]# curl 192.168.0.20/test/ <html> <head> <title>JSP Test Page</title> </head> <body> Tomcat_A_22 </body> </html>
4、配置基于mod_jk的負載均衡;
環境:
apache代理服務器(mod_jk):192.168.0.20
tomcat服務器A:192.168.0.22
tomcat服務器B:192.168.0.23
1.后端tomcat服務器配置
######修改Host類,添加jvmRoute屬性###### #Tomcat_A: ~]# vim /etc/tomcat/server.xml ... <Host name="localhost" appBase="webapps jvmRoute="TomcatA"" #jvmRoute值要與workers.properties中節點名稱一致 unpackWARs="true" autoDeploy="true"> <Context path="/test" docBase="testapp"/> ... #Tomcat_B: ~]# vim /etc/tomcat/server.xml ... <Host name="localhost" appBase="webapps jvmRoute="TomcatB"" unpackWARs="true" autoDeploy="true"> <Context path="/test" docBase="testapp"/> ... ~]# systemctl restart tomcat.service
2.前端apache代理服務器配置
########安裝mod_jk模塊########### ~]# yum groupinstall "Development Tools" "Server Platform Development" -y~]# yum install httpd-devel -y
~]# tar xf tomcat-connectors-1.2.40-src.tar.gz ~]# cd tomcat-connectors-1.2.40-src ~]# ./configure --with-apxs=/usr/bin/apxs ~]# make && make install ########創建mod_jk模塊配置文件########## ~]# vim /etc/httpd/conf.d/mod_jk.conf LoadModule jk_module modules/mod_jk.so JkWorkersFile /etc/httpd/conf.d/workers.properties JkLogFile logs/mod_jk.log JkLogLevel debug JkMount /* tcsrvs JkMount /jk_status StatA #########修改worker配置文件########## ~]# vim /etc/httpd/conf.d/workers.properties worker.list=tcsrvs,StatA #將tcsrvs組加入worker.list worker.TomcatA.host=192.168.0.22 worker.TomcatA.port=8009 worker.TomcatA.type=ajp13 worker.TomcatA.lbfactor=1 #設置后端節點的權重 worker.TomcatB.host=192.168.0.23 worker.TomcatB.port=8009 worker.TomcatB.type=ajp13 worker.TomcatB.lbfactor=1 worker.tcsrvs.type=lb #定義tcsrvs類型為lb worker.tcsrvs.balance_workers=TomcatA,TomcatB #指定tcsrvs組成員 worker.StatA.type=status ~]# systemctl reload httpd.service ######在客戶端上進行測試###### ~]# curl 192.168.0.20/test/ <html> <head> <title>JSP Test Page</title> </head> <body> Tomcat_A_22 </body> </html> ~]# curl 192.168.0.20/test/ <html> <head> <title>JSP Test Page</title> </head> <body> Tomcat_B_23 </body> </html> ######成功實現負載均衡!######
5、配置tomcat集群,能夠實現用戶的session會話保持。
環境:
apache代理服務器(mod_jk):192.168.0.20
tomcat服務器A:192.168.0.22
tomcat服務器B:192.168.0.23
1.前端apache代理仍使用上題的環境,這里不再贅述
2.后端兩臺tomcat服務器配置
#######修改tomcat配置文件,添加下面內容############# ~]# vim /etc/tomcat/server.xml ... <Engine name="Catalina" defaultHost="localhost" jvmRoute="TomcatA"> #Engine中要添加jvmRoute名稱 <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6"> <Manager className="org.apache.catalina.ha.session.BackupManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true" mapSendOptions="6"/> <!-- <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/> --> <Channel className="org.apache.catalina.tribes.group.GroupChannel"> <Membership className="org.apache.catalina.tribes.membership.McastService" address="228.101.0.4" port="45564" frequency="500" dropTime="3000"/> <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="192.168.0.22" #不同節點改為實際的地址 port="5000" selectorTimeout="100" maxThreads="6"/> <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> </Sender> <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/> </Channel> <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/> <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" tempDir="/tmp/war-temp/" deployDir="/tmp/war-deploy/" watchDir="/tmp/war-listen/" watchEnabled="false"/> <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> </Cluster> ... ########配置webapps,編輯WEB-INF/web.xml,添加<distributable/>########### ~]# cd /var/lib/tomcat/webapps/testapp/ ~]# cp /etc/tomcat/web.xml WEB-INF/ ~]# vim WEB-INF/web.xml ... <distributable/> ... systemctl start tomcat.service ######創建session id探測頁面###### ~]# vim testapp/index.jsp <%@ page language="java" %> <html> <head><title>TomcatA</title></head> <body> <h1><font color="red">TomcatA.magedu.com</font></h1> <table align="centre" border="1"> <tr> <td>Session ID</td> <% session.setAttribute("magedu.com","magedu.com"); %> <td><%=session.getId() %></td> </tr> <tr> <td>Created on</td> <td><%=session.getCreationTime() %></td> </tr> </table> </body> </html>
使用瀏覽器訪問代理服務器,可以看到雖然會話被負載均衡到了后端兩個節點上,但是session id并沒有改變!
注意:請確保各節點時間保持一致,否則可能導致session id發生變化!
原創文章,作者:N26-西安-方老喵,如若轉載,請注明出處:http://www.www58058.com/78412
博客總結非常贊,尤其是對tomcat內部的架構和容器結構,對于配置來說其實倒不是很難,主要是理解里面的流程才是王道。