Apache + Tomcat +mod_jk- win7與linux下實現負載均衡與集羣-

本文作者:陳超允chenchaoyun0

寫在前面的知識:

1、關於mod_jk

mod_jk簡稱JK,是Apache服務器的一個可插入模塊,用於爲Apache服務器提供處理JSP/SERVLET的能力。Apache作爲一個很強大的Web服

務器,本身缺乏處理JSP/SERVLET的能力,爲了能夠處理對JSP/SERVLET的請求,必須使用JSP/SERVLET容器,如Tomcat等。Tomcat本身

也可以作爲Web服務器使用,但是他的能夠遠不及Apache強大,所以Tomcat往往作爲JSP/SERVLET等容器的使用。mod_jk實質上是Apache與

Tomcat的連接器,並附帶提供了集羣和負載均衡的功能。

2、apache安裝包中的“no ssl”和“openssl”是什麼意思?

openSSL是表示帶有OpenSSL模塊,利用OpenSSL就可以給Apache配置SSL安全鏈接的,也就是使用https://方式進行訪問;no ssl則表示不帶

OpenSSL模塊,無法用於SSL安全鏈接。Tomcat中的集羣原理是通過組播的方式進行節點的查找並使用TCP連接進行會話的複製。實現效果:

用Apache分發請求到tomcat中對應的項目

操作環境:

操作系統:win7、虛擬機ubuntu15.04

jdk:1.7

Apache:2.2.22-下載地址:http://httpd.apache.org/download.cgi

Tomcat:7.0.67-選擇自己的版本即可,我在本機上模擬展示3個節點

Mod_jk:1.2.40-這個很重要,一定要選擇對自己的版本,不然apache啓動不了。下載地

址:http://mirror.bjtu.edu.cn/apache/tomcat/tomcat-connectors/jk/binaries/windows/




安裝步驟:

1、安裝JDK,這不用說了吧,必須的。

2、安裝Apache,使用默認配置,並且在安裝路徑中不要空格。我的是D:\Apache2.2

3、解壓Tomcat-分別命名:tomcat-node1、tomcat-node2、tomcat-ubuntu(這是在虛擬上的一個tomcat,沒有的話兩個就可以了,我是放在D盤)

4、拷貝下載的mod_jk.so到Apache安裝目錄下的modules文件夾下。


配置步驟:

1、修改Apache配置文件httpd.conf(我的路徑是:C:\Apache2.2\conf\httpd.conf),在最後一行默認添加:

include "C:\Apache2.2\conf\mod_jk.conf"


2、在httpd.conf同目錄新建mod_jk.conf,並添加以下內容:

