Apache_proxy负载均衡和Session复制

转自:http://suhuanzheng7784877.iteye.com/blog/987062

今天上网查了查资料,之前使用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中放开注释

Java代码   收藏代码
  1. #加载mod_proxy  
  2. LoadModule proxy_module modules/mod_proxy.so  
  3. LoadModule proxy_ajp_module modules/mod_proxy_ajp.so  
  4. LoadModule proxy_balancer_module modules/mod_proxy_balancer.so  
  5. LoadModule proxy_connect_module modules/mod_proxy_connect.so  
  6. LoadModule proxy_ftp_module modules/mod_proxy_ftp.so  
  7. LoadModule proxy_http_module modules/mod_proxy_http.so  

 因为在apache2.2.x版本中自动会有这些模块,所以直接打开注释即可。

 

修改<IfModule dir_module>内容如下

 

Java代码   收藏代码
  1. <IfModule dir_module>  
  2.    DirectoryIndex index.html index.jsp  
  3. </IfModule>  

 在此配置文件的末尾加上如下内容

 

 

 

 

Java代码   收藏代码
  1. <VirtualHost *:8011>  
  2.          ServerAdmin [email]weijie@126.com[/email]  
  3.          ServerName localhost  
  4.          ServerAlias localhost  
  5.          ProxyPass / balancer://mycluster/ stickysession=JSESSIONID nofailover=Off  
  6.          ProxyPassReverse / balancer://mycluster/  
  7.      ErrorLog "logs/error.log"  
  8.      CustomLog "logs/access.log" common  
  9. </VirtualHost>  

 其中VirtualHost *:8011代表笔者本机的http server端口。

ProxyPass / balancer://mycluster/代表所有的请求都会重定向到balancer://mycluster/处理。balancer是内置负载。

ProxyPassReverse / balancer://mycluster/是反向代理,也就是将所有的请求反向代理到负载均衡后的应用url路径中。

stickysession=JSESSIONID nofailover=Off是做Session复制用的。

之后再将此配置文件末尾加上如下内容,配置Node

Java代码   收藏代码
  1. ProxyRequests Off  
  2. <proxy balancer://mycluster>  
  3.     BalancerMember ajp://127.0.0.1:18009 loadfactor=1 route=tomcat7_node1  
  4.     BalancerMember ajp://127.0.0.1:28009 loadfactor=1 route=tomcat7_node2  
  5.     # status=+H为配置热备,当所有机器都over时,才会请求该机器  
  6.     #BalancerMember http://192.168.1.218:8009 status=+H  
  7.     #按照请求次数均衡(默认)  
  8.     #ProxySet lbmethod=byrequests  
  9.     #按照权重  
  10.     #ProxySet lbmethod=bytraffic  
  11.     #按负载量,也就是往负载少的派发新请求  
  12.     #ProxySet lbmethod=bybusyness  
  13.     ProxySet lbmethod=bybusyness  
  14. </proxy>  

 这里不仅配置了2个tomcat的node节点,还配置了相关的负载算法策略。ProxySet lbmethod即是负载均衡算法策略。此处使用的是按照负载量,吞吐量少Node的之后可要小心喽,分配到你的任务可就多了。而byrequests策略更偏重的是次数。

这里还要说明的就是<proxy balancer://mycluster>,和上面的ProxyPass要对应上。

2.       之后准备2个Tomcat,进行Node的配置

笔者的Tomcat版本是apache-tomcat-6.0.29,本来是要用apache-tomcat-7.0.6的,这个版本有点问题,后来看官方网站说,确实此7.0.6版本有些问题。

首先来看apache-tomcat-6.0.29.2-node1的配置文件

修改关闭端口

Java代码   收藏代码
  1. <Server port="8005" shutdown="SHUTDOWN">  

 修改http服务端口

Java代码   收藏代码
  1. <Connector port="18080" protocol="HTTP/1.1"   
  2.                connectionTimeout="20000"   
  3.                redirectPort="18443" />  

 修改AJP协议端口

Java代码   收藏代码
  1. <Connector port="18009" protocol="AJP/1.3" redirectPort="18443" />  

 这个端口实际上就是与Apache Http Server通讯的通道,Apache会通过AJP协议与Tomcat进行通讯,所以在Apache中配置的Node端口就是此处的端口。

增加jvmRoute名字

Java代码   收藏代码
  1. <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat7_node1">  

 之后最重要的将Tomcat的集群配置放开,内容如下

