原文地址:http://www.cnblogs.com/leader_89/archive/2011/08/01/2109181.html
Tomcat負載均衡原理詳解及配置(Apache2.2.19+Tomcat7.0.12)
結構圖
使用Tomcat的童鞋們注意了。爲了增加tomcat的性能和穩定性,我們一般採用balance和session同步機制。 下圖列出了我們常用也是最簡單的解決方案。
說明
1 balance
- 負載均衡我們一般採用Apache proxy和Apache+mod_jk方式
- 所使用軟件:Apache2.2.19 http://httpd.apache.org/download.cgi#apache22;
Tomcat7 http://tomcat.apache.org/download-70.cgi
1.1 mod_proxy方式
mod_proxy是一種分工合作的的形式,通過主服務器跳轉到各臺主機負責不同的任務而實現任務分工,這種形式不能實現負載均衡,只能提供主服務器的訪問跳轉
修改apache的httpd.conf文件配置
打開httpd.conf文件,取消下面四行的註釋,用以打開代理所需的.so支持模塊。
打開文件conf\extra\httpd-vhosts.conf,可以看到如下代碼:
根據需要更改<VirtualHost>節點內的參數。
注:
編輯httpd.conf,找到DocumentRoot "C:/Program Files/Apache Software Foundation/Apache2.2/htdocs"這項,這是默認根目錄路徑,但是要更改的不是這個,一直往下找,找到<Directory />節點,然後在節點結束後加上:
這裏的"C:/Program Files/Apache Software Foundation/Apache2.2/docs/dummy-host.leader89"和"C:/Program Files/Apache Software Foundation/Apache2.2/docs/dummy-host2.leader89"爲前面VirtualHost裏的路徑。
保存httpd.conf和httpd-vhosts.conf,然後重啓Apache。
然 後訪問dummy-host.leader89打開的是C:/Program Files/Apache Software Foundation/Apache2.2/docs/dummy-host.leader89目錄,
訪問dummy-host2.leader89的是C:/Program Files/Apache Software Foundation/Apache2.2/docs/dummy-host2.leader89目錄,
實現了單IP多域名多站點的功能。
1.2 mod_proxy_blancer方式
mod_proxy_balancer是mod_proxy的擴展,提供負載平衡支持,通過mod_proxy_balancer.so包實現負載平衡,公司生產服務器暫時就採用這種方式。
修改apache的httpd.conf文件配置
打開httpd.conf文件,取消下面四行的註釋,用以打開代理所需的.so支持模塊。
1 #LoadModule proxy_http_module modules/mod_proxy_http.so
2 #LoadModule proxy_connect_module modules/mod_proxy_connect.so
3 #LoadModule proxy_module modules/mod_proxy.so
4 #LoadModule proxy_module modules/mod_proxy_blancer.so
在httpd.conf文件最後添加以下代碼:
將下載的tomcat壓縮包解壓兩份,分別命名爲tomcat1、tomcat2。修改tomcat2中conf/server.xml中部分端口號(因爲我在本機做測試,所以爲了解決端口號被佔用的問題修改tomcat2的端口號,使tomcat1與tomcat2能夠同時啓動,實現多服務器;如果有多臺PC服務器可不必修改),修改內容如下:
…………
<Server port="9005" shutdown="SHUTDOWN"> #此處修改爲9005,避免與tomcat1的8005衝突
…………
…………
<Connector port="8081" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" /> #此處修改爲8081,避免與tomcat1的8080衝突
…………
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="9009" protocol="AJP/1.3" redirectPort="8443" /> #此處修改爲9009,避免與tomcat1的8009衝突。如果使用的是mod_proxy_blancer方式此處可以註釋掉,如果使用的是mod_jk方式則此處必須存在
…………
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> #去掉該行註釋即可實現session複製功能
…………
1)輪詢均衡策略的配置
ProxyPass / balancer://proxy/
<Proxy balancer://proxy>
BalancerMember http://127.0.0.1:8080/
BalancerMember http://127.0.0.1:8081/
</Proxy>
實現負載均衡的原理如下:
假設Apache接收到http://localhost/test請求,由於該請求滿足ProxyPass條件(其URL前綴爲“/"),該請求會 被分發到後臺某一個BalancerMember,譬如,該請求可能會轉發到http://127.0.0.1:8080/進行處理?當第二 個滿足條件的URL請求過來時,該請求可能會被分發到另外一臺BalancerMember,譬如,可能會轉發到http://127.0.0.1:8081/如此循環反覆,便實現了負載均衡的機制?
2)按權重分配均衡策略的配置
ProxyPass / balancer://proxy/
<Proxy balancer://proxy>
BalancerMember http://127.0.0.1:8080/ loadfactor=3
BalancerMember http://127.0.0.1:8081/ loadfactor=1
</Proxy>
參數"loadfactor"表示後臺服務器負載到由Apache發送請求的權值,該值默認爲1,可以將該值設置爲1到100之間的任何值?以上面 的配置爲例,介紹如何實現按權重分配的負載均衡,現假設Apache收到http://myserver/test 4次這樣的請求,該請求分別被負載到後臺 服務器,則有3次連續的這樣請求被負載到BalancerMember爲http://127.0.0.1:8080/的服務器,有1次這樣的請求被 負載BalancerMember爲http://127.0.0.1:8081/後臺服務器?實現了按照權重連續分配的均衡策略?
3)權重請求響應負載均衡策略的配置
ProxyPass / balancer://proxy/ lbmethod=bytraffic
<Proxy balancer://proxy>
BalancerMember http://127.0.0.1:8080/ loadfactor=3
BalancerMember http://127.0.0.1:8081/ loadfactor=1
</Proxy>
參數“lbmethod=bytraffic"表示後臺服務器負載請求和響應的字節數,處理字節數的多少是以權值的方式來表示的? “loadfactor"表示後臺服務器處理負載請求和響應字節數的權值,該值默認爲1,可以將該值設置在1到100的任何值?根據以上配置是這麼進行均 衡負載的,假設Apache接收到http://myserver/test請求,將請求轉發給後臺服務器,如果BalancerMember爲http://127.0.0.1:8080/後臺服務器負載到這個請求,那麼它處理請求和響應的字節數是BalancerMember爲http://127.0.0.1:8081/服務器的3倍(回想(2)均衡配置,(2)是以請求數作爲權重負載均衡的,(3)是以流量爲權重負載均衡的,這是 最大的區別)?
至此配置以完成
在tomcat1中webapps文件夾下新建test項目文件夾,test目錄下新建如下頁面
<%@ 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);
}
%>
<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>
如需session複製功能此步驟爲必須操作
打開項目的WEB-INF下的web.xml在</web-app>內添加<distributable/>標籤,如果沒有則手動建立目錄結構
<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>TomcatDemo</display-name>
<distributable/> #一般均放在web-app結束節點上一行
</web-app>
將tomcat1下的test項目複製一份到tomcat2的webapps目錄下
至此所有操作已完成
啓動tomcat1、tomcat2、apache。打開瀏覽器,輸入http://localhost/test/test.jsp回車,刷新幾次即可從tomcat1與tomcat2的控制檯看到負載效果。輸入session即可看到session複製效果
1.3 mod_jk方案
mod_jk是比較專門針對Tomcat的方法,通過AJP協議連接Tomcat
1)需要下載mod_jk-1.2.31-httpd-2.2.3.so http://archive.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/win32/jk-1.2.31/mod_jk-1.2.31-httpd- 2.2.3.so包並放到Apache安裝目錄下的modules子目錄中
2)然後配置mod_jk.conf
3)配置workers2.properties
注意:因爲mod_jk2方式不被推薦,mod_jk2已經不再被更新了。因此,此處不予列舉,如有需要參考者請留言,將隨後貼出。
proxy、proxy_blancer和mod_jk的比較
- proxy的缺點是,當其中一臺tomcat停止運行的時候,apache仍然會轉發請求過去,導致502網關錯誤。但是隻要服務器再啓動就不存在這個問題。
- mod_jk方式的優點是,Apache 會自動檢測到停止掉的tomcat,然後不再發請求過去。
缺點就是,當停止掉的tomcat服務器再次啓動的時候,Apache檢測不到,仍然不會轉發請求過去。
- proxy和mod_jk的共同優點是.可以只將Apache置於公網,節省公網IP地址資源。
可以通過設置來實現Apache專門負責處理靜態網頁,讓Tomcat專門負責處理jsp和servlet等動態請求。
共同缺點是:如果前置Apache代理服務器停止運行,所有集羣服務將無法對外提供。 - proxy和mod_jk對靜態頁面請求的處理,都可以通設置來選取一個儘可能優化的效果。
mod_proxy_balancer和mod_jk都需要修改tomcat的配置文件配合
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1"> - 這三種Tomcat集羣方式對實現最佳負載均衡都有一定不足,mod_proxy_balancer和mod_jk相對好些,mod_jk的設置能力更強些。lbfactor參數來分配請求任務。
- apache自帶mod_proxy功能模塊中目前只可以實現兩種不同的負載均衡集羣實現方式,第一種是分工合作的的形式,通過各臺主機負責不同的任務而實 現任務分工。第二種是不同的機器在擔任同樣的任務,某臺機器出現故障主機可以自動檢測到將不會影響到客戶端,而第一種卻不能實現但第一種實現方式的優點在 於他是主服務器負擔相應沒第二種大因爲臺只是提供跳轉指路功能,形象的說他不給你帶路只是告訴你有條路可以到,但到了那是否可以看到你見的人他已經不會去管你了。相比之下第二種性能要比第一種會好很多;但他們都有個共同點都是一託N形式來完成任務的所以你的主機性能一定要好。
2 session同步
- 對於tomcat的集羣有兩種方式,這個主要是針對session而言的。一種就是sticky模式,即黏性會話模式;另外一種就是session複製模式了。
2.1 sticky模式
- 利用負載均衡器的sticky模式的方式把所有同一session的請求都發送到相同的Tomcat節點。這樣不同用戶的請求就被平均分配到集羣 中各個tomcat節點上,實現負載均衡的能力。這樣做的缺點是沒有災難恢復的能力。一旦一個節點發生故障,這個節點上所有的session信息全部丟 失;
- 這種方式其實是由前端balancer實現的,基本不需要webServer做任何改動(只需要修改jvmRoute="tomcat1")
- 同一用戶同一session只和一個webServer交互,一旦這個webserver發生故障,本次session將丟失,用戶不能繼續使用
2.2 複製模式
- 利用Tomcat session複製的機制使得所有session在所有Tomcat節點中保持一致。當一個節點修改一個session數據的時候,該節點會把這個 session的所有內容序列化,然後廣播給所有其它節點。這樣當下一個用戶請求被負載均衡器分配到另外一個節點的時候,那個節點上有完備的 session信息可以用來服務該請求。這種做法的問題是對session哪怕有一點點修改,也要把整個sessions數據全部序列化 (serialize),還要廣播給集羣中所有節點,不管該節點到底需不需要這個session。這樣很容易會造成大量的網絡通信,導致網絡阻塞。一般採 用這種方式,當Tomcat節點超過4個時候,整個集羣的吞吐量就不能再上升了;
- 此方式是通過tomcat本身提供的功能,只需要修改server.xml文件
(1)修改Engine節點信息: <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
(2)去掉<Cluster> <\Cluster> 的註釋符
(3)web.xml中增加 <distributable/>
2.3 Terracotta模式
- 另一種方式就是利用開源軟件Terracotta。Terracotta的基本原理是對於集羣間共享的數據,當在一個節點發生變化的時 候,Terracotta只把變化的部分發送給Terracotta服務器,然後由服務器把它轉發給真正需要這個數據的節點。這樣對網絡的壓力就非常小, 各個節點也不必浪費CPU時間和內存進行大量的序列化操作。把這種集羣間數據共享的機制應用在session同步上,相當於對tomcat第二種集羣實現 機制進行了優化,既避免了對數據庫的依賴,又能達到負載均衡和災難恢復的效果。在對比測試中,採用Terracotta搭建Tomcat集羣,節點達到8 個時候,整個集羣的吞吐量還一直是線性增長的。
2.4 三種模式比較
- sticky模式最大的缺點就是不支持failover,一旦某一個webServer發生故障則此節點上的session就會丟失,因此不建議使用。
- 複製模式可以保證個別節點發生故障不丟失session,但是複製時需要序列化數據這會影響到系統的性能。
另外性能隨着服務器增加急劇下降,而且容易引起廣播風暴。經測試當Tomcat節點超過4個時候,整個集羣的吞吐量就不能再上升了。
需要修改server.xml和web.xml文件 - 使用第三方軟件Terracotta進行session同步,配置對原來的web應用完全透明,原有程序不用做任何修改。。
數據不需要序列化,也不佔用webServer的內存,執行效率高。 - terracotta本身支持HA,增加了系統的穩定性。
- Terracotta是開源的,並且可以集成在很多主流的開源軟件中,如Jetty、Tomcat、Spring、Geronimo和EHCache等。