• Apache_proxy负载均衡和Session复制


    今天上网查了查资料,之前使用apache的jk模块做负载均衡。后来觉得jk的负载配置有点死板,只能按照负载权重值来进行请求的分发,没有做到比较智能的负载平衡,并且使用mod_jk访问页面发现确实比较慢。可能是jk路由到真正的Node Server上比较费时间吧。结合笔者提出的jk的缺点,今天使用mod_proxy来进行负载均衡和路由选择。

    之前提出了jk相关的缺点

    1):负载均衡权重是在配置文件中写死的。不能根据实际的运行时机器的环境来决定负载均衡的策略,显得比较死板

    2):虽然在apache中配置了session共享,但是实际上session并没有在node上进行共享传递。如果一台机器挂了,那么这台机器的客户session也就消失了,容错性比较差

    笔者的环境如下:

    OS:Windows7

    HttpServer:Apache Http Server2.2.17

    Tomcat:apache-tomcat-6.0.29

    下面来看如何加载mod_proxy模块

    1. 加载相关apache的模块

    在配置文件httpd.conf中放开注释

     
    #加载mod_proxy
    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
    LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
    LoadModule proxy_connect_module modules/mod_proxy_connect.so
    LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
    LoadModule proxy_http_module modules/mod_proxy_http.so

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

    修改<IfModule dir_module>内容如下

    <IfModule dir_module>
       DirectoryIndex index.html index.jsp
    </IfModule>

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

    <VirtualHost *:8011>
             ServerAdmin [email]weijie@126.com[/email]
             ServerName localhost
             ServerAlias localhost
             ProxyPass / balancer://mycluster/ stickysession=JSESSIONID nofailover=Off
             ProxyPassReverse / balancer://mycluster/
    	 ErrorLog "logs/error.log"
    	 CustomLog "logs/access.log" common
    </VirtualHost>

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

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

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

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

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

    ProxyRequests Off
    <proxy balancer://mycluster>
    	BalancerMember ajp://127.0.0.1:18009 loadfactor=1 route=tomcat7_node1
    	BalancerMember ajp://127.0.0.1:28009 loadfactor=1 route=tomcat7_node2
    	# status=+H为配置热备,当所有机器都over时,才会请求该机器
    	#BalancerMember http://192.168.1.218:8009 status=+H
    	#按照请求次数均衡(默认)
    	#ProxySet lbmethod=byrequests
    	#按照权重
    	#ProxySet lbmethod=bytraffic
    	#按负载量,也就是往负载少的派发新请求
    	#ProxySet lbmethod=bybusyness
    	ProxySet lbmethod=bybusyness
    </proxy>

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

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

    1. 之后准备2个Tomcat,进行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" 
                   connectionTimeout="20000" 
                   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"
                     channelSendOptions="8">
    
              <Manager className="org.apache.catalina.ha.session.DeltaManager"
                       expireSessionsOnShutdown="false"
                       notifyListenersOnReplication="true"/>
    
              <Channel className="org.apache.catalina.tribes.group.GroupChannel">
                <Membership className="org.apache.catalina.tribes.membership.McastService"
                            address="228.0.0.4"
    						mcastBindAddress="127.0.0.1"
                            port="45564"
                            frequency="500"
                            dropTime="3000"/>
                <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                          address="auto"
    					  tcpListenAddress="127.0.0.1"
                          port="4000"
                          autoBind="100"
                          selectorTimeout="5000"
                          maxThreads="6"/>
    
                <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
                  <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
                </Sender>
                <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
                <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
              </Channel>
    
              <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                     filter=""/>
              <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
    
              <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
                        tempDir="/tmp/war-temp/"
                        deployDir="/tmp/war-deploy/"
                        watchDir="/tmp/war-listen/"
                        watchEnabled="false"/>
    
              <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
              <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
    </Cluster>

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

    <Server port="8006" shutdown="SHUTDOWN">
    ………………
    <Connector port="28080" protocol="HTTP/1.1" 
                   connectionTimeout="20000" 
                   redirectPort="28443" />
    ………………
    <Connector port="28009" protocol="AJP/1.3" redirectPort="28443" />
    ………………
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat7_node2">
    ………………
                <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                          address="auto"
    					  tcpListenAddress="127.0.0.1"
                          port="4001"
                          autoBind="100"
                          selectorTimeout="5000"
                          maxThreads="6"/>

     这样Tomcat算是完成

    1. 写一个Web项目测试

    测试页面代码如下

    <%@ page language="java" contentType="text/html; charset=UTF-8"
    	pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <%@page import="java.util.*"%>
    <%@page import="java.net.InetAddress;"%>
    <html>
    	<head>
    		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    		<title>Cluster App Test</title>
    	</head>
    	<body>
    		<%
    			InetAddress ip = InetAddress.getLocalHost();
    			//out.println(ip.getHostAddress());
    		%>
    		This is responsed by
    		<font color="red"> <%=ip.getHostAddress()%></font>
    		<br>
    		Host Name :
    		<font color="red"><%=ip.getHostName()%></font>
    		<br>
    		Time :
    		<font color="red"><%=new Date()%></font>
    		<br>
    		<%
    			ip = null;
    		%>
    		<br />
    		<br />
    		<br />
    		<br />
    		Server Info:
    		<%
    			out.println(request.getLocalAddr() + " : " + request.getLocalPort()
    					+ "<br>");
    		%>
    		<%
    			out.println("<br>Session 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("<br/> <b>Session 列表</b>");
    			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="index.jsp" method="POST">
    			名称:
    			<input type=text size=20 name="dataName">
    			<br>
    			&nbsp;&nbsp;值:
    			<input type=text size=20 name="dataValue">
    			<br>
    			<input type=submit>
    		</form>
    	</body>
    </html>

     WEB-INFweb.xml如下

     
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    	<distributable/>
    	<welcome-file-list>
    		<welcome-file>index.jsp</welcome-file>
    	</welcome-file-list>
    </web-app>

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

    1. Web项目测试效果

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

  • 相关阅读:
    CF1359D Yet Another Yet Another Task
    【数据结构】fhq_treap
    AtCoder Beginner Contest 182 题解
    UVA11992 Fast Matrix Operations
    双指针例题
    python使用国内镜像库
    APP元素定位工具之——Weditor
    安卓ADB的常见命令的使用
    函数进阶之迭代器,递归
    函数基础之对象,嵌套,名称空间和作用域
  • 原文地址:https://www.cnblogs.com/edison2012/p/4600018.html
Copyright © 2020-2023  润新知