Tomcat之反向代理、負載均衡、session綁定、session共享以及集羣的構建

[root@node2 ~]# rpm -e httpdphp


實驗環境html

node1 192.168.139.2前端

node4 192.168.139.8java

node5 192.168.139.9node


node1上編譯安裝httpd,用來做爲前端反向代理服務器mysql

node4|node5上安裝Tomcat,用來做爲後端的Tomcat應用程序服務器linux


node4安裝jdk
nginx

[root@node4 tool]# tar -xf jdk-8u111-linux-x64.tar.gz -C /usr/local/java/web

[root@node4 tool]# vim /etc/profile.d/java.sh算法

export JAVA_HOME=/usr/local/java/jdk1.8.0_111

export JRE_HOME=/usr/local/java/jdk1.8.0_111/jre

export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH

export PATH=$JAVA_HOME/bin:$PATH


[root@node4 tool]# . /etc/profile.d/java.sh 

[root@node4 tool]# java -version

java version "1.8.0_111"

Java(TM) SE Runtime Environment (build 1.8.0_111-b14)

Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)


node4vim 安裝Tomcat

[root@node4 tool]# tar -xf apache-tomcat-7.0.73.tar.gz -C /usr/local/

[root@node4 tool]# cd /usr/local/

[root@node4 local]# ln -sv apache-tomcat-7.0.73/ tomcat

`tomcat' -> `apache-tomcat-7.0.73/'

[root@node4 local]# cd tomcat/

[root@node4 tomcat]# vim /etc/profile.d/tomcat.sh

export CATALINA_HOME=/usr/local/tomcat

export PATH=$PATH:$CATALINA_HOME/bin

                                  

[root@node4 tomcat]# . /etc/profile.d/tomcat.sh 

[root@node4 tomcat]# catalina.sh version

Using CATALINA_BASE:   /usr/local/tomcat

Using CATALINA_HOME:   /usr/local/tomcat

Using CATALINA_TMPDIR: /usr/local/tomcat/temp

Using JRE_HOME:        /usr/local/java/jdk1.8.0_111/jre

Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar

Server version: Apache Tomcat/7.0.73

Server built:   Nov 7 2016 21:27:23 UTC

Server number:  7.0.73.0

OS Name:        Linux

OS Version:     2.6.32-573.el6.x86_64

Architecture:   amd64

JVM Version:    1.8.0_111-b14

JVM Vendor:     Oracle Corporation


[root@node4 tomcat]# catalina.sh start

Using CATALINA_BASE:   /usr/local/tomcat

Using CATALINA_HOME:   /usr/local/tomcat

Using CATALINA_TMPDIR: /usr/local/tomcat/temp

Using JRE_HOME:        /usr/local/java/jdk1.8.0_111/jre

Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar

Tomcat started.

wKiom1hrIzLhL-TMAAGG297c5So568.png



[root@node4 logs]# catalina.sh stop


添加一個虛擬主機,修改默認虛擬主機

[root@node4 logs]# vim /usr/local/tomcat/conf/server.xml 

 <Engine name="Catalina" defaultHost="node4.zxl.com" jvmRoute="TomcatA">

修改默認的虛擬主機爲新添加的虛擬主機,並加一個jvm路由標籤「TomcatA」(Jvm的路由名稱,每一個JVM實例均可以有一個獨立的名稱,用來在多JVM實例的狀況下區分)


加入虛擬主機,其中應用程序目錄爲/web/webapps

 <Host name="node4.zxl.com"  appBase="/web"

            unpackWARs="true" autoDeploy="true">

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

      </Host>


[root@node4 logs]# catalina.sh configtest #測試配置語法前,關掉tomcat

.......輸出一大堆內容,不過不要緊

INFO: Initializing ProtocolHandler ["ajp-bio-8009"]

Jan 03, 2017 1:35:50 PM org.apache.catalina.startup.Catalina load

INFO: Initialization processed in 2315 ms


添加jsp測試頁面

[root@node4 logs]# vim /web/webapps/index.jsp 


  <%@ page language="java" %>

  <html>

  <head><title>TomcatA</title></head>

  <body>

    <h1><font color="red">TomcatA </font></h1>

    <table align="centre" border="1">

      <tr>

        <td>Session ID</td>

    <% session.setAttribute("abc","abc"); %>

        <td><%= session.getId() %></td>

      </tr>

      <tr>

        <td>Created on</td>

        <td><%= session.getCreationTime() %></td>

     </tr>

   </table>

  </body>

  </html>


啓動Tomcat

[root@node4 logs]# catalina.sh start


wKioL1hrOKWR7QJYAABUE6uB52k243.png


