Tomcat 從何而來?
先說 Tomcat 這一單詞解釋,如果你不是一個開發者,當然它在美國口語中並非是褒義詞;如果你是開發者,那你一定聽過 Web 應用服務器、Sun 公司和 Tomcat 。如你所知道那樣,牛逼的公司總是推動這個世界的發展,並建立一個又一個標准,當然,在軟件界 Sun 公司絕對算牛逼中的其一。
在貴的離譜的商用服務器充斥着市場的時候,Sun 公司推出了第一個 Java servlet container(Servlet 容器) 名字叫:Java Web Server(JWS),物美價廉,這簡直是業界的一股清流,但市場並沒有像他們想象的那么喜歡 JWS,一家商業公司如果產品賣不出去,那真是令人極其傷感的,但對於 Sun 公司來說這不重要,因為他們是 Java servlet 這個最初的標准的制定者,應該沒有什么比這個更令人興奮的了。隨着標准的推出,直接推動了當時許多自由的、免費的 Java servlet container 的出現,像 Jetty 、JServ 等這些容器,好像所有人都喜歡免費,當然同時期還有一些商用的如 WebLogic 、JRun 這些容器存在。到這里好像還並沒有出現 Tomcat ,別着急,Sun 公司其實比你更着急,因為 JSP 還沒有出現。
可能由於 Sun 公司在 Servlet 容器市場的低迷表現,他們轉頭又憤而推出了迷你型 servlet coutainer 並支持 Web 的工具包,他們稱之為 JavaServer Pages(JSP),這個工具包(JSDK)任何人都可以下載,接着隨着 Sun 接着制定了新版的 JSP 規范,JSDK 也升級到了 2.1 版本后,注意,這時候大神出現了。在 Sun 公司上班的 James Duncan Davidson 沒有使用任何原來代碼的情況下寫出了一個全新的 servlet contaniner ,從此取代了 JSDK 2.1 版本,因次這也是為什么 Tomcat 的版本是從 3.0 開始的而不是 1.0 。
當然,接下來的加入 Apache 基金會和開源也算是 Sun 公司為軟件界的貢獻,這其中肯定有商業上的考慮,但你何必在意呢。
Tomcat 的基本組成
了解一個事物的本質是現在就用它。不廢話,直接先說一下 Tomcat 的安裝和使用,之前寫過 Tomcat 在 CentOS 、Windows 和配合 Nginx 在做負載均衡這三篇文章,用到的可以簡單看下:
安裝好之后,進入安裝目錄看一眼結構:
簡單介紹一下各個文件夾及文件:
- bin:主要存放腳本文件,例如比較常用的windows和linux系統中啟動和關閉腳本
- conf:主要存放配置文件,其中最重要的兩個配置文件是server.xml和web.xml
- lib:主要存放tomcat運行所依賴的包
- LICENSE:版權許可證,軟件版權信息及使用范圍等信息
- logs:主要存放運行時產生的日志文件,例如catalina.out(曾經掉過一個大坑)、catalina.{date}.log等
- NOTICE:通知信息,一些軟件的所屬信息和地址什么的
- RELEASE-NOTES:發布說明,包含一些版本升級功能點
- RUNNING.txt:運行說明,必需的運行環境等信息
- temp:存放tomcat運行時產生的臨時文件,例如開啟了hibernate緩存的應用程序,會在該目錄下生成一些文件
- webapps:部署web應用程序的默認目錄,也就是 war 包所在默認目錄
- work:主要存放由JSP文件生成的servlet(java文件以及最終編譯生成的class文件)
上面是一個安裝后的 Tomcat 的全部組成部分,如果你要啟動,進入bin
目錄執行startup.sh
就可以了,接着就可以在瀏覽器輸入http://localhost:8080/
訪問了。那么問題來了:當你有了三個、五個以及十個應用服務需要同時部署到同一台服務器上時,你的 Tomcat 服務正確啟動方式是什么?是把上面文件全部復制出 N 多個目錄么?還是有其他處理方式呢?
Tomcat 常見的幾種部署場景
通常,我們在同一台服務器上對 Tomcat 部署需求可以分為以下幾種:單實例單應用,單實例多應用,多實例單應用,多實例多應用。實例的概念可以理解為上面說的一個 Tomcat 目錄。
- 單實例單應用:比較常用的一種方式,只需要把你打好的 war 包丟在
webapps
目錄下,執行啟動 Tomcat 的腳本就行了。 - 單實例多應用:有兩個不同的 Web 項目 war 包,還是只需要丟在
webapps
目錄下,執行啟動 Tomcat 的腳本,訪問不同項目加上不同的虛擬目錄。這種方式要慎用在生產環境,因為重啟或掛掉 Tomcat 后會影響另外一個應用的訪問。 - 多實例單應用:多個 Tomcat 部署同一個項目,端口號不同,可以利用 Nginx 這么做負載均衡,當然意義不大。
- 多實例多應用:多個 Tomcat 部署多個不同的項目。這種模式在服務器資源有限,或者對服務器要求並不是很高的情況下,可以實現多個不同項目部署在同一台服務器上的需求,來實現資源使用的最大化。-
這次其實要說的就是這種方式,但多個 Tomcat 就是簡單的復制出一個新的 Tomcat 目錄后改一下端口么?這樣做也太 Low 了點吧?哈哈,其實並不是低端沒技術含量的問題,當你同一台服務器部署了多個不同基於 Tomcat 的 Web 服務時,會迎來下面幾個極其現實的問題。
- 當你需要對數十台 Tomcat 版本進行升級的時候,你需要怎么做?
- 當你需要針對每一個不同的 Web 服務分配不用的內存時,你需要怎么做?
- 當你需要啟動多台服務器時,你需要怎么做?
當然,好像上面的都不是很重要,注意,划重點,多實例部署最大作用就是最大化利用服務器資源。
說干就干,現在就開始干?
別着急別着急,先看一下官方文檔怎么建議的。他們說可不建議你復制一個又一份的全部 Tomcat 目錄進行多實例的部署,說安照下圖可以實現更優雅的 Tomcat 單機多實例部署:
上圖中的 CATALINA_HOME
指Tomcat安裝路徑,CATALINA_BASE
指實例所在位置。
CATALINA_HOME
路徑下只需要包含 bin
和 lib
目錄,而 CATALINA_BASE
只存放 conf、webapps、logs
等這些文件,這樣部署的好處在於升級方便,配置及安裝文件間互不影響,在不影響 Tomcat 實例的前提下,替換掉 CATALINA_HOME
中的安裝文件。
流程清楚了,接下來才是真正的擼起袖子加油干了。
快來實踐一下吧
你看到了這里肯定已經安裝了 Tomcat 了,我現在演示用的是最新的 8.5.11 版本。
1.復制出兩個 Tomcat 實例
在 Tomcat 安裝路徑的同一級目錄下,新建兩個tomcat-1、tomcat-2
文件夾,先把安裝路徑下的 conf、webapps、temp、logs、work
這五個文件移動到tomcat-1
實例中:
命令:
mkdir tomcat-1 tomcat-2
cd apache-tomcat-8.5.11
mv conf/ webapps/ temp/ logs/ work/ -t ../tomcat-1
接着把tomcat-1
下的這幾個文件再復制到tomcat-2
中,直接命令:
cp tomcat-1/* tomcat-2
2.新建 Tomcat 啟動、停止腳本
依然是在 Tomcat 安裝路徑的同一級目錄下,新建兩個tomcat-shell
文件夾,用於存放啟動和停止腳本,同時賦予文件全部權限。
命令:
cd tomcat-shell/
vim start_tomcat.sh
vim stop_tomcat.sh
chmod 777 start_tomcat.sh stop_tomcat.sh
tomcat-start.sh:
#!/bin/bash
export CATALINA_HOME=/software/apache-tomcat-8.5.11
export CATALINA_BASE=${1%/}
echo $CATALINA_BASE
TOMCAT_ID=`ps aux |grep "java"|grep "Dcatalina.base=$CATALINA_BASE "|grep -v "grep"|awk '{ print $2}'`
if [ -n "$TOMCAT_ID" ] ; then
echo "tomcat(${TOMCAT_ITOMCAT_ID}) still running now , please shutdown it firest";
exit 2;
fi
TOMCAT_START_LOG=`$CATALINA_HOME/bin/startup.sh`
if [ "$?" = "0" ]; then
echo "$0 ${1%/} start succeed"
else
echo "$0 ${1%/} start failed"
echo $TOMCAT_START_LOG
fi
tomcat-stop.sh:
#!/bin/bash
export CATALINA_HOME=/software/apache-tomcat-8.5.11
export CATALINA_BASE=${1%/}
echo $CATALINA_BASE
TOMCAT_ID=`ps aux |grep "java"|grep "[D]catalina.base=$CATALINA_BASE "|awk '{ print $2}'`
if [ -n "$TOMCAT_ID" ] ; then
TOMCAT_STOP_LOG=`$CATALINA_HOME/bin/shutdown.sh`
else
echo "Tomcat instance not found : ${1%/}"
exit
fi
if [ "$?" = "0" ]; then
echo "$0 ${1%/} stop succeed"
else
echo "$0 ${1%/} stop failed"
echo $TOMCAT_STOP_LOG
fi
這兩個就是簡單的腳本,其中傳入了要啟動的 Tomcat 實例所在的路徑,當然,你也可以寫一個重啟的腳本,其實就是先停止再啟動,還可以加入不同的 JVM 參數配置等等操作。
到這里,其實全部基礎工作已經做好了。接下來我們看一眼整個多實例的目錄結構:
3.配置 server.xml 端口
你知道的,同一個服務器部署不同 Tomcat 要設置不同的端口,不然會報端口沖突,所以我們只需要修改conf/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;
我這里把 tomcat-2
實例的 Connector Port
改為了 8081 ,並分別在 tomcat-1、tomcat-2
的 webapps/ROOT
目錄下放入了一個頁面文件,內容如下:
<html>
<title>Tomcat-1</title>
<body>
Hello Mafly! from Tomcat-1.
</body>
</html>
4.啟動
直接通過執行我們剛寫的腳本,傳入某一個 Tomcat 實例路徑即可來啟動對應的 Tomcat。
命令:
/software/tomcat-shell/start_tomcat.sh /software/tomcat-1
/software/tomcat-shell/start_tomcat.sh /software/tomcat-2
去瀏覽器看一眼:
哈哈,可以了。接下來,停止或者重啟什么的都一樣,你可以根據需要來在單個服務器上創建更多的 Tomcat 實例,一切都看你喜歡。
總結一下
這兩天簡單翻了一下 《Tomcat 權威指南》這本書,對於我們日常使用的 Tomcat 有了更詳細的了解,當然我在這里並沒有詳細寫配置、部署管理工具、安全管理和集群什么的,我還了解不夠透徹,只是簡單把 Tomcat 單機多實例比較優雅的部署方式玩了一下,希望對你有用。
昨天晚上看 Linux 和 Git 的發起者 Linus 這位大神的傳記,真是令人感到上帝的不公平,怎么能設計出這樣的天才人類,但更令人興奮的是,我們目前絕大多數人都被設計成了幾乎無差別,還遠遠輪不到拼智商的地步。