1. 程式人生 > >Tomcat多例項部署及其原理(修訂版)

Tomcat多例項部署及其原理(修訂版)

導讀:
昨天在跟群友做技術交流的時候,瞭解到,有很多大公司都是採用了高可用的,分散式的,例項沉餘1+臺。但是在小公司的同學也很多,他們反映並不是所有公司都有那樣的資源來供你排程。往往公司只會給你一臺機器,因為有些應用掛了公司也不會有損失的,我們往往一臺機器就可以搞定。
但是,我們也要為我們做出來的應用負責,畢竟東西做出來是為了給人用的,如果做出來的東西經常掛了,談何使用,在前期,如果公司資源緊張的情況下,可以不可以做高可用,多機器的沉餘部署。但是至少是在但機上有2個程序在跑。so,在這裡我們就說說這個,如何做單機多例項的部署。
在這裡談談,在只有單機的資源下,如何把單機的資源壓榨出來,用好單機。

自家的主頁: http://jbeacon.top/2016/11/19/yunwei/1/

1、Tomcat部署的場景分析

通常,我們對tomcat單機部署需求可以分為幾種:

  • 單例項單應用 (一個tomcat 一個web應用)
  • 單例項多應用 (一個tomcat多個應用)
  • 多例項單應用 (多個tomcat都部署一個應用)
  • 多例項多應用 (多個tomcat部署多個不同的應用)

第一種場景:這是我們開發中經常用到的,如果不要求週期性地維護tomcat版本,一般的做法是把打好的war包丟到webapps目錄下,然後執行startup.sh指令碼,並且可以在瀏覽器裡訪問就行了。
第二種場景

:是把多個應用程式的war包放在同一個tomcat的webapps目錄,這樣一來,關閉和啟動tomca,或tomcat掛掉會影響所有專案。
第三種場景: 各個tomcat都運行同一個應用程式,對應地需要修改不同的監聽埠,這種方式通常會和apache httpd或者nginx整合使用,做一些負載均衡的處理。
第四種場景: 相當於第一種場景的複數形式,除了修改不同的監聽埠,沒有本質區別。

一般來說,多例項部署tomcat,可以充分利用系統資源,不過這種方式,也有幾個方面需要考慮:
多例項tomcat的更新維護,例如對tomcat進行升級等操作,我們需要考慮如何能“優雅”地對所有例項進行升級
儘量不要影響應用程式,在更新tomcat時,一不小心就把conf目錄等全部覆蓋,所以儘量要把配置檔案和安裝目錄隔離
對於單應用來說,如果將war包分別置於各個tomcat的webapps目錄,那麼在釋出新版本的war時,可能會出現某個例項更新失敗,導致使用者在訪問時可能會訪問到不同版本的web app,因此,比較好的方式就是所有tomcat例項都統一指向同一個應用程式

,這樣做,就可以多個tomcat用一份應用原始碼,簡單部署,單機高可用也能實現(要配合nginx).
本文重點闡述多例項應用的部署方案,但是為了解決上述幾個問題,我們需要先來了解一下tomcat的一些基本情況。

2、我們的目標

tomcat架構

3、tomcat架構

整體架構圖

tomcat架構

這裡有一臺伺服器,3臺tomcat服務,以及一臺tomcat的解構圖。

分離目錄

目錄 作用
bin 主要存放指令碼檔案,例如比較常用的windows和linux系統中啟動和關閉指令碼
conf 主要存放配置檔案,其中最重要的兩個配置檔案是server.xml和web.xml
lib 主要存放tomcat執行所依賴的包
logs 主要存放執行時產生的日誌檔案,例如catalina.{date}.log等
temp 存放tomcat執行時產生的臨時檔案,例如開啟了hibernate快取的應用程式,會在該目錄下生成一些檔案
webapps 部署web應用程式的預設目錄
work 主要存放由JSP檔案生成的servlet(java檔案以及最終編譯生成的class檔案)