[root@node4 jsp]# cd /usr/local/tomcat/work/Catalina/node4.zxl.com/_/org/apache/jsp/

[root@node4 jsp]# ls

index_jsp.class  index_jsp.java

注:其中work目錄爲工做目錄,Catalina爲Engine名稱,node4.zxl.com爲Host的名稱

/usr/local/tomcat/work/Catalina/node4.zxl.com/_/org/apache/jsp/下的.class和.java就是咱們剛纔經過瀏覽器進行第一次訪問/web/webapps/index.jsp時在tomcat的Web Container中動態編譯生成的.java源程序和.class類,而第二次訪問相同的資源,就直接使用這裏的.class類,不用再次編譯,這就是爲何用JSP寫的站點第一次訪問慢,第二次訪問相同資源就很快的緣由;同時也是用JSP寫的站點訪問快的主要緣由


ok!在node4上tomcat已近安裝而且測試成功,一樣方法在node5安裝Tomcat就行,這裏再也不演示


node5上的tomcat測試以下:

wKioL1hrQLbzLCI-AAAtR9NzZYw901.png




Apache反向代理請求到後端的Tomcat,node2編譯安裝httpd

[root@node2 ~]# rpm -e httpd #刪除之前安裝的httpd,本身編譯安裝

[root@node2 ~]# rpm -ql httpd 

package httpd is not installed

[root@node2 tool]# tar -xf apr-1.5.2.tar.gz 

[root@node2 tool]# cd apr-1.5.2

[root@node2 apr-1.5.2]# ./configure --prefix=/usr/local/apr

[root@node2 apr-1.5.2]# make &&make install


[root@node2 tool]# tar -xf apr-util-1.5.4.tar.gz 

[root@node2 tool]# cd apr-util-1.5.4

[root@node2 apr-util-1.5.4]# ./configure --prefix=/usr/local/apr-util --with-         apr=/usr/local/apr

[root@node2 apr-util-1.5.4]# make &&make install


[root@node2 tool]# tar -xf httpd-2.4.23.tar.gz 

[root@node2 tool]# cd httpd-2.4.23

[root@node2 httpd-2.4.23]# ./configure --prefix=/usr/local/apache --sysconfdir=/etc/httpd --enable-so --enable-ssl --enable-cgi --enable-rewrite --with-zlib --with-pcre --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util --enable-mpms-shared=all --with-mpm=event --enable-proxy --enable-proxy-http --enable-proxy-ajp --enable-proxy-balancer  --enable-lbmethod-heartbeat --enable-heartbeat --enable-slotmem-shm  --enable-slotmem-plain --enable-watchdog

[root@node2 httpd-2.4.23]# make &&make install


爲編譯安裝的Apache提供Sysv啓動腳本

         [root@node2 httpd-2.4.23]# vim /etc/rc.d/init.d/httpd

          #!/bin/bash

#

# httpd        Startup script for the Apache HTTP Server

#

# chkconfig: - 85 15

# description: Apache is a World Wide Web server.  It is used to serve \

#       HTML files and CGI.

# processname: httpd

# config: /etc/httpd/conf/httpd.conf

# config: /etc/sysconfig/httpd

# pidfile: /var/run/httpd.pid


# Source function library.

. /etc/rc.d/init.d/functions


if [ -f /etc/sysconfig/httpd ]; then

. /etc/sysconfig/httpd

fi


# Start httpd in the C locale by default.

HTTPD_LANG=${HTTPD_LANG-"C"}


# This will prevent initlog from swallowing up a pass-phrase prompt if

# mod_ssl needs a pass-phrase from the user.

INITLOG_ARGS=""


# Set HTTPD=/usr/sbin/httpd.worker in /etc/sysconfig/httpd to use a server

# with the thread-based "worker" MPM; BE WARNED that some modules may not

# work correctly with a thread-based MPM; notably PHP will refuse to start.


# Path to the apachectl script, server binary, and short-form for messages.

apachectl=/usr/local/apache/bin/apachectl

httpd=${HTTPD-/usr/local/apache/bin/httpd}

prog=httpd

pidfile=${PIDFILE-/var/run/httpd.pid}

lockfile=${LOCKFILE-/var/lock/subsys/httpd}

RETVAL=0


start() {

echo -n $"Starting $prog: "

LANG=$HTTPD_LANG daemon --pidfile=${pidfile} $httpd             $OPTIONS

RETVAL=$?

echo

[ $RETVAL = 0 ] && touch ${lockfile}

return $RETVAL

}


stop() {

echo -n $"Stopping $prog: "

killproc -p ${pidfile} -d 10 $httpd

RETVAL=$?

echo

[ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}

}

