1. 程式人生 > >tomcat 之 tomcat實例配置

tomcat 之 tomcat實例配置

tomcat 調度器 cluster session

1 概述

本文通過例子,介紹LNMT和LAMT,結合例子介紹如何實現如下的功能

(1) nginx + tomcat cluster, httpd(proxy_http_module)+tomcat cluster, httpd(proxy_ajp_module)+tomcat cluster;

(2) tomcat cluster升級為session cluster, 使用deltaManager;

(3) tomcat cluster將會話保存至memcached中;

2 概念介紹

LNMT:Linux Nginx MySQL Tomcat

Client (http) --> nginx (reverse proxy)(http) --> tomcat (http connector)

tomcat處理靜態資源效率比nginx低,而且消耗更多的資源,所以靜態資源一般有nginx作為web服務器處理

LAMT:Linux Apache(httpd) MySQL Tomcat

httpd的代理模塊有如下三個:

proxy_module

proxy_http_module:適配http協議客戶端;

proxy_ajp_module:適配ajp協議客戶端;

Client (http) --> httpd (proxy_http_module)(http) --> tomcat (http connector)

Client (http) --> httpd (proxy_ajp_module)(ajp) --> tomcat (ajp connector)

Client (http) --> httpd (mod_jk)(ajp) --> tomcat (ajp connector)

2.1 會話保持:

動態內容通常要追蹤用戶的會話,php或者jsp的會話會定期保存在磁盤,所以重新上線的機器,會話可以從磁盤恢復。但是,需要解決單點故障的問題。

(1) session sticky,會話綁定

source_ip:調度粒度粗糙,用於三四層調度

nginx: ip_hash

haproxy: source

lvs: sh

cookie:七層調度,粒度精細

nginx:hash

haproxy: cookie

(2) session cluster:delta session manager,會話集群,通過多播的方式,把會話傳給集群中的其他主機,保證集群中的所有主機都擁有相同的會話信息。這種調度的缺點是,當站點訪問量很大的時候,站點保存的會話會很多,在會話保持期間每一臺主機持有相同的會話,導致了對每臺服務器都造成壓力。

(3) session server:redis(store), memcached(cache)。節點的會話都保存在服務器中,一般是kv存儲,如redis(kv store,持久存儲)或者memcache(kv cache,不能持久存儲),redis和memcache的存儲都在內存中,沒有復雜的約束關系,(不能使用mysql,因為myslq的約束多,數據存取效率低,不過mysql具有事務的強移植).session server 建議配置為冗余模型。

服務器後端冗余,這裏有兩種機制:

客戶端存儲的時候,直接把會話存儲在後端的多臺緩存服務器上。

另一機制,後端存儲服務器自動同步數據。缺點是存在延時。後端服務可能存在故障,可以用keepalive來實現,但是節點太多的時候,keepalive就實現不了,這個時候,可以使用服務註冊(服務發現+)來實現,在服務總線上註冊自己主機的信息。

2.2 Tomcat Cluster(session)

有三個方式

(1) session sticky

(2) session cluster:tomcat delta manager

(3) session server :借助memcached

Tomcat Cluster,有以下的方案構建集群

一個httpd調度用戶請求到tomcat,httpd有多種變化方式,所以有三種方式

(1) httpd + tomcat cluster,

httpd: mod_proxy, mod_proxy_http, mod_proxy_balancer

tomcat cluster:http connector

(2) httpd + tomcat cluster

httpd: mod_proxy, mod_proxy_ajp, mod_proxy_balancer

tomcat cluster:ajp connector

(3) httpd + tomcat cluster,需要額外編譯安裝,現在不流行了,httpd調度目前主要使用前兩種方式,以下將不演示該方法的實現

httpd: mod_jk

tomcat cluster:ajp connector,實現反代和會話保持

(4) nginx + tomcat cluster 一個nginx調度用戶請求到tomcat

3 例子

3.1 環境準備

實驗前首先實現時間同步和主機名解析

環境如下

host 172.18.50.75為www面向客戶端,作為調度器,兩種安裝方法,安裝nginx和httpd,這裏通過兩種方法演示調度器

172.18.50.72 和73,為tomcat server