再介紹兩個tomcat中比較重要的概念(通常也是兩個系統變數)——CATALINA_HOMECATALINA_BASE

CATALINA_HOME:即指向Tomcat安裝路徑的系統變數
CATALINA_BASE:即指向活躍配置路徑的系統變數通過設定這兩個變數,就可以將tomcat的安裝目錄和工作目錄分離,從而實現tomcat多例項的部署。
Tomcat官方文件指出,CATALINA_HOME路徑的路徑下只需要包含bin和lib目錄,這也就是支援tomcat軟體執行的目錄,而CATALINA_BASE設定的路徑可以包括上述所有目錄,不過其中bin和lib目錄並不是必需的,預設時會使用CATALINA_HOME中的bin和conf。如此,我們就可以使用一個tomcat安裝目錄部署多個tomcat例項,這樣的好處在於方便升級,就可以在不影響tomcat例項的前提下,替換掉CATALINA_HOME指定的tomcat安裝目錄。

tomcat架構

tomcat serve.xml 配置結構
Container容器子容器間關係圖

tomcat架構

互動圖

tomcat架構

對比下Tomcat serve.xml 的配置

12345678910111213141516171819202122232425262728293031323334
<?xml version="1.0" encoding="UTF-8"?><Serverport="8005"shutdown="SHUTDOWN"><ListenerclassName="org.apache.catalina.startup.VersionLoggerListener"/><ListenerclassName="org.apache.catalina.core.AprLifecycleListener"SSLEngine="on"/><ListenerclassName="org.apache.catalina.core.JreMemoryLeakPreventionListener"/><ListenerclassName="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/><ListenerclassName="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/><GlobalNamingResources><Resourcename="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><Servicename="Catalina"><Connectorport="8080"protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443"/><Connectorport="8009"protocol="AJP/1.3"redirectPort="8443"/><Enginename="Catalina"defaultHost="localhost"><RealmclassName="org.apache.catalina.realm.LockOutRealm"><RealmclassName="org.apache.catalina.realm.UserDatabaseRealm"resourceName="UserDatabase"/></Realm><Hostname="localhost"appBase="webapps"unpackWARs="true"autoDeploy="true"><ValveclassName="org.apache.catalina.valves.AccessLogValve"directory="logs"prefix="localhost_access_log"suffix=".txt"pattern="%h %l %u %t &quot;%r&quot; %s %b"/></Host></Engine></Service></Server>

4、實戰

埠配置

修改server.xml

在server.xml中配置了四個監聽埠,分別是:
Server Port:該埠用於監聽關閉tomcat的shutdown命令,預設為8005.
Connector Port:該埠用於監聽HTTP的請求,預設為8080.
AJP Port:該埠用於監聽AJP( Apache JServ Protocol )協議上的請求,通常用於整合Apache Server等其他HTTP伺服器,預設為8009
Redirect Port:重定向埠,出現在Connector配置中,如果該Connector僅支援非SSL的普通http請求,那麼該埠會把https的請求轉發到這個Redirect Port指定的埠,預設為8443

虛擬主機配置
再來說Host配置,Host就是所謂的虛擬主機,對應包含了一個或者多個web應用程式,預設的Host配置如下

1
<Hostname="localhost"appBase="webapps"unpackWARs="true"autoDeploy="true">

其中:
name: 虛擬主機的名稱,一臺主機表示了完全限定的域名或IP地址,預設為localhost,同時也是唯一的host,進入tomcat的所有http請求都會對映到該主機上
appBase:web應用程式目錄的路徑,可以是CATALINA_HOME的相對路徑,也可以寫成絕對路徑,預設情況下為$CATALINA_HOME/webappsunpackWARs: 表示是否自動解壓war包
autoDeploy:所謂的熱部署,即在tomcat正在執行的情況下,如果有新的war加入,則會立即執行部署操作
另外再介紹一個Host中的屬性—deployOnStartup:表示tomcat啟動時是否自動部署appBase目錄下所有的Web應用程式,預設為true。這個屬性和autoDeploy會產生兩次部署的“副作用”:一次是tomcat啟動時就開始部署,第二次就是autoDeploy引起的熱部署。因此最好將autoDeploy置為false
在部署多例項單應用的時候,預設的$CATALINA/webapps會因為tomcat安裝目錄升級產生不必要的麻煩,我們考慮將appBase的目錄統一到另外的路徑下。

