Tomcat多實例部署及其原理

導讀:
昨天在跟羣友作技術交流的時候,瞭解到,有不少大公司都是採用了高可用的,分佈式的,實例沉餘1+臺。可是在小公司的同窗也不少,他們反映並非全部公司都有那樣的資源來供你調度。每每公司只會給你一臺機器,由於有些應用掛了公司也不會有損失的,咱們每每一臺機器就能夠搞定。
可是,咱們也要爲咱們作出來的應用負責,畢竟東西作出來是爲了給人用的,若是作出來的東西常常掛了,談何使用,在前期,若是公司資源緊張的狀況下,能夠不能夠作高可用,多機器的沉餘部署。可是至少是在但機上有2個進程在跑。so,在這裏咱們就說說這個,如何作單機多實例的部署。
在這裏談談,在只有單機的資源下,如何把單機的資源壓榨出來,用好單機。html

一、Tomcat部署的場景分析

一般,咱們對tomcat單機部署需求能夠分爲幾種:java

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

第一種場景:這是咱們開發中常常用到的,若是不要求週期性地維護tomcat版本,通常的作法是把打好的war包丟到webapps目錄下,而後執行startup.sh腳本,而且能夠在瀏覽器裏訪問就好了。
第二種場景:是把多個應用程序的war包放在同一個tomcat的webapps目錄,這樣一來,關閉和啓動tomca,或tomcat掛掉會影響全部項目。
第三種場景: 各個tomcat都運行同一個應用程序,對應地須要修改不一樣的監聽端口,這種方式一般會和apache httpd或者nginx整合使用,作一些負載均衡的處理。
第四種場景: 至關於第一種場景的複數形式,除了修改不一樣的監聽端口,沒有本質區別。linux

通常來講,多實例部署tomcat,能夠充分利用系統資源,不過這種方式,也有幾個方面須要考慮:
多實例tomcat的更新維護,例如對tomcat進行升級等操做,咱們須要考慮如何能「優雅」地對全部實例進行升級
儘可能不要影響應用程序,在更新tomcat時,一不當心就把conf目錄等所有覆蓋,因此儘可能要把配置文件和安裝目錄隔離
對於單應用來講,若是將war包分別置於各個tomcat的webapps目錄,那麼在發佈新版本的war時,可能會出現某個實例更新失敗,致使用戶在訪問時可能會訪問到不一樣版本的web app,所以,比較好的方式就是全部tomcat實例都統一指向同一個應用程序,這樣作,就能夠多個tomcat用一份應用源碼,簡單部署,單機高可用也能實現(要配合nginx).
本文重點闡述多實例應用的部署方案,可是爲了解決上述幾個問題,咱們須要先來了解一下tomcat的一些基本狀況。nginx

二、咱們的目標

 

tomcat架構

 

三、tomcat架構

總體架構圖

 

tomcat架構

 

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

分離目錄

目錄 做用
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_HOME和CATALINA_BASE:shell

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容器子容器間關係圖apache

tomcat架構

 

交互圖windows

tomcat架構

 

對比下Tomcat serve.xml 的配置瀏覽器

<?xml version="1.0" encoding="UTF-8"?>

<Server port="8005" shutdown="SHUTDOWN">

<Listener className="org.apache.catalina.startup.VersionLoggerListener" />

<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />

<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

<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">

<Connector port="8080" protocol="HTTP/1.1"

connectionTimeout="20000"

redirectPort="8443" />

<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 &quot;%r&quot; %s %b" />

</Host>

</Engine>

</Service>

</Server>


四、實戰

端口配置

修改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配置以下

<Host name="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配置以下

<Context path="/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 

<?xml version="1.0" encoding="UTF-8"?>

<!-- 8005 改成8005 -->

<Server port="8005" shutdown="SHUTDOWN">

<Listener className="org.apache.catalina.startup.VersionLoggerListener" />

<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />

<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

<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">

<Connector port="8081" protocol="HTTP/1.1"

connectionTimeout="20000"

redirectPort="8443" />