安裝軟件; 172.18.50.72 和73

yum install java-1.8.0-openjdk-devel
yum install tomcat tomcat-lib tomcat-admin-webapps tomcat-docs-webapp tomcat-webapps

172.18.50.72 和73 建議將主機名寫入hosts,如172.18.50.72 node1 ,73為node2 ;解析主機名

準備tomcat虛擬主機test和站點頁面

mkdir -pv /usr/share/tomcat/webapps/test/WEB-INF
vim  /usr/share/tomcat/webapps/test/index.jsp

#頁面內容如下

<%@ page language="java" %>
<html>
    <head><title>Tomcat7B</title></head>
    <body>
        <h1><font color="blue">Tomcat7B.sunny.com</font></h1>
        <table align="centre" border="1">
            <tr>
                <td>Session ID</td>
            <% session.setAttribute("sunny.com","sunny.com"); %>
                <td><%= session.getId() %></td>
            </tr>
            <tr>
                <td>Created on</td>
                <td><%= session.getCreationTime() %></td>
            </tr>
        </table>
    </body>
</html>

重啟tomcat服務

systemctl restart tomcat

測試

在瀏覽器上測試,輸入http://172.18.50.72:8080/test和 http://172.18.50.73:8080/test可以看到藍色和紅色的相關session內容,到這裏環境環境準備完成

3.2 調度配置

實現調度這裏介紹三種方法

調度器配置參數

BalancerMember:

格式:BalancerMember [balancerurl] url [key=value [key=value ...]]

status:

D:worker被禁用,不會接受任何請求。

S:worker被管理性的停止。

I:worker處於忽略錯誤模式,並將始終被視為可用。

H:worker處於熱備份模式,只有在沒有其他可行的worker時才能使用。

E:worker處於錯誤狀態。

N:worker處於流失模式,只會接受發往自己的現有粘性會話,並忽略所有其他請求。

loadfactor:負載因子,即權重;

lbmethod:

設置調度算法,負載均衡算法三種:

byrequests 為roundrobin,

bybusiness:根據後端的繁忙程度來調度

bytraffic:根據流量來調度,根據流量較空閑來調度

stickysession:

平衡器粘滯的會話名稱。 該值通常設置為類似於JSESSIONID或PHPSESSIONID的值,並且取決於支持會話的後端應用程序服務器。 如果後端應用程序服務器的cookie使用不同的名稱和url編碼的id使用不同的名稱(如servlet容器),請使用| 分開他們。 第一部分是cookie,第二部分是路徑。在Apache HTTP Server 2.4.4及更高版本中可用。


方法一:配置nginx,實現調度器

vim  /etc/nginx/conf.d/vhost.conf
upstream tcsrvs {
    server 172.18.50.72:8080;
    server 172.18.50.73:8080;
    }   
server {    
    location / { 
            proxy_pass http://tcsrvs;
        }   
}

重啟nginx,在瀏覽器輸入 http:172.18.50.75/test可以查看到不同內容,已經實現調度

或者用curl命令測試調度

for i in {1..10}; do curl -s http://172.18.50.75/test/index.jsp | grep -i tomcat;done

方法二:配置httpd,基於http模塊實現調度

配置如下

vim  /etc/httpd/conf.d/http-tomcat.conf
<proxy balancer://tcsrvs>
    BalancerMember http://172.18.50.72:8080
    BalancerMember http://172.18.50.73:8080
    ProxySet lbmethod=byrequests
</Proxy>
<VirtualHost *:80>
    ServerName lb.sunny.com
    ProxyVia On
    ProxyRequests Off 
     ProxyPreserveHost On
 <Proxy *>
     Require all granted
 </Proxy>
     ProxyPass / balancer://tcsrvs/
     ProxyPassReverse / balancer://tcsrvs/
 <Location />
     Require all granted
 </Location>
</VirtualHost>

測試

重啟http,在瀏覽器輸入 http:172.18.50.75/test可以查看到不同內容,已經實現調度

或者用curl命令測試調度

for i in {1..10}; do curl -s http://172.18.50.75/test/index.jsp | grep -i tomcat;done