Context的配置
最後再說明一下Context的配置,它出現在Host配置內,一個Context的配置就代表了一個web應用程式,如果配置多應用程式,就需要在Host下配置多個Context,一個簡單的Context配置如下

1
<Contextpath="/some"docBase="someapp.war">

path:表示訪問入口,例如,path=”/abc”,則訪問localhost:8080/abc時,就可以訪問該Context對應的應用程式。如果path=””,則直接用localhost:8080就可以訪問
docBase:表示應用程式的解包目錄或者war檔案路徑,是Host的appBase配置目錄的相對路徑,也可以是直接寫成絕對路徑,但是不要將appBase的值,作為docBase配置路徑的字首,例如appBase=”somedir”,docBase=”somedir-someapp.war”,這樣的配置會導致部署錯誤
通過配置Host的appBase和Context的docBase兩個屬性,可以將應用程式的檔案和tomcat相關的目錄進行分離,這樣webapps目錄也就沒有作用了。

跟我來實施該方案

  • 現在假設我們有一臺已經配置好Java環境的伺服器:(我用的是阿里雲)
  • 我已經有一個已經完成的shop.war 應用程式

步驟1:
下載並解壓tomcat

tomcat架構

步驟2:
對Tomcat目錄作以下調整:
在tomcat安裝目錄下建立a.ttlsa.com、b.ttlsa.com,並且將conf、logs、webapp、temp、work目錄拷貝到這兩個目錄,然後tomcat安裝目錄只需要留下bin、a.ttlsa.com、b.ttlsa.com、lib這4個目錄即可。配置後的目錄結構如下:

tomcat架構

如果要度tomcat 進行升級,我們只是需要對tomcat的lib 和 bin 目錄進行升級即可。

步驟3:
配置站點server.xml
配置a.ttlsa.com 

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
<?xml version="1.0" encoding="UTF-8"?><!-- 8005 改為8005 --><Serverport="8005"shutdown="SHUTDOWN"><ListenerclassName="org.apache.catalina.startup.VersionLoggerListener"/><ListenerclassName="org.apache.catalina.core.AprLifecycleListener"SSLEngine="on"/><ListenerclassName="org.apache.catalina.core.JreMemoryLeakPreventionListener"/><ListenerclassName="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/><ListenerclassName="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/><GlobalNamingResources><Resourcename="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><Servicename="Catalina"><Connectorport="8081"protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443"/><!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> --><Enginename="Catalina"defaultHost="localhost"><RealmclassName="org.apache.catalina.realm.LockOutRealm"><RealmclassName="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 &quot;%r&quot; %s %b" />      </Host>	  --><Hostname="localhost"appBase="F:\data\www\a.ttlsa.com"unpackWARs="true"autoDeploy="true"xmlValidation="false"xmlNamespaceAware="false"><Contextpath=""docBase=""reloadable="true"><valveclassName="org.apache.catalina.valves.RemoteAddrValve"/></Context></Host></Engine></Service></Server>

配置b.ttlsa.com

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
<?xml version="1.0" encoding="UTF-8"?><!-- 8005 改為8006 --><Serverport="8002"shutdown="SHUTDOWN"><ListenerclassName="org.apache.catalina.startup.VersionLoggerListener"/><ListenerclassName="org.apache.catalina.core.AprLifecycleListener"SSLEngine="on"/><ListenerclassName="org.apache.catalina.core.JreMemoryLeakPreventionLis