<!-- <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 &quot;%r&quot; %s %b" />

</Host>

-->

<Host name="localhost" appBase="F:\data\www\a.ttlsa.com"

unpackWARs="true" autoDeploy="true"

xmlValidation="false" xmlNamespaceAware="false">

<Context path="" docBase="" reloadable="true">

<valve className="org.apache.catalina.valves.RemoteAddrValve" />

</Context>

</Host>

</Engine>

</Service>

</Server>


配置b.ttlsa.com

<?xml version="1.0" encoding="UTF-8"?>

<!-- 8005 改成8006 -->

<Server port="8002" shutdown="SHUTDOWN">

<Listener className="org.apache.catalina.startup.VersionLoggerListener" />

<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />

<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

<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">

<Connector port="8082" protocol="HTTP/1.1"

connectionTimeout="20000"

redirectPort="8443" />

<!-- <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 &quot;%r&quot; %s %b" />

</Host>

-->

<Host name="localhost" appBase="F:\data\www\a.ttlsa.com"

unpackWARs="true" autoDeploy="true"

xmlValidation="false" xmlNamespaceAware="false">

<Context path="" docBase="" reloadable="true">

<valve className="org.apache.catalina.valves.RemoteAddrValve" />

</Context>

</Host>

</Engine>

</Service>

</Server>


建立多實例啓動腳本

# description: 啓動tomcat多實例.#

. /etc/init.d/functions

RETVAL=$?

# tomcat實例目錄

export CATALINA_BASE="$PWD"

# tomcat安裝目錄

export CATALINA_HOME="/usr/local/tomcat-7.0.50"

# 可選

export JVM_OPTIONS="-Xms128m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=512m"

case "$1" in

start)

if [ -f $CATALINA_HOME/bin/startup.sh ];then

echo $"Start Tomcat"

$CATALINA_HOME/bin/startup.sh

fi

;;

stop)

if [ -f $CATALINA_HOME/bin/shutdown.sh ];then

echo $"Stop Tomcat"

$CATALINA_HOME/bin/shutdown.sh

fi

;;

*)

echo $"Usage: $0 {start|stop}"

exit 1

;;

esac

exit $RETVAL


這段shell 腳本比較簡單,主要是設置環境變量,接受命令參數 RETVAL=?,來執行不一樣的命令。RETVAL=start/stop等exportCATALINABASE=」?,來執行不一樣的命令。RETVAL=start/stop等exportCATALINABASE=」PWD」 表示設置當前路徑爲 CATALINA_BASE 的環境變量,通常狀況下CATALINA_BASE 和 CATALINA_HOME 是默認同樣的。

啓動腳本賦權限

# chmod a+x tomcat.sh


五、啓動測試

啓動/關閉a.ttlsa.com

啓動

# cd /usr/local/tomcat-7.0.50/a.ttlsa.com/

# ./tomcat.sh start

關閉

# cd /usr/local/tomcat-7.0.50/a.ttlsa.com/

# ./tomcat.sh stop


啓動/關閉b.ttlsa.com

啓動

# cd /usr/local/tomcat-7.0.50/a.ttlsa.com/

# ./tomcat.sh start

關閉

# cd /usr/local/tomcat-7.0.50/a.ttlsa.com/

# ./tomcat.sh stop


備註:必定須要cd到tomcat.sh的當前目錄下執行才能夠

在win7 下,須要建立在a.ttlsa.com 和b.ttlsa.com下面建立 startup.bat 來啓動

@echo off

set JAVA_HOME=D:\Program Files\Java\jdk1.8.0_112

set PATH=%JAVA_HOME%\bin;%PATH%

set CATALINA_BASE=%CD%

cd E:\tomcat-8.5.6\bin

catalina.bat start


shell 腳本入門參考:http://sishuok.com/forum/blogPost/list/5655.html這段是在win7 下雲的bat腳本,於shell腳本同理,set CATALINA_BASE=%CD% 也是設置環境變量,CD 能夠獲取當前的路徑。

六、結果