方法三:配置httpd,基於ajp模塊實現調度, 後端tomcat依靠ajp協議提供服務

vim  /etc/httpd/conf.d/ajp-tomcat.conf
<proxy balancer://tcsrvs>
    BalancerMember ajp://172.18.50.72:8009
    BalancerMember ajp://172.18.50.73:8009
    ProxySet lbmethod=byrequests
</Proxy>
 <VirtualHost *:80>
    ServerName lb.sunny.com
    ProxyVia On
    ProxyRequests Off 
     ProxyPreserveHost On
 <Proxy *>
     Require all granted
 </Proxy>
     ProxyPass / balancer://tcsrvs/
     ProxyPassReverse / balancer://tcsrvs/
 <Location />
     Require all granted
 </Location>
</VirtualHost>

測試

重啟http,在瀏覽器輸入 http:172.18.50.75/test可以查看到不同內容,已經實現調度

或者用curl命令測試調度

for i in {1..10}; do curl -s http://172.18.50.75/test/index.jsp | grep -i tomcat;done

另外,可以關閉掉後端一臺主機,會發現調度器75已經不會再調度請求到對應的失敗主機上,因為httpd默認有健康檢查功能,移除主機速度快,但是當主機恢復正常後,即被關閉的服務器重新啟動tomcat 8005主進程後,健康檢查就很慎重,要一段時間後才會重新添加恢復的主機為正常

標記後端主機不可用,就不會再次調度到該臺被標記位D的主機,如下例子,則將不會被調度到172.18.50.72這臺機器上

<proxy balancer://tcsrvs>
    BalancerMember ajp://172.18.50.72:8009 status=D
    BalancerMember ajp://172.18.50.73:8009
    ProxySet lbmethod=byrequests
</Proxy>

httpd的balance模塊

httpd的balance模塊有內鍵的狀態管理接口,可以啟用 balancer-manager,內鍵管理接口,啟用內鍵管理器,不要開放給任何人訪問,如指定固定ip 172.18.50.99這臺主機才能訪問該鏈接。在httpd的子配置文件裏添加如下的配置

<Location /balancer-manager>
    SetHandler balancer-manager  
    ProxyPass !
    Require all granted
    order deny,allow
    deny from all
    allow from 172.18.50.99     
 </Location>

測試,在瀏覽器裏輸入http://172.18.50.75/balancer-manager 查看。同時,該頁面的鏈接部分,點擊進入後可以實現相關的管理配置。

到這裏,調度的方法介紹完成。

3.3 session sticky

基於cookie會話綁定,依賴調度器,需要在調度器上配置

基於ajp協議調度,當後端服務器狀態不變時(基於env=BALANCER_ROUTE_CHANGED這個關鍵字實現),不會重新調度,同一請求會調度到同一機器上

http的配置文件,env這個選項表示當後端服務器發生變化的時候,會話綁定才會變化,否則不變

調度器75上子配置文件配置如下

Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
<proxy balancer://tcsrvs>
    BalancerMember ajp://172.18.50.72:8009 route=Tomcat7B
    BalancerMember ajp://172.18.50.73:8009 route=Tomcat7C
    ProxySet lbmethod=byrequests
    ProxySet stickysession=ROUTEID
</Proxy>

virtualhost部分配置不變,見上面調度器的配置

tomcat 72和73上配置如下,只需在engine配置段裏添加jvmRoute的鍵值對即可

vim /usr/share/tomcat/conf/server.xml
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tc7b">

測試,在瀏覽器上輸入http://172.18.50.75/test/,當後端的服務器不發生變化,則同一請求始終會被調度到同一臺服務器上,得到的session和內容是一樣的。

httpd基於http協議的調度方法和ajp協議基本一致。更改協議和端口即可。

註意這裏http不支持基於源地址綁定。nginx可以基於源地址進行調度,這裏的調度也可以使用haproxy來實現。

這裏還有另一種配置實現了會話的綁定,如通過proxypass 配置段裏添加stickysession=jsessionid 來構建,但是一般不采用如下的配置,因為有可能jssesionid帶有服務器本身的內容,如節點的標誌,導致hash值每次不一樣,不能實現會話綁定的效果,所以一般不基於這種方式來實現會話綁定,這裏就不做配置,建議使用上面的例子來實現會話的綁定。