reload() {

echo -n $"Reloading $prog: "

if ! LANG=$HTTPD_LANG $httpd $OPTIONS -t >&/dev/null; then

RETVAL=$?

echo $"not reloading due to configuration syntax error"

failure $"not reloading $httpd due to configuration syntax         error"

else

killproc -p ${pidfile} $httpd -HUP

RETVAL=$?

fi

echo

}


# See how we were called.

case "$1" in

  start)

start

;;

  stop)

stop

;;

  status)

status -p ${pidfile} $httpd

RETVAL=$?

;;

  restart)

stop

start

;;

  condrestart)

if [ -f ${pidfile} ] ; then

stop

start

fi

;;

  reload)

reload

;;

  graceful|help|configtest|fullstatus)

$apachectl $@

RETVAL=$?

;;

  *)

echo $"Usage: $prog {start|stop|restart|condrestart|reload|status|fullstatus|graceful|help|configtest}"

exit 1

 esac


 exit $RETVAL



[root@node2 httpd-2.4.23]# chmod +x /etc/rc.d/init.d/httpd

[root@node2 httpd-2.4.23]# chkconfig --add httpd

[root@node2 httpd-2.4.23]# service httpd start

Starting httpd:                                         [  OK  ]

看來這個腳本的stop關閉httpd有問題

[root@node2 httpd-2.4.23]# service httpd stop

Stopping httpd:                                         [FAILED]

[root@node2 httpd-2.4.23]# service httpd restart

Stopping httpd:                                         [FAILED]

Starting httpd: httpd (pid 33077) already running

                                                   [  OK  ]

[root@node2 httpd-2.4.23]# tail /usr/local/apache/logs/error_log 

[Tue Jan 03 12:28:49.353372 2017] [mpm_event:notice] [pid 33077:tid 140099424745216] AH00489: Apache/2.4.23 (Unix) configured -- resuming normal operations

[Tue Jan 03 12:28:49.353815 2017] [core:notice] [pid 33077:tid 140099424745216] AH00094: Command line: '/usr/local/apache/bin/httpd'


經過httpd (pid 33077) already running的提示可知是httpd關閉時沒有將pid文件刪掉

[root@node2 httpd-2.4.23]# vim  /usr/local/apache/logs/httpd.pid 


33077


刪除pid文件

[root@node2 httpd-2.4.23]# rm -rf   /usr/local/apache/logs/httpd.pid 

[root@node2 httpd-2.4.23]# vim /etc/httpd/httpd.conf 

加入 PidFile "/var/run/httpd.pid"

[root@node2 httpd-2.4.23]# service httpd restart

Stopping httpd:                                          [FAILED]

Starting httpd:                                          [  OK  ]

[root@node2 httpd-2.4.23]# service httpd restart

Stopping httpd:                                          [  OK  ]

Starting httpd:                                          [  OK  ]

OK,httpd的啓動腳本正常,至此node4上的httpd編譯安裝完成



[root@node5 webapps]# vim /etc/httpd/conf/httpd.conf 

#DocumentRoot "/var/www/html"

include /etc/httpd/extra/httpd-proxy.conf

啓用如下模塊

LoadModule slotmem_shm_module modules/mod_slotmem_shm.so

LoadModule slotmem_plain_module modules/mod_slotmem_plain.so

#負載均衡時依賴這兩個內存共享模塊

LoadModule proxy_module modules/mod_proxy.so

#讓Apache反向代理的模塊

LoadModule proxy_connect_module modules/mod_proxy_connect.so

LoadModule proxy_ftp_module modules/mod_proxy_ftp.so

LoadModule proxy_http_module modules/mod_proxy_http.so

#以http協議轉發請求至後端Tomcat

LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so

#支持fast-cgi

LoadModule proxy_scgi_module modules/mod_proxy_scgi.so

#支持scgi

LoadModule proxy_ajp_module modules/mod_proxy_ajp.so

#以ajp協議轉發請求至後端Tomcat

LoadModule proxy_balancer_module modules/mod_proxy_balancer.so

#讓Apache反向代理至後端Tomcat時支持負載均衡

LoadModule proxy_express_module modules/mod_proxy_express.so

[root@node2 ~]# /usr/local/apache/bin/httpd -D DUMP_MODULES |grep proxy

 proxy_module (shared)

 proxy_connect_module (shared)

 proxy_ftp_module (shared)

 proxy_http_module (shared)

 proxy_fcgi_module (shared)

 proxy_scgi_module (shared)

 proxy_ajp_module (shared)

 proxy_balancer_module (shared)

 proxy_express_module (shared)


