Apache_proxy負載均衡和Session複製

天上網查了查資料,之前使用apachejk模塊做負載均衡。後來覺得jk的負載配置有點死板,只能按照負載權重值來進行請求的分發,沒有做到比較智能的負載平衡,並且使用mod_jk訪問頁面發現確實比較慢。可能是jk路由到真正的Node Server上比較費時間吧。結合筆者提出的jk的缺點,今天使用mod_proxy來進行負載均衡和路由選擇。
之前提出了jk相關的缺點
1):負載均衡權重是在配置文件中寫死的。不能根據實際的運行時機器的環境來決定負載均衡的策略,顯得比較死板
2):雖然在apache中配置了session共享,但是實際上session並沒有在node上進行共享傳遞。如果一臺機器掛了,那麼這臺機器的客戶session也就消失了,容錯性比較差
筆者的環境如下:
OSWindows7
HttpServerApache Http Server2.2.17
Tomcatapache-tomcat-6.0.29
下面來看如何加載mod_proxy模塊
1. 加載相關apache的模塊
在配置文件httpd.conf中放開註釋
 
#加載mod_proxy
  1. LoadModule proxy_module modules/mod_proxy.so
  2. LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
  3. LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
  4. LoadModule proxy_connect_module modules/mod_proxy_connect.so
  5. LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
  6. LoadModule proxy_http_module modules/mod_proxy_http.so
因爲在apache2.2.x版本中自動會有這些模塊,所以直接打開註釋即可。
 
修改<IfModule dir_module>內容如下
 
<IfModule dir_module>
  1. DirectoryIndex index.html index.jsp
  2. </IfModule>
在此配置文件的末尾加上如下內容
 
<VirtualHost *:8011>
  1. ServerAdmin [email]weijie@126.com[/email]
  2. ServerName localhost
  3. ServerAlias localhost
  4. ProxyPass / balancer://mycluster/ stickysession=JSESSIONID nofailover=Off
  5. ProxyPa***everse / balancer://mycluster/
  6. ErrorLog "logs/error.log"
  7. CustomLog "logs/access.log" common
  8. </VirtualHost>
其中VirtualHost *:8011代表筆者本機的http server端口。
ProxyPass / balancer://mycluster/代表所有的請求都會重定向到balancer://mycluster/處理。balancer是內置負載。
ProxyPa***everse / balancer://mycluster/是反向代理,也就是將所有的請求反向代理到負載均衡後的應用url路徑中。
stickysession=JSESSIONID nofailover=Off是做Session複製用的。
之後再將此配置文件末尾加上如下內容,配置Node
ProxyRequests Off
  1. <proxy balancer://mycluster>
  2. BalancerMember ajp://127.0.0.1:18009 loadfactor=1 route=tomcat7_node1
  3. BalancerMember ajp://127.0.0.1:28009 loadfactor=1 route=tomcat7_node2
  4. # status=+H爲配置熱備,當所有機器都over時,纔會請求該機器
  5. #BalancerMember http://192.168.1.218:8009 status=+H
  6. #按照請求次數均衡(默認)
  7. #ProxySet lbmethod=byrequests
  8. #按照權重
  9. #ProxySet lbmethod=bytraffic
  10. #按負載量,也就是往負載少的派發新請求
  11. #ProxySet lbmethod=bybusyness
  12. ProxySet lbmethod=bybusyness
  13. </proxy>
這裏不僅配置了2tomcatnode節點,還配置了相關的負載算法策略。ProxySet lbmethod即是負載均衡算法策略。此處使用的是按照負載量,吞吐量少Node的之後可要小心嘍,分配到你的任務可就多了。而byrequests策略更偏重的是次數。
這裏還要說明的就是<proxy balancer://mycluster>,和上面的ProxyPass要對應上。
2. 之後準備2Tomcat,進行Node的配置
筆者的Tomcat版本是apache-tomcat-6.0.29,本來是要用apache-tomcat-7.0.6的,這個版本有點問題,後來看官方網站說,確實此7.0.6版本有些問題。
首先來看apache-tomcat-6.0.29.2-node1的配置文件
修改關閉端口
<Server port="8005" shutdown="SHUTDOWN">
修改http服務端口
<Connector port="18080" protocol="HTTP/1.1"
  1. connectionTimeout="20000"
  2. redirectPort="18443" />