Java代码   收藏代码
  1. <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"  
  2.                  channelSendOptions="8">  
  3.   
  4.           <Manager className="org.apache.catalina.ha.session.DeltaManager"  
  5.                    expireSessionsOnShutdown="false"  
  6.                    notifyListenersOnReplication="true"/>  
  7.   
  8.           <Channel className="org.apache.catalina.tribes.group.GroupChannel">  
  9.             <Membership className="org.apache.catalina.tribes.membership.McastService"  
  10.                         address="228.0.0.4"  
  11.                         mcastBindAddress="127.0.0.1"  
  12.                         port="45564"  
  13.                         frequency="500"  
  14.                         dropTime="3000"/>  
  15.             <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"  
  16.                       address="auto"  
  17.                       tcpListenAddress="127.0.0.1"  
  18.                       port="4000"  
  19.                       autoBind="100"  
  20.                       selectorTimeout="5000"  
  21.                       maxThreads="6"/>  
  22.   
  23.             <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">  
  24.               <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>  
  25.             </Sender>  
  26.             <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>  
  27.             <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>  
  28.           </Channel>  
  29.   
  30.           <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"  
  31.                  filter=""/>  
  32.           <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>  
  33.   
  34.           <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"  
  35.                     tempDir="/tmp/war-temp/"  
  36.                     deployDir="/tmp/war-deploy/"  
  37.                     watchDir="/tmp/war-listen/"  
  38.                     watchEnabled="false"/>  
  39.   
  40.           <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>  
  41.           <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>  
  42. </Cluster>  

 之后apache-tomcat-6.0.29.2-node2的配置和它差不多,只有一些端口的差异,差异如下

Java代码   收藏代码
  1. <Server port="8006" shutdown="SHUTDOWN">  
  2. ………………  
  3. <Connector port="28080" protocol="HTTP/1.1"   
  4.                connectionTimeout="20000"   
  5.                redirectPort="28443" />  
  6. ………………  
  7. <Connector port="28009" protocol="AJP/1.3" redirectPort="28443" />  
  8. ………………  
  9. <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat7_node2">  
  10. ………………  
  11.             <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"  
  12.                       address="auto"  
  13.                       tcpListenAddress="127.0.0.1"  
  14.                       port="4001"  
  15.                       autoBind="100"  
  16.                       selectorTimeout="5000"  
  17.                       maxThreads="6"/>  

 这样Tomcat算是完成

3.       写一个Web项目测试

测试页面代码如下

Java代码   收藏代码
  1. <%@ page language="java" contentType="text/html; charset=UTF-8"  
  2.     pageEncoding="UTF-8"%>  
  3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  4. <%@page import="java.util.*"%>  
  5. <%@page import="java.net.InetAddress;"%>  
  6. <html>  
  7.     <head>  
  8.         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  9.         <title>Cluster App Test</title>  
  10.     </head>  
  11.     <body>  
  12.         <%  
  13.             InetAddress ip = InetAddress.getLocalHost();  
  14.             //out.println(ip.getHostAddress());  
  15.         %>  
  16.         This is responsed by  
  17.         <font color="red"> <%=ip.getHostAddress()%></font>  
  18.         <br>  
  19.         Host Name :  
  20.         <font color="red"><%=ip.getHostName()%></font>  
  21.         <br>  
  22.         Time :  
  23.         <font color="red"><%=new Date()%></font>  
  24.         <br>  
  25.         <%  
  26.             ip = null;  
  27.         %>  
  28.         <br />  
  29.         <br />  
  30.         <br />  
  31.         <br />  
  32.         Server Info:  
  33.         <%  
  34.             out.println(request.getLocalAddr() + " : " + request.getLocalPort()  
  35.                     + "<br>");  
  36.         %>  
  37.         <%  
  38.             out.println("<br>Session ID " + session.getId() + "<br>");  
  39.             // 如果有新的 Session 属性设置  
  40.             String dataName = request.getParameter("dataName");  
  41.             if (dataName != null && dataName.length() > 0) {  
  42.                 String dataValue = request.getParameter("dataValue");  
  43.                 session.setAttribute(dataName, dataValue);  
  44.             }  
  45.             out.print("<br/> <b>Session 列表</b>");  
  46.             Enumeration e = session.getAttributeNames();  
  47.             while (e.hasMoreElements()) {  
  48.                 String name = (String) e.nextElement();  
  49.                 String value = session.getAttribute(name).toString();  
  50.                 out.println(name + " = " + value + "<br>");  
  51.                 System.out.println(name + " = " + value);  
  52.             }  
  53.         %>  
  54.         <form action="index.jsp" method="POST">  
  55.             名称:  
  56.             <input type=text size=20 name="dataName">  
  57.             <br>  
  58.             &nbsp;&nbsp;值:  
  59.             <input type=text size=20 name="dataValue">  
  60.             <br>  
  61.             <input type=submit>  
  62.         </form>  
  63.     </body>  
  64. </html>  

 WEB-INF\web.xml如下

Java代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
  5.     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
  6.     <distributable/>  
  7.     <welcome-file-list>  
  8.         <welcome-file>index.jsp</welcome-file>  
  9.     </welcome-file-list>  
  10. </web-app>  

 加入了<distributable/>用于Session复制。

4.       Web项目测试效果

测试效果就是同一个浏览器IE的Session在不同的Node上共享了一个Session,其中一个Node挂了也不要紧,另一个紧跟着就复制过来了,而且在不同Node上切换也没关系,Session不会丢失的。换一个浏览器FireFox建立一个新Session,互不影响。解决了之前提出的2个问题,1,负载算法可以根据实际请求压力而分担;2,Session不用很复杂的配置即可完成Session的复制,并且一个Node挂了也不要紧,Session在另一个节点上也可以正常使用,而且Node在请求的不同阶段切换也没关系,对用户是透明的。

你可能感兴趣的:(session)