[root@node2 ~]# vim /etc/httpd/extra/httpd-proxy.conf 


<VirtualHost *:80>

  ProxyVia Off

  ProxyRequests Off

  ProxyPass / http://192.168.139.8:8080/

  ProxyPa***everse / http://192.168.139.8:8080/

 <Proxy *>

   Require all granted

 </Proxy>

  <Location / >

    Require all granted

  </Location>

</VirtualHost>


注:

ProxyVia {On|Off|Full|Block}:用於控制在http首部是否使用Via首部(這樣可讓client端知道請求時由哪一個server代理的),主要用於在多級代理中控制代理請求的流向。默認爲Off,即不啓用此功能;On表示每一個請求和響應報文均添加Via:;Full表示每一個Via:行都會添加當前apache服務器的版本號信息;Block表示每一個代理請求報文中的Via:都會被移除。


ProxyRequests {On|Off}:是否開啓apache正向代理的功能;啓用此項時爲了代理http協議必須啓用mod_proxy_http模塊。同時,若是爲apache設置了ProxyPass,則必須將ProxyRequests設置爲Off,正反向代理不能同時使用


ProxyPreserveHost {On|Off}:若是啓用此功能,則會讓後端server支持虛擬主機;代理會將用戶請求報文中的Host:行發送給後端的服務器,而再也不使用ProxyPass指定的服務器地址。若是想在反向代理中支持虛擬主機,則須要開啓此項,不然就無需打開此功能。


ProxyPass  [path]  !|url  [key=value key=value ...]]:將後端服務器某URL與當前服務器的某虛擬路徑關聯起來做爲提供服務的路徑,path爲當前服務器上的某虛擬路徑,url爲後端服務器上某URL路徑。使用此指令時必須將ProxyRequests的值設置爲Off。須要注意的是,若是path以「/」結尾,則對應的url也必須以「/」結尾,反之亦然。

如訪問後端某應用程序的路徑爲 http://http192.168.139.8:8080/fprum

則前端Apache的代理爲:ProxyPass  /forum http://192.168.139.8/forum  

即前端的uri必須和後端的uri保持一致(除非寫大量的uri重寫規則)


另外,mod_proxy模塊在httpd 2.1的版本以後支持與後端服務器的鏈接池功能,鏈接在按需建立在能夠保存至鏈接池中以備進一步使用。鏈接池大小或其它設定能夠經過在ProxyPass中使用key=value的方式定義。經常使用的key以下所示:


◇ min:鏈接池的最小容量,此值與實際鏈接個數無關,僅表示鏈接池最小要初始化的空間大小。

◇ max:鏈接池的最大容量,每一個MPM都有本身獨立的容量;都值與MPM自己有關,如Prefork的老是爲   1,而其它的則取決於ThreadsPerChild指令的值。

◇ loadfactor:用於負載均衡集羣配置中,定義對應後端服務器的權重,取值範圍爲1-100。

◇ retry:當apache將請求發送至後端服務器獲得錯誤響應時等待多長時間之後再重試。單位是秒鐘。


若是Proxy指定是以balancer://開頭,即用於負載均衡集羣時,其還能夠接受一些特殊的參數,以下所示:

◇lbmethod:apache實現負載均衡的調度方法,默認是byrequests(輪調),即基於權重將統計請求個數進行調度,bytraffic則執行基於權重的流量計數調度,bybusyness經過考量每一個後端服務器的當前負載進行調度。

◇ maxattempts:放棄請求以前實現故障轉移的次數,默認爲1,其最大值不該該大於總的節點數。

◇ nofailover:取值爲On或Off,設置爲On時表示後端服務器故障時,用戶的session將損壞;所以,在後端服務器不支持session複製時可將其設置爲On。

◇ stickysession:調度器的sticky session的名字,根據web程序語言的不一樣,其值爲JSESSIONID(用於Java的)或PHPSESSIONID(用於php的)。

上述指令除了能在banlancer://或ProxyPass中設定以外,也可以使用ProxySet指令直接進行設置,如:


<Proxy balancer://hotcluster>

BalancerMember  http://node1.zxl.com:8080 loadfactor=1

BalancerMember  http://node2.zxl.com:8080 loadfactor=2

ProxySet  lbmethod=bytraffic

</Proxy>


ProxyPa***everse:用於讓apache調整HTTP重定向響應報文中的Location、Content-Location及URI標籤所對應的URL,在反向代理環境中必須使用此指令避免響應報文和重定向報文繞過proxy服務器。


<Proxy *> Require all granted </Proxy>:容許全部用戶訪問

   

 



[root@node2 ~]# service httpd restart


wKioL1hrZprBmJYVAAA9nrV4qFk598.png