#加載mod_jk Module 
LoadModule jk_module modules/mod_jk-1.2.31-httpd-2.2.3.so<span style="font-family: Arial, Helvetica, sans-serif;">#指定 workers.properties文件路徑</span>
JkWorkersFile conf/workers.properties
#指定哪些請求交給tomcat處理,"controller"爲在workers.propertise裏指定的負載分配控制器名
JkMount /* controller




3、在httpd.conf同目錄新建workers.properties

#這裏可以配置任意多個Tomcat,此處配置了2個Tomat服務器.
#host和port根據自己實際配置.實例配置的是本機兩個tomcat,分別使用不同的端口.避免衝突
#如果Tomcat不再同一機器上,沒必要改端口的。




#server 列表
worker.list=controller,tomcat1,tomcat2,tomcat3,tomcat4




#========tomcat1========


worker.tomcat1.port=8888       #ajp13 端口號,在tomcat下server.xml配置,默認8009
worker.tomcat1.host=localhost        #tomcat的主機地址,如不爲本機,請填寫ip地址
worker.tomcat1.type=ajp13
worker.tomcat1.lbfactor=1        #server的加權比重,值越高,分得的請求越多


#========tomcat2========


worker.tomcat2.port=9999        #ajp13 端口號,在tomcat下server.xml配置,默認8009
worker.tomcat2.host=localhost        #tomcat的主機地址,如不爲本機,請填寫ip地址
worker.tomcat2.type=ajp13
worker.tomcat2.lbfactor=1        #server的加權比重,值越高,分得的請求越多 


#========tomcat3========


#worker.tomcat3.port=7777   #ajp13 端口號,在tomcat下server.xml配置,默認8009
#worker.tomcat3.host=192.168.0.45  #tomcat的主機地址,如不爲本機,請填寫ip地址
#worker.tomcat3.type=ajp13#這是在局域網下另一臺機器的配置
#worker.tomcat3.lbfactor=1       #server的加權比重,值越高,分得的請求越多 


#========tomcat4========


worker.tomcat4.port=8787   #ajp13 端口號,在tomcat下server.xml配置,默認8009
worker.tomcat4.host=192.168.0.124   #tomcat的主機地址,如不爲本機,請填寫ip地址
worker.tomcat4.type=ajp13#這是在ubuntu下的配置

worker.tomcat4.lbfactor=1#server的加權比重,值越高,分得的請求越多 

#========controller,負載均衡控制器========
worker.controller.type=lb




#指定此負載平衡器負責的Tomcat應用節點。


worker.controller.balanced_workers=tomcat1,tomcat2,tomcat3,tomcat4#指定分擔請求的tomcat


#此處指定集羣是否需要會話複製,如果設爲true,則表明爲會話粘性,不進行會話複製,當某用戶的請求第一次分發到哪臺
#Tomcat後,後繼的請求會一直分發到此Tomcat服務器上處理;如果設爲false,則表明需求會話複製。


#worker.controller.sticky_session=false    #設爲false,則表明需求會話複製。


worker.controller.sticky_session=0    #
worker.controller.sticky_session_force=1  #這裏session黏性與session複製






Tomcat配置:

說明:如果修改了tomcat配置文件,最好將文件編碼轉換成UTF-8,我這裏兩個在win7下,還有一個在虛擬機裏的ubuntu下

因爲實例中我們定義了兩個tomcat處理分發,所以我們將tomcat的解壓版本格式複製一份。Tomcat6和tomcat7的配置方式一樣,下面是兩個沒修改前一樣的tomcat。

以tomcat_node1爲例:

1、修改分發tomcat對應的service.xml文件,保證Apache對應的workers.properties中的AJP13的connector的port。

<!--定義一個AJP 1.3 連接端口爲888 ,默認值爲8009,這裏我們改成我們自己定義的9988端口 -->
<Connector port="8888" protocol="AJP/1.3" redirectPort="8443" />


2、增加jvmRoute的值,保證同worders.properties裏面的配置一致。

<!--增加jvmRoute,值爲在Apache中配置的list集羣結點中的值,這裏定義爲tomcat1結點-->
<Engine name="Catalina"defaultHost="localhost"jvmRoute="tomcat1">


3、去掉默認註釋掉的集羣配置

<!--取消集羣結點相關的註釋,該句默認值註釋掉的,我們需要配置集羣所以去掉註釋,讓其起作用-->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>


如果我們的tomcat節點分佈在不同機器上,那麼我們的集羣至此已經配置完成。去掉多餘註釋,顯示做了修改的部位。修改前的tomcat-node1:

<!--Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<!--You should set jvmRoute to support load-balancing via AJP ie :<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">-->
<Engine name="Catalina" defaultHost="localhost">
<!--For clustering-->
<!--   <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>-->

修改後的tomcat-node1

<!--定義一個AJP 1.3 連接端口爲9988 ,默認值爲8009,這裏我們改成我們自己定義的9988端口 -->
<Connector port="8888" protocol="AJP/1.3" redirectPort="8443" />
<!--增加jvmRoute,值爲在Apache中配置的list集羣結點中的值,這裏定義爲tomcat1結點-->
 <Engine name="Catalina" defaultHost="localhost"  jvmRoute="tomcat1">
<!--取消集羣結點相關的註釋,該句默認值註釋掉的,我們需要配置集羣所以去掉註釋,讓其起作用-->  
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>


修改後的tomcat-node2

<!--Define an AJP 1.3 Connector on port 8009 -->
<Connector port="9999" protocol="AJP/1.3" redirectPort="8443" />
<!--You should set jvmRoute to support load-balancing via AJP ie :
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">-->
<Engine name="Catalina" defaultHost="localhost"  jvmRoute="tomcat2">
<!--For clustering-->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>



修改後的tomcat-ubuntu

說明:這裏的protocol=”AJP/1.3”,連接以及jvmRoute需要保證同我們Apache服務器中配置的works.properties一致。修改完後最好將service.xml文件的編碼方式設置爲utf-8。否則可能tomcat啓動報錯。

4、實例中我們的兩個tomcat節點在同一臺機器上,所以我們還需要保證protocol=”HTTP/1.1”的端口不一致,不然本地的兩個tomcat會起衝突。

下面是本實例中解決同一臺機器上多個tomcat服務器之間端口衝突做的修改:

圖片參考至 http://www.tuicool.com/articles/feABvu

Tomcat-node2做的修改

<pre name="code" class="html"><Server port="9995" shutdown="SHUTDOWN">
<!--…略…-->
<Connector port="9990" 
protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<!--…略…-->

說明:這裏的protocol=”HTTP/1.1”配置相關端口之間不能衝突,而且也不能同本機其他應用程序佔用的端口衝突,否則可能

報錯。

測試:

1、需要注意的是,項目的實體類需要實現serializable接口,

(1)當你想把的內存中的對象狀態保存到一個文件中或者數據庫中時候;
(2)當你想用套接字在網絡上傳送對象的時候; java對象序列化不僅保留一個對象的數據,而且遞歸保存對象引用的每個對            象的數據。可以將整個對象層次寫入字節流中,可以保存在文件中或在網絡連接上傳遞。利用對象序列化可以進行對象            的"深複製",即複製對象本身及引用的對象本身。序列化一個對象可能得到整個對象序列。
(3)當你想通過RMI傳輸對象的時候; RMI要利用對象序列化運行遠程主機上的服務,就像在本地機上運行對象時一樣。在            創建的WEB工程的web.xml文件中增加

<distributable/>

2、修改工程中index.jsp頁面的代碼,修改的結果如下:

<%@ page contentType="text/html; charset=gbk"%>
<%@ page import="java.util.*"%>
<html>
<head>
<title>Cluster App Test</title>
</head>
<body>
	Server Info:
	<%
	out.println(request.getLocalAddr() + " : " + request.getLocalPort()
			+ "<br>");
	%>
	<%
		out.println("<br> ID " + session.getId() + "<br>");
		// 如果有新的 Session 屬性設置
		String dataName = request.getParameter("dataName");
		if (dataName != null && dataName.length() > 0) {
			String dataValue = request.getParameter("dataValue");
			session.setAttribute(dataName, dataValue);
		}
		out.println("<b>Session 列表</b><br>");
		System.out.println("============================");
		Enumeration e = session.getAttributeNames();
		while (e.hasMoreElements()) {
			String name = (String) e.nextElement();
			String value = session.getAttribute(name).toString();
			out.println(name + " = " + value + "<br>");
			System.out.println(name + " = " + value);
		}
	%>
	
</body></html>




3、測試負載均衡與session分發

將項目部署到每個集羣節點中,即實例中的tomcat_node1和tomcat_node2,依次啓動Apache,和Tomcat服務器,兩個Tomcat服務器的啓動順序隨意。這裏Apache的端口使用安裝的時候選擇的8080.


這是tomcat1的


這是tomcat2的



這是在ubuntu裏的



相信都能看出來,這兩個sesssion斌不一樣。

下面說說session的複製問題


關於session的複製討論

sticky_session           sticky_session_force           結論

0                                   0                                            session無黏性,session會複製

0                                   1                                            session無黏性,session會複製

1                                   0                                            session有粘性(非強制)session會複製

1                                   1                                            session有粘性(強制)session沒必要再複製(此處有爭議,待深入研究

常見問題:

1、  如果同一臺機器上的節點之間session能夠同步,但是不同機器間的session無法同步,可能的原因是機器間的時鐘不同步,需要進行同步操作。

2、  關於Cluster
此實驗中對Cluster的配置如下:
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
其實這只是對Cluster的最簡單的一種配置,該配置下tomcat使用的是all-to-all方式的session同步,這種方式只適用於小規模的集羣。文章開頭列舉了三種session同步策略,all-to-all屬於第二種,tomcat也支持第三種,只需爲Cluster配置BackupManager即可

3、  關於jvmRoute
前面實驗中的sessionid由兩部分組成(前綴+後綴),而其後綴名就是jvmRoute配置的名稱,mod_jk需要根據這個後綴名進行請求轉發:當sticky_session=1時,mod_jk根據這個後綴名來判斷該會話應該始終由哪個tomcat進行處理。

總結:


worker.controller.sticky_session=false,提交頁面,將按照負載均衡的規則切換服務器,實現“完全的負載均衡”,代價是
Tomcat不停交換session數據,慢;
worker.controller.sticky_session=true,提交頁面將仍使用同一服務器(session建立在哪就用哪臺),不能保證完完全全的負
載均衡,但相對能省頻繁切換服務器的代價。可能會變上面的快一些。
worker.controller.sticky_session_force=true,始終轉發到session創建的服務器上。

我一直很糾結這個,如果說sticky_session=true的話,一個瀏覽器的請求就都是由一個tomcat去處理。=false的話,就按照負

載均衡去處理但是這個就得tomcat間一直來回複製會話了,性能上也有損失吧。我覺得session不復制是不是應該好一些,不

然如果很多用戶登錄了,session就得在多個tomcat間來回複製了。sticky_session=true的話,不進行session複製,按照用戶

瀏覽器去實現負載均衡,這樣應該好一點~~~其實好像就是,一個是按照請求去負載均衡,就必須得來回複製會話;另一個是

按照用戶瀏覽器去實現的負載均衡,那就不需要了。應該是後者,一開始理解錯了 ,現在改成1,0測試。




但結果並非那麼樂觀,還是一樣,可能是因爲不同的機子而session不一樣。日後找到解決的辦法再來補充

參考文檔:http://www.tuicool.com/articles/feABvu 、http://blog.csdn.net/lubiaopan/article/details/8936443




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章