單個Tomcat應用多個tomcat實例的配置到此,就結束了。
此外,咱們在這裏的基礎上進行系統的擴展,好比若是個人Tomcat應用掛掉了,個人整個應用都將不可用了,咱們應該如何處理?
咱們能夠把Tomcat複製多份,在單機的狀況下,開多一個Tomcat進程,在配合Nginx 來配置,就能實現Tomcat的自動切換,這些內容,有空再寫。

若是須要操做多個實例顯得比較麻煩,你們能夠自行寫統一的腳本。

 

tomcat架構

 

tomcat架構

 

Linux 下的實現基本一致。

這樣的好處是,顯而易見的,這樣能開啓Tomcat的多個進程,即多臺tomcat,掛了也不太怕,還有其餘tomcat應用支撐,代碼實例咱們發版本的時候,只須要發佈一份,實例代碼易於維護。
可是,咱們網站的域名和端口通常是同一採用80端口,統一的域名,而如今咱們開啓tomcat只能一個使用80端口,顯然是不合適的·,爲此咱們會引入負載均衡的nginx來配置。
nginx 採用80 端口,tomcat分別採用8080, 8081, 8082 這樣就能讓咱們的程序穩定的運行。
這樣,咱們就能進最大的限度來壓榨單機的性能,保證應用程序的穩定的運行。
而然,單機否則有單機的瓶頸,畢竟單機中的cpu 已經各類硬件的限制,會大大影響實例程序的跑動,在這時,就再也不是單機能抗的動的了,咱們須要分析程序的瓶頸在那?數據庫,那就把數據庫單獨分出去,單獨一臺機器,是文件圖片服務器,就把他分出去。若是是應用程序太大,就要考慮把應用實例進行拆解爲不一樣哦那個的組件,單獨部署,這就是分佈式部署。
固然,這都是後話,只有程序複雜到必定的程度,並體量很大的話,纔會作這種架構的演變,成本和技術投入的難度也會相應的變大。
本章,只侷限於如何玩好單機的基礎上來討論,對於分佈式的那塊,筆者能力有限,尚且還不能徹底駕馭,不作分享。

七、nginx+tomcat熱備

在上面的配置的基礎上,咱們在進一步進行擴展,進行實例的均衡和熱備。
能夠在一個服務器掛了的狀況下連到另一個,那怎麼弄呢?
其實很簡單,在upstream中的local_tomcat中配置多一個server。
在上面,個人a.ttlsa.com 和 b.ttlsa.com 都是訪問 F:\data\www\a.ttlsa.com 下的源碼的index.jsp 頁面,
爲了能觀察,nginx 的keepAlive 的效果,我作一下修改:
a.ttlsa.com —> F:\data\www\a.ttlsa.com index.jsp 中文字是 1
b.ttlsa.com —> F:\data\www\b.ttlsa.com index.jsp 中文字是 2

upstream local_tomcat {

server localhost:8081 weight=1;

server localhost:8082 weight=5;

}

 

server {

listen 80;

server_name localhost:8081;

#charset koi8-r;

#access_log logs/host.access.log main;

#location / {

# root html;

# index index.html index.htm;

#}

location / {

proxy_pass http://local_tomcat;

}

 

tomcat架構

 

在一般的狀況下,咱們通常是指向一份源碼就足夠了,而且設置權值,減輕應用的壓力。同時也不會出現單點的狀況。

補充:nginx.con 配置

#user  nobody;
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    upstream local_tomcat {  
        server localhost:8081 weight=1;  
        server localhost:8082 weight=5;  
    } 

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        #location / {
        #    root   html;
        #    index  index.html index.htm;
        #}        
        location / {  
            proxy_pass http://local_tomcat;  
        }  

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

}

綜上:咱們作到了多臺tomcat 可是咱們也能作到tomcat的簡單升級,而且實現實例的負載均衡,已經應用的主備,在也不用擔憂應用掛掉而睡不了覺了。

本次的實驗資源供下載:http://download.csdn.net/detail/a82793510/9687715

相關文章
相關標籤/搜索