本文作者:陳超允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的
關於session的複製討論
這是在ubuntu裏的
相信都能看出來,這兩個sesssion斌不一樣。
下面說說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