這樣就實現了讓Apache依賴mod_proxy模塊實現發現代理,接下來將演示讓Apache依賴mod_jk模塊實現反向代理

mod_jk是ASF的一個項目,是一個工做於apache端基於AJP協議與Tomcat通訊的鏈接器,它是apache的一個模塊,是AJP協議的客戶端(服務端是Tomcat的AJP鏈接器)。

http://tomcat.apache.org/download-connectors.cgi 

[root@node2 tool]# tar -xf tomcat-connectors-1.2.42-src.tar.gz 

[root@node2 tool]# cd tomcat-connectors-1.2.42-src/native/

[root@node2 native]# ./configure --with-apxs=/usr/local/apache/bin/apxs 

[root@node2 native]# make &&make install


[root@node2 native]# vim /etc/httpd/httpd.conf 

#include /etc/httpd/extra/httpd-proxy.conf #註釋掉剛纔配置mod_proxy進行代理的配置文件

include /etc/httpd/extra/httpd-jk.conf #新加入用mod_jk模塊進行代理的配置文件


[root@node2 native]# vim /etc/httpd/extra/httpd-jk.conf

LoadModule  jk_module  modules/mod_jk.so

啓用jk_module模塊

JkWorkersFile  /etc/httpd/extra/workers.properties

jk主要使用一些worker進程和後端的tomcat通行,因此在這個文件中定義worker的一些屬性

JkLogFile  logs/mod_jk.log

JkLogLevel  debug

以上兩行與日誌有關