3.4 session cluster

session replication cluster方法實現會話集群即節點會變,但是會話id不變的效果

主要在後端服務器把後端的服務器構建成會話集群,每一個節點本地獲取到新的會話或者更改會話值的時候,要通過後端的會話集群信道,將會話同步到後端的所有服務器上

通過多播實現session的傳輸復制到每一臺後端服務器上,每個收到新的會話信息時,會更新自己的會話集,所以後續調度器根據調度算法隨意調度到任意主機,都保存對應的會話信息,可以處理請求,可以返回相應的信息。這裏的會話一般是通過多播發送的給其他主機,即基於多播實現會話擴散。

集群有多種會話管理器

persistent manager(持久會話管理器),默認的會話管理器,會話會被同步到磁盤內,即使關機,會話依然存在。

delta manager(會話管理器)使用多播集群構建replication cluster要通過delta manager會話管理器來實現,這裏可以理解為每一次傳遞都是通過增量傳遞,會話只傳遞更新的部分會話

backup manager (備用會話管理器) 工作邏輯是會話的復制只在有限的主機間復制,如兩臺,而不是全部的主機,調度時只調度到其中一臺,當這臺主機異常,才會調度到另一臺主機

這裏演示基於Delta Manager的會話綁定,不依賴於調度器,即不需要在前端調度器上配置會話綁定的配置,只需配置調度即可。在後端tomcat上配置cluster,是app級別的,如果直接配置在engine中,則對該engine對應的所有app都有效,也可以直接配置在app中,即一般是放在在host中,只對對應的app生效。

tomcat上相關配置介紹如下

(1) 配置啟用集群,將下列配置放置於<engine>或<host>中;多播地址建議不要使用默認的,節點設定為一致
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
  #建議放在對應的host段裏
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
#定義manager,表示調用哪個manager,如這裏使用deltamanager.可以使用會話ha功能,即會話可以同步到其他節點
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"  #建議更改主播地址
port="45564"
frequency="500" #心跳時間
dropTime="3000"/>  #判定異常的間隔,超出這個間隔就判斷為異常
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" 
address="auto" #綁定在本機正常通信的地址,auto自動找,不建議,綁定的地址為auto時,會自動解析本地主機名,並解析得出的IP地址作為使用的地址;建議直接設定本機ip,如172.18.50.75,
port="4000"
autoBind="100"
selectorTimeout="5000" #挑選器的超時時間
maxThreads="6"/> #最大線程數,表示一共啟用多少線程來接收其他主機傳過來的會話,如集群4臺,這裏就設置為3就足夠了。
 # Receiver表示定義一個接收器,接收別人傳過來的多播信息
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
# Sender是定義如何把會話信息發送給同一集群中的其他節點
<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解析器,解析當什麽時候
</Channel>
# Channel是定義集群成員關系
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=""/> #valve閥門,考慮到jvmRoute
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<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.JvmRouteSessionIDBinderListener"/>
#ClusterListener監聽java集群資源是否發生變化,如果發生變化要如何變得集群的變化。
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>        
確保Engine的jvmRoute屬性配置正確。
 (2) 配置webapps
編輯WEB-INF/web.xml,添加<distributable/>元素;這個要手動添加

例子

編輯tomcat主機,

步驟一,修改配置文件,有兩個地方需要配置

一是engine裏需要添加jvmRoute配置

二是 Cluster配置放在host配置段裏,以下配置只需要調整組播地址和本機的ip,其他地方不需要調整。兩臺tomcat都需要配置

vim /usr/share/tomcat/conf/server.xml 
  <Engine name="Catalina" defaultHost="localhost" jvmRoute="tc7b">
#以下放在host配置段裏
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
<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.0.0.4"  #需要更改
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="172.18.50.72"  #調整為本機的ip,不使用默認的auto
port="4000"
autoBind="100"
selectorTimeout="5000"
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"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<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.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>

步驟二

