實戰Apache+Tomcat集羣和負載均衡html
目錄java
1. 什麼是J2EE集羣... 3web
1.1. 序言... 3apache
1.2. 基本術語... 3瀏覽器
伸縮性(Scalability):... 4tomcat
高可用性(High availability):... 4服務器
負載均衡(Load balancing):... 4網絡
容錯(Fault tolerance):... 5session
失效轉移(Failover):... 5架構
等冪方法(Idempotent methods):... 5
1.3. 什麼是J2EE集羣... 5
2. J2EE集羣給咱們帶來了什麼... 9
3. 實戰準備... 9
4. 首戰失敗... 9
5. 詳細配置... 9
6. 負載均衡... 9
7. 失敗轉移... 9
愈來愈多的關鍵應用運行在J2EE(Java 2, Enterprise Edition)中,這些諸如銀行系統和帳單處理系統須要高的可用性(High Availability, HA),同時像Google和Yahoo這種大系統須要大的伸縮性。高可用性和伸縮性在今天高速增加的互鏈接的世界的重要性已經證明了。eBay於1999年6月停機22小時的事故,中斷了約230萬的拍賣,使eBay的股票降低了9.2個百分點。
J2EE集羣是用來提供高可用性和伸縮性服務,同時支持容錯處理的一種流行的技術。可是,因爲J2EE規範缺少對集羣的支持,J2EE供應商實現集羣的方法也各異。這給J2EE架構師和開發人員帶來了不少困難。如下是幾個常見的問題:
l 爲何帶集羣功能的商業J2EE服務器產品如此昂貴?(10倍於不帶集羣功能的產品)
l 爲何基於單服務器環境構建的應用不能在集羣中運行?
l 爲何應用在集羣環境中運行得很慢,但在非集羣環境中卻快得多?
l 爲何集羣的應用移植到其餘服務器中失敗?
l 理解這些限制和要素的最佳方法是學習他們的實現方式。
在咱們討論不一樣的集羣實現以前,先談談幾個概念。這有助於理解不一樣的J2EE集羣產品不一樣的設計結果和概念:
在一些大的系統中,預測最終用戶的數量和行爲是很是困難的,伸縮性是指系統適應不斷增加的用戶數的能力。提升這種併發會話能力的一種最直觀的方式就增長資源(CPU,內存,硬盤等),集羣是解決這個問題的另外一種方式,它容許一組服務器組在一塊兒,像單個服務器同樣分擔處理一個繁重的任務。
單一服務器的解決方案並非一個健壯方式,由於容易出現單點失效。像銀行、帳單處理這樣一些關鍵的應用程序是不能容忍哪怕是幾分鐘的死機。它們須要這樣一些服務在任什麼時候間均可以訪問並在可預期的合理的時間週期內有響應。集羣方案經過在集羣中增長的冗餘的服務器,使得在其中一臺服務器失效後仍能提供服務,從而得到高的可用性。
負載均衡是集羣的一項關鍵技術,經過把請求分發給不一樣的服務器,從而得到高可用性和較好的性能。一個負載均衡器能夠是從一個簡單的Servlet或Plug-Ins(例如一個Linux box利用ipchains來實現),到昂貴的內置SSL加速器的硬件。除此以外,負載均衡器還需執行一些其餘的重要任務,如「會話膠粘」讓一個用戶會話始終存在一個服務器上,「健康檢查」用於防止將請求分發到已失效的服務器上。有些負載均衡器也會參與咱們下面將要談到「失效轉移」過程。
高可用性意味着對數據正確性的要求不那麼高。在J2EE集羣中,當一個服務器實例失效後,服務仍然是有效的,這是由於新的請求將被冗餘服務器處理。可是,當一個請求在一個正在失效的服務器中處理時,可能獲得不正確的結果。無論有多少個錯誤,容錯的服務應當能確保有嚴格的正確的行爲。
失效轉移是集羣中用來獲取容錯能力的另外一項關鍵的技術。當一個結點失效後,經過選擇集羣中的另外一個結點,處理將會繼續而不會終止。轉移到另外一個結點能夠被顯式的編碼,或是經過底層平臺自動地透明地路由到另外一個服務器。
等冪方法是指這樣一些方法:重複用相同的參數調用都能獲得相同的結果。這些方法不會影響系統狀態,能夠重複調用而不用擔憂改變系統。例如:getUsername()就是等冪的,而deleteFile就不是。當咱們討論HTTP Session失效轉移和EJB失效轉移時,它是一個重要的概念。
一個天真的問題,不是嗎?但我仍要用幾句話和圖來回答它。一般,J2EE集羣技術包括"負載均衡"和"失效轉移"。
如圖1所示,負載均衡意味着有許多客戶端向目標對象同時發出請求。負載均衡器在調用者和被調用者之間,分發請求到與原始對象相同的冗餘對象中。伸縮性和高可用性就是這樣獲得的。
如圖2所示,失效轉移與負載均衡不一樣。有時客戶端會連續發請求到目標對象,若是請求中間目標對象失效了,失效轉移系統將檢測到此次失敗,並將請求重定向到另外一個可用的對象。經過這種方式能夠得到容錯能力。
若是你想知道更多的有關J2EE集羣的知識,你就會問到一個基本的問題,「什麼對象能夠集羣?」和「在個人J2EE代碼中哪裏會發生負載均衡和失效轉移呢?」。這些都是用來理解J2EE集羣的很是好的問題。實際上,並非全部的對象都能被集羣的,而且負載均衡和失效轉移並非在J2EE代碼全部地方都能發生。看看下面的例子代碼:
在Class A的bussiness()方法中,instance1能夠負載均衡嗎?或是當其失效,能夠失效轉移到其餘B的實例上嗎?我想是不行的!對負載均衡和失效轉移來講,必需要有個攔截器在調用者和被調用者之間分發或重定向請求到不一樣的對象上。Class A和Class B的實例是運行在一個JVM中緊密耦合的,在方法調用間加入分發邏輯很是困難。
什麼類型對象能夠被集羣?——只有那些能夠被部署到分佈式拓樸結構中的組件。
在個人J2EE代碼中,什麼地方會有負載均衡和失效轉移?——只在你調用分佈式組件的方法時。
在如圖4所示的分佈式環境中,調用者和被調用者被分離在有明顯邊界的不一樣的運行容器中,這個邊界能夠是JVM,進程和機器。
當目標對象被客戶端調用時,目標對象的功能是在容器中運行的(這就是爲何咱們說它是分佈式的緣由)。客戶端和目標對象經過標準的網絡協議通訊。這些特性就爲一些機制提供了機會能夠介入到方法調用之間實現負載均衡和失效轉移。
如圖4,瀏覽器經過HTTP協議調用JSP對象,JSP運行在WEB服務器中,瀏覽器只須要返回結果而不關心它是怎麼運行的。在上述場景中,一些東西就能夠在瀏覽器與WEB服務器之間實現負載均衡和失效轉移的功能。在J2EE平臺,分佈式技術包括:JSP(Servlet),JDBC,EJB,JNDI,JMS,WEB Service等。負載均衡和失效轉移就發生在這些分佈式方法被調用時。在後續部分咱們將詳細討論這些技術。
apache 2.0.55 (由http://httpd.apache.org/進入下載)
Tomcat 5.5.25 (由http://tomcat.apache.org/進入下載)
在頁面 http://tomcat.apache.org/ Download 標題下找到 Tomcat Connectors 連接進入( 點擊下載mod_jk-apache-2.0.55.so),看起來像是個Unix/Linux下的動態庫,實際應是個Win32 的 DLL 動態庫,大概是爲保持不一樣平臺配置的一致性,才用了這個擴展名。
用Apache進行分流,把請求按照權重以及當時負荷分tomcat1,tomcat2...去處理
我把Apache安裝在F:\ZQ\apache2.0.55\Apache2
解壓兩分Tomcat, 分別在 F:\ZQ\apache-tomcat-5.5.1,F:\ZQ\apache-tomcat-5.5.2
在apache安裝目錄下conf目錄中找到http.conf,在文件最後加上下面一句話就能夠了
include conf/mod_jk.conf
#加載mod_jk Module
LoadModule jk_module modules/mod_jk-apache-2.0.55.so
#指定 workers.properties文件路徑
JkWorkersFile conf/workers.properties
#指定那些請求交給tomcat處理,"controller"爲在workers.propertise裏指定的負載分配控制器
JkMount /*.jsp controller
若是還要指定*.do也進行分流就再加一行
JkMount /*.do controller
若是你想對全部的請求進行分流只須要寫成
JkMount /* controller
內容以下(可能要去除 # 不在行首的註釋)
worker.list = controller,tomcat1,tomcat2 #server 列表
#========tomcat1========
worker.tomcat1.port=8009
#ajp13 端口號,在tomcat下server.xml配置,默認8009
worker.tomcat1.host=localhost
#tomcat的主機地址,如不爲本機,請填寫ip地址
worker.tomcat1.type=ajp13
worker.tomcat1.lbfactor = 1
#server的加權比重,值越高,分得的請求越多
#========tomcat2========
worker.tomcat2.port=8109
#ajp13 端口號,在tomcat下server.xml配置,默認8009
worker.tomcat2.host=localhost
#tomcat的主機地址,如不爲本機,請填寫ip地址
worker.tomcat2.type=ajp13
worker.tomcat2.lbfactor = 2
#server的加權比重,值越高,分得的請求越多
#========controller,負載均衡控制器========
worker.controller.type=lb
worker.controller.balanced_workers=tomcat1,tomcat2
#指定分擔請求的tomcat
worker.controller.sticky_session=1
若是你是水平集羣,即在不一樣電腦上安裝tomcat,tomcat的安裝數量爲一個,能夠沒必要修改tomcat配置文件.我這裏是在同一臺電腦上安裝兩個tomcat,實現的是垂直集羣方式,因此必須修改其中一個的設置,以免端口衝突,按照參考文章是把原來以9開頭的端口號改成以9開頭端口號,可是在我機器上若是以9開頭的端口號,例如9080、9082會與個人WebSphere Application Server配置衝突,因此我這裏採起的策略是把原來端口號的第三位改成1,如8080改成8180。
打開tomcat2/conf/server.xml文件
1) 將關閉Tomcat的監聽端口改爲由8005改成8105
即把
<Server port="8005" shutdown="SHUTDOWN">
改成
<Server port="8105" shutdown="SHUTDOWN">
2) 把http服務端口號由8080改成8180
找到
<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
<CONNECTOR port="8080"
把這裏的8080改成8180
3) 把AJP端口號由8009改成8109
找到
<!-- Define an AJP 1.3 Connector on port 8009 -->
<CONNECTOR port="8009"
把這裏的8009改成8109
4) 把 HTTP 代理端口從8082改成8182(這個配置默認是被註釋掉的,可跳過這一步)
找到
<CONNECTOR port="8082"
把這裏的8082改成8182
5) 編寫一個測試 jsp
創建一個目錄TestCluster,裏面新建一個test.jsp,內容爲
<% System.out.println("==========================="); %> |
把TestCluster放到tomcat1,tomcat2的webapps下
6) 啓動apache,tomcat1,tomcat2,進行測試
經過 http://localhost/TestCluster/test.jsp 訪問,多刷新幾回頁面,查看Tomcat1和Tomcat2的窗口,你將能夠看到打印了一行行"===========================",而且從統計上來講,大約在tomcat2打印的數量是在Tomcat1中的兩倍,能夠看到請求會被tomcat1,tomcat2按照不一樣的權重分流處理,實現了負載均衡。
做下面的集羣配置,請在workers.properties把tomcat1和tomcat2的權重改成同樣的,使請求較平均分配,將有便於看到實驗的效果。
只配置負載均衡還不行,還要session複製,也就是說其中任何一個tomcat的添加的session,是要同步複製到其它tomcat, 集羣內的tomcat都有相同的session
即對<Cluster>節點的在註釋符刪掉,並將tomcat2的4001端口改成4002,以免與tomcat衝突,固然,若是是兩臺電腦,是不用改端口的,去掉註釋符便可
即取消對以下處
<Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
managerClassName="org.apache.catalina.cluster.session.DeltaManager"
expireSessionsOnShutdown="false"
............
<ClusterListener className="org.apache.catalina.cluster.session.ClusterSessionListener"/>
</Cluster>
先後的註釋標記<!-- -->,啓用該項配置,實現服務器間的Session複製。
這裏的做用大概是爲了在集羣的TOMCAT裏面,生成全局HTTP會話標識,這樣能夠保證會話的惟一性,有利於session的複製
(先跳過這一步,有精力能夠試驗一下)
在 Tomcat1 和 Tomcat2 的 server.xml 文件,找到
<ENGINE name="Catalina" defaultHost="localhost">
分別改成
<ENGINE name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
和
<ENGINE name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">
然而實際我配置的時候還不能加jvmRoute屬性,配置了反而有問題。
刷新瀏覽器窗口老是在某一個tomcat控制檯輸出形如
SessionID:154678FA6D4D0ABD57658B750E7A3532.tomcat1 (在tomcat1窗口)
或者
SessionID:3800571A532AECEA7280F45361861AD4.tomcat2 (在tomcat2窗口)
由控制檯打印的結果能夠看出,SessionID在哪一個tomcat上產生,那麼後續該會話的請求將老是會這個tomcat來處理。
而且注意到SessionID的形式比一般狀況多了一個後綴.tomcat1或.tomcat2,還搞不清楚是爲何。
配置時請視實際狀況而取捨。
修改test.jsp,內容以下
<%@ page contentType="text/html; charset=GBK" %> <%@ page import="java.util.*" %> <html><head><title>Cluster App Test</title></head> <body> <% System.out.println("SessionID:" + session.getId()); %> Server Info: <% out.println(request.getServerName() + " : " + request.getServerPort()+"<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.print("<b>Session 列表</b><br>"); 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); } %> <form action="test.jsp" method="POST"> 名稱:<input type=text size=20 name="dataName"> <br> 數值:<input type=text size=20 name="dataValue"> <br> <input type=submit> </form> </body> </html> |
4. 配置Session複製
在TestCluster目錄下新建WEB-INF目錄,WEB-INF下新建web.xml,內容以下
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<display-name>TomcatClusterDemo</display-name>
<distributable/>
<web-app>
也就是在須要集羣的應用的web.xml中加上屬性,代表該應用可多應用分流處理,能進行Session的複製
把TestCluster複製到Tomcat一、Tomcat2的webapps目錄下,重啓apache,tomcat1,tomcat2
5. 測試Session的複製
經過 http://localhost/TestCluster/test.jsp 訪問,輸入名稱爲 name, 值爲 Unmi,提交查詢,多刷新幾回瀏覽器窗口,你將會看到在兩個Tomcat窗口都打印出相同的SessionID及其中的值,而且每次刷新後打印的結果都同樣的。
若是不爲應用的web.xml加上 ,一樣測試上面那個test.jsp頁面,每次刷新分流到不一樣的tomcat上都會產生不同的SessionID,在同一個tomcat上也是間隔出現不一樣的sessionID。
更切身的體驗是必定要本身動手配置一遍,並仔細觀察兩個tomcat的控制上的輸出。因本文是參考 輕鬆實現Apache,Tomcat集羣和負載均衡 的實踐經歷,
啓動環境後,啓動2個瀏覽器,獲得的是2個不一樣的session標識,各自提交您輸入的key-value後,把一個tomcat2服務關閉掉,再訪問頁面,發現tomcat2的session會複製到tomcat1中
用 WebSphere Application Server ND 版配置過垂直和水平集羣,可是本身試驗集羣環境下的應用卻不想搬弄這個龐然大物。眼下急於想體驗的就是 Quartz 如何適應集羣環境,問題的焦點就是:Quartz 定時任務隨 Web 應用啓動,而 Web 應用部署在集羣環境中,如何保證同一時刻只有一個同名的任務實例在跑。
因此會考慮用Apache+Tomcat配置一個輕量級的WEB應用集羣,通常進行HTTP分流都是使用Apache,包括WAS集羣也是,不多用IIS的。雖然單純的用Tomcat的balancer應用也能配置進行負載分流,但那個性能應該好不到哪兒去。
用Apache+Tomcat配置的Web應用集羣就是部署起來麻煩些,老是要保持雙份的應用拷貝,WAS集羣則不須要,不知道Jboss作WEB應用集羣是怎麼樣一種狀況。
好了,下面要進行該作的事情了,最後也但願能寫個工具能完成從下載到安裝配置,啓動,中止,重啓的全自動化,以及界面的人性化。
在準備軟件環境的環節中:最開始的時候小弟下載了Apache2.2.21,mod_jk下載的是2.2.X版本,沒有按照網上給出的版本,全部配置都弄好後,訪問頁面,老是提示404錯誤
後來換回2.0.55版本,此次實戰才成功了。
http://blog.csdn.net/kypfos/article/details/3081330
http://www.kuqin.com/java/20080418/6942.html