JkMount  /*  TomcatB

全部發往/*下的請求都轉發給TomcatB這個worker,此處的TomcatB是node5(192.168.139.9)上tomcat的核心配置文件server.xml中定義的JvmRoute(Jvm路由標籤即Jvm實例的名稱)

JkMount  /status/  stat1

全部發往/status/路徑的請求都轉發給stat1這個worker,其中stat1爲Apache的jk模塊自帶的一個實例,是讓jk專門用來輸出狀態信息的一個自帶的worker


[root@node2 apache]# vim /etc/httpd/extra/workers.properties


worker.list=TomcatB,stat1

兩個worker的名稱,分別爲TomcatB、stat1

worker.TomcatB.port=8009

jk模塊進行代理用的是ajp鏈接器(ajp協議),其後端Tomcat監聽的端口爲8009

注:後端8009,前端只有httpd的80端口,後端還有http的8080端口

worker.TomcatB.host=192.168.139.9

後端tomcat的ip

worker.TomcatB.type=ajp13

ajp13協議(ajp的1.3版本)

worker.TomcatB.lbfactor=1

定義的權重爲1,主要在負載均衡後端server時定義

worker.stat1.type = status


此處根據需求能夠定義的所有參數以下:

ajp13:此類型表示當前worker爲一個運行着的Tomcat實例,其協議爲ajp1.3。


lb:lb即load balancing,專用於負載均衡場景中的woker;此worker並不真正負責處理用戶請求,而是將用戶請求調度給其它類型爲ajp13的worker。


status:用戶顯示分佈式環境中各實際worker工做狀態的特殊worker,它不處理任何請求,也不關聯到任何實際工做的worker實例。具體示例如請參見後文中的配置。


worker其它常見的屬性說明:

host:Tomcat 的worker實例所在的主機;

port:Tomcat 實例上AJP1.3鏈接器的端口;

connection_pool_minsize:最少要保存在鏈接池中的鏈接的個數;默認爲pool_size/2;

connection_pool_timeout:鏈接池中鏈接的超時時長;

mount:由當前worker提供的context路徑,若是有多個則使用空格格開;此屬性能夠由JkMount指令替代;


retries:錯誤發生時的重試次數;

socket_timeout:mod_jk等待worker響應的時長,默認爲0,即無限等待;

socket_keepalive:是否啓用keep alive的功能,1表示啓用,0表示禁用;

lbfactor:worker的權重,能夠在負載均衡的應用場景中爲worker定義此屬性;


負載均衡模式中,專用的屬性還有:

balance_workers:用於負載均衡模式中的各worker的名稱列表,須要注意的是,出如今此處的worker名稱必定不能在任何worker.list屬性列表中定義過,而且worker.list屬性中定義的worker名字必須包含負載均衡worker。具體示例請參見後文中的定義。

method:能夠設定爲R、T或B;默認爲R,即根據請求的個數進行調度;T表示根據已經發送給worker的實際流量大小進行調度;B表示根據實際負載狀況進行調度。

sticky_session:在將某請求調度至某worker後,源於此址的全部後續請求都將直接調度至此worker,實現將用戶session與某worker綁定。默認爲值爲1,即啓用此功能。若是後端的各worker之間支持session複製,則能夠將此屬性值設爲0。




配置好後重啓測試

[root@node2 apache]# service httpd restart


wKioL1hrcePRgmlHAAAp03RJ-K8120.png


基於mod_proxy模塊實現負載均衡


[root@node2 apache]# vim /etc/httpd/httpd.conf 

include /etc/httpd/extra/httpd-proxy.conf

#include /etc/httpd/extra/httpd-jk.conf


[root@node2 apache]# vim /etc/httpd/extra/httpd-proxy.conf 


ProxyRequests Off #關閉正向代理

<proxy balancer://lbcluster1>

  BalancerMember ajp://192.168.139.8:8009 loadfactor=1 route=TomcatA

 #注意爲ajp協議代理

  BalancerMember ajp://192.168.139.9:8009 loadfactor=1 route=TomcatB

  ProxySet lbmethod=byrequests

 #輪調的調度算法

</proxy>


<VirtualHost *:80>

ServerAdmin admin@zxl.com

ServerName node2.zxl.com

ProxyVia On

ProxyPass / balancer://lbcluster1/ #必定要注意先後uri一致

ProxyPa***everse / balancer://lbcluster1/

 <proxy *>

  Require all granted

 </proxy>

 <Location />

 Require all granted

 </Location>

</VirtualHost>


[root@node2 apache]# service httpd configtest

AH00526: Syntax error on line 5 of /etc/httpd/extra/httpd-proxy.conf:

ProxySet: unknown lbmethod lbmethod=byrequests; balancer://lbcluster1

[root@node2 apache]# vim /etc/httpd/httpd.conf 

啓用如下模塊

LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so

LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so

LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so

LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so


[root@node2 apache]# service httpd restart

Stopping httpd:                                        [  OK  ]

Starting httpd:                                        [  OK  ]


瀏覽器測試

wKioL1hrtvnSQ0TCAAAtbG_vsHY888.png

刷新

wKiom1hrtw6DYXiIAAAs5WSVfTs930.png

基於mod_jk模塊實現負載均衡

[root@node2 apache]# vim /etc/httpd/httpd.conf

#include /etc/httpd/extra/httpd-proxy.conf

include /etc/httpd/extra/httpd-jk.conf


[root@node2 apache]# vim /etc/httpd/extra/httpd-jk.conf 


LoadModule  jk_module  modules/mod_jk.so

JkWorkersFile  /etc/httpd/extra/workers.properties

JkLogFile  logs/mod_jk.log

JkLogLevel  debug

JkMount  /*  lbcluster1

JkMount  /status/  stat1


[root@node2 apache]# vim /etc/httpd/extra/workers.properties 


worker.list = lbcluster1,stat1

worker.TomcatA.type = ajp13

worker.TomcatA.host = 192.168.139.8

worker.TomcatA.port = 8009

worker.TomcatA.lbfactor = 5

worker.TomcatB.type = ajp13

worker.TomcatB.host = 192.168.139.9

worker.TomcatB.port = 8009

worker.TomcatB.lbfactor = 5

worker.lbcluster1.type = lb

worker.lbcluster1.sticky_session = 0

worker.lbcluster1.balance_workers = TomcatA, TomcatB

[root@node2 apache]# service httpd restart


瀏覽器測試

wKiom1hrwhCiITilAAAt1hf9gM4869.png

刷新

wKiom1hrwiXwVo00AAArCA_BPJ4601.png



基於mod_jk模塊實現session的會話綁定


[root@node2 apache]# vim /etc/httpd/extra/workers.properties 

worker.lbcluster1.sticky_session = 1

[root@node2 apache]# service httpd restart

則無論如何刷新,請求始終定向到同一個後端tomcat,且session信息始終不變

wKioL1hrwtmAQzHxAAAo8tqJLYA768.png

換個瀏覽器不斷刷新也同樣

wKiom1hrwxKz6NenAAAtnAkmmWA098.png

這樣就實現了session信息的綁定



基於虛擬主機的反向代理,且實現狀態信息的輸出

[root@node2 ~]# vim /etc/httpd/httpd.conf 

include /etc/httpd/extra/httpd-proxy.conf

#include /etc/httpd/extra/httpd-jk.conf


[root@node2 ~]# vim /etc/httpd/extra/httpd-proxy.conf 

[root@node2 ~]# vim /etc/httpd/extra/httpd-proxy.conf 

ProxyRequests Off

<proxy balancer://lbcluster1>

  BalancerMember ajp://192.168.139.8:8009 loadfactor=1 route=TomcatA

  BalancerMember ajp://192.168.139.9:8009 loadfactor=1 route=TomcatB

  ProxySet lbmethod=byrequests

</proxy>


<VirtualHost *:80>

 ServerName node2.zxl.com

 <Location /balancer-manager>

  SetHandler balancer-manager

  Require all granted

 </Location>

</VirtualHost>


<VirtualHost *:80>

 ServerAdmin admin@zxl.com

 ServerName node2.zxl.com

 ProxyVia On

 ProxyPass / balancer://lbcluster1/

 ProxyPa***everse / balancer://lbcluster1/

 <proxy *>

  Require all granted

 </proxy>

 <Location />

  Require all granted

 </Location>

</VirtualHost>

[root@node2 ~]# service httpd restart

wKiom1hsh4eRpdQbAACyvQsRIsI229.png


可是這樣這前面定義一個balancer-manager虛擬機後就不能經過訪問http://192.168.139.4來實現負載均衡,以下圖


wKioL1hsiDiw87cAAAAtzJEn1Z8880.png


能夠這樣定義

[root@node2 ~]# vim /etc/httpd/extra/httpd-proxy.conf 

ProxyRequests Off

<proxy balancer://lbcluster1>

  BalancerMember ajp://192.168.139.8:8009 loadfactor=1 route=TomcatA

  BalancerMember ajp://192.168.139.9:8009 loadfactor=1 route=TomcatB

  ProxySet lbmethod=byrequests

</proxy>



<VirtualHost *:80>

 ServerAdmin admin@zxl.com

 ServerName node2.zxl.com

 ProxyVia On

 ProxyPass / balancer://lbcluster1/

 ProxyPa***everse / balancer://lbcluster1/

 <Location /balancer-manager>

  Sethandler balancer-manager

  Proxypass ! #表示對/balancer-manager請求不進行轉發(狀態信息是由代理server輸出的,!表示           #不作代理)

  Require all granted

 </Location>

 <proxy *>

  Require all granted

 </proxy>

 <Location />

  Require all granted

 </Location>

</VirtualHost>

[root@node2 ~]# service httpd restart

這樣既能經過http://192.168.139.4/balancer-manager/輸出狀態信息

wKiom1hsiTfiRoUcAACfxARwGeU763.png

也能經過訪問htp://192.168.139.4/實現負載均衡

wKioL1hsiTjDgFh7AAAog_b56Dc812.png

wKiom1hsiTjyKr4zAAAp5Q8Hu2E984.png




Tomcat的內部有一個叫作cluster的組件,在這個組件內部有許多的會話管理器


1.標準會話管理器(StandardManager):


<Manager className="org.apache.catalina.session.StandardManager"

         maxInactiveInterval="7200"/>

注:org.apache爲反寫的域名、catalina爲項目名、session爲項目對應的功能名、standmanager爲具體的實現這名稱(會話管理器名稱)、maxInactiveInterval="7200"則表示持久鏈接時間爲7200s,即一個用戶兩個小時後再來訪問纔會被識別爲新用戶


默認保存於$CATALINA_HOME/work/Catalina/<hostname>/<webapp-name>/下的SESSIONS.ser文件中。


maxActiveSessions:最多容許的活動會話數量,默認爲-1,表示不限制; 

maxInactiveInterval:非活動的會話超時時長,默認爲60s;

pathname:會話文件的保存目錄;


使用標準會話管理器後Tomcat就算關閉再重啓session信息也不會丟失,由於標準會話管理器會沒個一段時間將內存中的session同步到磁盤文件上進行保存;但有個弊端就是不能實現和其餘節點進行session共享,一旦當前節點掛了,則用戶的session信息也就丟了


2.持久會話管理器(PersistentManager):

將會話數據保存至持久存儲中,而且能在服務器意外停止後從新啓動時從新加載這些會話信息。持久會話管理器支持將會話保存至文件存儲(FileStore)或JDBC存儲(基於jdbc進行鏈接的關係型數據庫中)。由於是直接將用戶信息保存在磁盤上,因此不會出現標準會話管理器若是server忽然掛了,形成session沒來的即從內存寫入磁盤這種狀況,但一樣沒法實現session在隔節點共享


保存至文件中的示例:

<Manager className="org.apache.catalina.session.PersistentManager"

  saveOnRestart="true">

  <Store className="org.apache.catalina.session.FileStore"

    directory="/data/tomcat-sessions"/>

</Manager>


每一個用戶的會話會被保存至directory指定的目錄中的文件中,文件名爲<session id>.session,並經過後臺線程每隔一段時間(checkInterval參數定義,默認爲60秒)檢查一次超時會話。



保存至JDBCStore中的示例:

<Manager className="org.apache.catalina.session.PersistentManager"

  saveOnRestart="true">

  <Store className="org.apache.catalina.session.JDBCStore"

    driverName="com.mysql.jdbc.Driver"

    connectionURL="jdbc:mysql://localhost:3306/mydb?user=jb;password=pw"/>

</Manager>


3.Deltamanager會話管理器,它能夠將各個節點建成相似HA的集羣。各節點之間能夠傳遞心跳信息,且任何用戶經過前端代理鏈接到後端節點後,其會話信息會被同步複製到每個節點,這樣即便當前節點掛了,用戶請求下次被代理到其餘接點,其session信息任然存在;但這種爲每個節點都進行會話信息的同步會佔用大量的帶寬,容易消耗過多流量


4.BackUp會話管理器,與DeltaManager不一樣的是其session信息只同步到相應的備份節點上(相似於HA中的故障轉移域),而不會爲每一個節點都同步,且不一樣的節點能夠相互進行備份,這樣既實現了session共享也避免了佔用過多的網絡流量


下面將演示基於DeltaManager會話管理器實現各節點的session共享集羣


注:全部啓用集羣功能的web應用程序,其web.xml中都須添加<distributable/>才能實現集羣功能。若是某web應用程序沒有本身的web.xml,也能夠經過複製默認的web.xml至其WEB-INF目錄中實現。

[root@node4 webapps]# mkdir WEB-INF

[root@node4 webapps]# cp /usr/local/tomcat/conf/web.xml WEB-INF/

[root@node4 webapps]# vim WEB-INF/

加入

<distributable/>

[root@node4 webapps]#scp WEB-INF/ node5:/web/webapps/



定義cluster(集羣)及定義如何發送本身的心跳信息、如何接受別的節點的心跳信息、監聽的端口、地址、經過那個組播進行信息傳輸、等待對放的超時時間等等;說白了就是tomcat須要你本身定義了底層的通訊信道即如何進行各節點的信息、心跳等傳輸(而之前用的corosync、heartbeat等不用本身定義怎麼進行信息傳輸)


[root@node4 ~]# vim /usr/local/tomcat/conf/server.xml 

  在Engine下面加入如下內容

<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.50.10.1"   bind="192.168.139.8"   port="45564"


                 frequency="500"  dropTime="3000"/>


        <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"


              address="192.168.139.8"   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.apaalina.tribes.group.interceptors.TcpFailureDetector"/>



<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>


     </Channel>



  <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"


                   filter=".*\.gif;.*\.js;.*\.jpg;.*\.htm;.*\.html;.*\.txt;"/>


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



[root@node4 ~]# catalina.sh stop

[root@node4 ~]# catalina.sh configtest

[root@node4 ~]# catalina.sh start


[root@node5 ~]# vim /usr/local/tomcat/conf/server.xml 

一樣加入上面的內容,但要將ip改成192.168.139.9

[root@node5 ~]# catalina.sh stop

[root@node5 ~]# catalina.sh configtest

[root@node5 ~]# catalina.sh start

 

wKiom1hsrXbTCTAtAACWxxXzZgM859.png

刷新後能夠看到從新代理到TomcatB節點但session沒有改變

wKiom1hsrXfzYLmeAACThgCumsA349.png


這樣就實現了負載均衡和session共享(基於DeltaManager會話管理器)

注:雖說BackManager會話管理器設計的更好,但因爲Tomcat集羣通常節點不會不少,因此session信息的傳遞對帶寬的影響仍是比較小的


其實也能夠用Nginx的upstream定義一個集羣實現反向代理Tomcat,但Nginx反向代理只能基於http協議進行通訊和請求的轉發;而Apache能夠實現基於http/ajp進行通訊,且在使用ajp協議時,能夠關閉後端Tomcat的http鏈接器,讓其只能以ajp協議收到前端Apache轉發用戶的JSP請求,這樣就能夠保證後端Tomcat服務器的安全


下面是Nginx反向代理Tomcat集羣的演示

[root@node2 ~]# service httpd stop

Stopping httpd:                                            [  OK  ]

[root@node2 nginx]# vim /etc/nginx/nginx.conf

upstream Tomcat_Cluster {

            server 192.168.139.8:8080;

            server 192.168.139.9:8080;

            }



 location / {

            root   html;

            index  index.html index.htm;

            proxy_pass http://Tomcat_Cluster;

        }


[root@node2 ~]# service nginx start


wKioL1hst6LyZAGAAAAssnlKAaM079.png

刷新

wKiom1hst6OTWYXuAAAqedpBuzY440.png


本次實驗結束!

相關文章
相關標籤/搜索