集群會話的app的web.xml裏需要配置<distributable/>這個元素,配置在web.xml的web-app配置段裏即可。一般程序員開發的站點web.xml這個文件肯定是存在的,而且是放在WEB-INF目錄下,不過實驗環境沒有,所以就拷貝公共的web.xml到對應主機目錄下

cp /etc/tomcat/web.xml /usr/share/tomcat/webapps/test/WEB-INF/
vim /usr/share/tomcat/webapps/test/WEB-INF/web.xml
<distributable/>

保存後退出。重啟tomcat服務器

測試:在瀏覽器上輸入http://172.18.50.75/test/,可以看到此時請求被調度到不同的機器上,但是,頁面上的session id始終保持不變。則實驗成功。說明在不同的服務器上已經有同一session id。即實現了會話集群即節點會變,但是會話不變。

3.5 session server

借助第三方的工具memcached實現,tomcat cluster將會話保存至memcached中,通過memcached來實現。把memcached當做tomcat的session server,不需要在前端做綁定會話,不需要在tomcat服務器綁定會話。後端的memcache需要做高可用,後端支持兩臺memcache,tomcat服務器開啟雙寫機制,所有要存儲的信息都同時寫入後端的兩臺memcache裏,讀取數據時可以只讀取一臺,當memcache主服務器掛掉,就啟用備用的memcache.支持分布式,空間不夠可以擴容

配置案例的介紹鏈接,如下:https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration

tomcat自身不直接把會話保存在memcache中,需要借助開發工具來實現。相應的項目官方代碼可以直接從github上搜到。資源鏈接:https://github.com/magro/memcached-session-manager

對tomcat而言,要把會話保存在memcache中,有以下幾種類庫

第一:要使用專門的會話管理工具memcache-session-manager的類庫,如 memcached-session-manager-${version}.jar 和 memcached-session-manager-tc7-${version}.jar(如tomcat是7版本)這個類庫

第二: 會話是保存在內存中,不支持流式化,借助流式化工具實現,流式化工具有如下四種,可以任意用一種,這些是類庫,需要裝入tomcat才能使用

kryo-serializer: msm-kryo-serializer, kryo-serializers-0.34+, kryo-3.x, minlog, reflectasm, asm-5.x, objenesis-2.x

javolution-serializer: msm-javolution-serializer, javolution-5.4.3.1

xstream-serializer: msm-xstream-serializer, xstream, xmlpull, xpp3_min

flexjson-serializer: msm-flexjson-serializer, flexjson

第三:支持適配對應存儲系統的類庫,如要使得tomcat和memcached能通信,要有能適配memcached客戶端的類庫,如 spymemcached-${version}.jar。如果存儲是redis,則要使用jedis-2.9.0.jar.

這裏介紹流式工具為javolution-serializer的部署

例子

步驟一

前端調度器上不需要做綁定的設置,只需要配置調度即可

步驟二

找兩臺服務器172.18.50.62和63,安裝memcached,並啟用memcached服務。

yum -y  install memcached
systemctl restart memcached

步驟三

後端tomcat 72和73 在如下的路徑放置相關的jar包

/usr/share/tomcat/webapps/test/WEB-INF/lib/路徑下放置兩個類庫

javolution-5.4.3.1.jar

msm-javolution-serializer-2.1.1.jar

/usr/share/tomcat/lib/路徑下放置三個類庫

memcached-session-manager-2.1.1.jar

memcached-session-manager-tc7-2.1.1.jar

spymemcached-2.12.3.jar

編輯配置文件server.xml,放置host配置段裏,如下

vim  /usr/share/tomcat/conf/server
<Context path="/test" docBase="/usr/share/tomcat/webapps/test" reloadable="true">
              <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
                memcachedNodes="n1:172.18.50.62:11211,n2:172.18.50.63:11211"
                failoverNodes="n1"
                requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
                transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"
              />
             </Context>

重啟tomcat服務器

測試

在瀏覽器裏輸入http://172.18.50.75/test,不管怎麽調度, session id始終不變,但是網頁上的其他內容已經發生變化,說明實驗成功。





本文出自 “陽光運維” 博客,請務必保留此出處http://ghbsunny.blog.51cto.com/7759574/1982321

tomcat 之 tomcat實例配置