修改AJP協議端口
<Connector port="18009" protocol="AJP/1.3" redirectPort="18443" />
這個端口實際上就是與Apache Http Server通訊的通道,Apache會通過AJP協議與Tomcat進行通訊,所以在Apache中配置的Node端口就是此處的端口。
增加jvmRoute名字
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat7_node1">
之後最重要的將Tomcat的集羣配置放開,內容如下
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
  1. channelSendOptions="8">
  2. <Manager className="org.apache.catalina.ha.session.DeltaManager"
  3. expireSessionsOnShutdown="false"
  4. notifyListenersOnReplication="true"/>
  5. <Channel className="org.apache.catalina.tribes.group.GroupChannel">
  6. <Membership className="org.apache.catalina.tribes.membership.McastService"
  7. address="228.0.0.4"
  8. mcastBindAddress="127.0.0.1"
  9. port="45564"
  10. frequency="500"
  11. dropTime="3000"/>
  12. <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
  13. address="auto"
  14. tcpListenAddress="127.0.0.1"
  15. port="4000"
  16. autoBind="100"
  17. selectorTimeout="5000"
  18. maxThreads="6"/>
  19. <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
  20. <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
  21. </Sender>
  22. <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
  23. <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
  24. </Channel>
  25. <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
  26. filter=""/>
  27. <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
  28. <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
  29. tempDir="/tmp/war-temp/"
  30. deployDir="/tmp/war-deploy/"
  31. watchDir="/tmp/war-listen/"
  32. watchEnabled="false"/>
  33. <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
  34. <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
  35. </Cluster>
之後apache-tomcat-6.0.29.2-node2的配置和它差不多,只有一些端口的差異,差異如下
<Server port="8006" shutdown="SHUTDOWN">
  1. ………………
  2. <Connector port="28080" protocol="HTTP/1.1"
  3. connectionTimeout="20000"
  4. redirectPort="28443" />
  5. ………………
  6. <Connector port="28009" protocol="AJP/1.3" redirectPort="28443" />
  7. ………………
  8. <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat7_node2">
  9. ………………
  10. <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
  11. address="auto"
  12. tcpListenAddress="127.0.0.1"
  13. port="4001"
  14. autoBind="100"
  15. selectorTimeout="5000"
  16. maxThreads="6"/>
這樣Tomcat算是完成
3. 寫一個Web項目測試
測試頁面代碼如下
<%@ page language="java" contentType="text/html; charset=UTF-8"
  1. pageEncoding="UTF-8"%>
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  3. <%@page import="java.util.*"%>
  4. <%@page import="java.net.InetAddress;"%>
  5. <html>
  6. <head>
  7. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  8. <title>Cluster App Test</title>
  9. </head>
  10. <body>
  11. <%
  12. InetAddress ip = InetAddress.getLocalHost();
  13. //out.println(ip.getHostAddress());
  14. %>
  15. This is responsed by
  16. <font color="red"> <%=ip.getHostAddress()%></font>
  17. <br>
  18. Host Name :
  19. <font color="red"><%=ip.getHostName()%></font>
  20. <br>
  21. Time :
  22. <font color="red"><%=new Date()%></font>
  23. <br>
  24. <%
  25. ip = null;
  26. %>
  27. <br />
  28. <br />
  29. <br />
  30. <br />
  31. Server Info:
  32. <%
  33. out.println(request.getLocalAddr() + " : " + request.getLocalPort()
  34. + "<br>");
  35. %>
  36. <%
  37. out.println("<br>Session ID " + session.getId() + "<br>");
  38. // 如果有新的 Session 屬性設置
  39. String dataName = request.getParameter("dataName");
  40. if (dataName != null && dataName.length() > 0) {
  41. String dataValue = request.getParameter("dataValue");
  42. session.setAttribute(dataName, dataValue);
  43. }
  44. out.print("<br/> <b>Session 列表</b>");
  45. Enumeration e = session.getAttributeNames();
  46. while (e.hasMoreElements()) {
  47. String name = (String) e.nextElement();
  48. String value = session.getAttribute(name).toString();
  49. out.println(name + " = " + value + "<br>");
  50. System.out.println(name + " = " + value);
  51. }
  52. %>
  53. <form action="index.jsp" method="POST">
  54. 名稱:
  55. <input type=text size=20 name="dataName">
  56. <br>
  57. &nbsp;&nbsp;值:
  58. <input type=text size=20 name="dataValue">
  59. <br>
  60. <input type=submit>
  61. </form>
  62. </body>
  63. </html>
WEB-INF\web.xml如下
<?xml version="1.0" encoding="UTF-8"?>
  1. <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  4. http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  5. <distributable/>
  6. <welcome-file-list>
  7. <welcome-file>index.jsp</welcome-file>
  8. </welcome-file-list>
  9. </web-app>
加入了<distributable/>用於Session複製。
4. Web項目測試效果
測試效果就是同一個瀏覽器IESession在不同的Node上共享了一個Session,其中一個Node掛了也不要緊,另一個緊跟着就複製過來了,而且在不同Node上切換也沒關係,Session不會丟失的。換一個瀏覽器FireFox建立一個新Session,互不影響。解決了之前提出的2個問題,1,負載算法可以根據實際請求壓力而分擔;2Session不用很複雜的配置即可完成Session的複製,並且一個Node掛了也不要緊,Session在另一個節點上也可以正常使用,而且Node在請求的不同階段切換也沒關係,對用戶是透明的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章