[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.
[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
[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測試以下:
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
這樣就實現了讓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
基於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 ]
瀏覽器測試
刷新
基於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
瀏覽器測試
刷新
基於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信息始終不變
換個瀏覽器不斷刷新也同樣
這樣就實現了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
可是這樣這前面定義一個balancer-manager虛擬機後就不能經過訪問http://192.168.139.4來實現負載均衡,以下圖
能夠這樣定義
[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/輸出狀態信息
也能經過訪問htp://192.168.139.4/實現負載均衡
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
刷新後能夠看到從新代理到TomcatB節點但session沒有改變
這樣就實現了負載均衡和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
刷新
本次實驗結束!