Apache服务器配置反向代理实现负载均衡和双机热备

考虑到对不同的 App Server 而言, 实现 Session 复制的配置各不相同(通常是需要配置集群), 因此从通用的角度, 觉得使用 session sticky 方式实现的负载均衡比较方便(没有看到有资料说 lighttpd 能够实现 session sticky, 所以决定使用 Apache 试试)
环境准备:
1、下载安装 Apache(不多废话了)
2、准备两个运行同样程序的 Web 服务器,这里使用的是 Tomcat 5.5, 并使用一个 jsp 文件作为测试文件
3、下载安装 JMeter ( jakarta-jmeter-2.2), 用于压力测试, 验证负载均衡的效果
测试 jsp 文件说明:
1、显示当前运行的服务器的 IP 地址及端口号, 这样从返回的页面就能够知道是运行在哪一个 Web 服务器上的了
2、统计每个客户端(不同的 session)向同一台服务器发出请求的次数, 通过这个计数可以验证是否实现了 session sticky
3、通过 clear 请求参数(即 .../test.jsp?clear=1)清除请求次数的计数结果, 以便进行下一次测试
4、模拟 JSESSIONID +jvmRoute 的机制, 自行实现了一个 STICK_PORT_TOKEN 的 Cookie, 直接使用不同服务器的 HTTP 端口号作为 route

Apache 的配置:
#######################################################
# Reverse Proxy and Load Balance ######################
#######################################################
# 1)简单的反向代理
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass /1 http://localhost:8080/test
#ProxyPassReverse /1 http://localhost:8080/test
ProxyPass /2 http://localhost:18080/test
#ProxyPassReverse /2 http://localhost:18080/test

# 2)非 stickysession 的 balance
ProxyPass /3 balancer://non-sticky-cluster nofailover=On
<Proxy balancer://non-sticky-cluster>
BalancerMember http://localhost:8080/test
BalancerMember http://localhost:18080/test smax=10
</Proxy>

# 3)stickysession 的 balance
ProxyPass /4 balancer://sticky-cluster stickysession=STICK_PORT_TOKEN nofailover=On
<Proxy balancer://sticky-cluster>
BalancerMember http://localhost:8080/test route=8080
BalancerMember http://localhost:18080/test route=18080 loadfactor=2
</Proxy>

这个配置分为3个部分, 包括了 
1)简单的反向代理, 
2)非 session sticky 的 load balance, 以及 
3)session sticky 的 load balance 三种方式的配置(这里假设两个 Tomcat 服务器的 HTTP 服务被配置在 8080 和 18080 端口), 其中第 2) 和 3) 的配置中 "nofailover=On" 适合于没有 session 复制的情况下, 这种情况下, 如果其中一台 HTTP 服务器出错, 那么原来分配在这个出错机器上的浏览器客户端不会被自动转移到另外的服务器上, 必须重新启动浏览器才能将请求分配到另外一台服务器上去.

使用 JMeter 测试结果:
使用 JMeter 对 "3)session sticky 的 load balance" 的效果进行测试, 通过压力测试的方式, 检查两台 Tomcat 服务器被分配到的请求数量(注意如果重复测试, 在下一次测试开始之前请对每个 Tomcat 服务器执行 .../test.jsp?clear=1 的请求, 清除上一次的计数结果).

从下图的测试结果可见: 50个线程中有21个被分配在 8080 端口的服务器上, 29个则被分配到 18080 端口的服务器; 另外, 所有的 session 请求次数都是 20 次, 说明 session sticky 达到了预期的效果.
补充一下对 PHP 的 session sticky 配置问题:
对于使用 PHP 的朋友可能会在这里遇到一些问题,也许是因为 Apache 文档的误导,大家可能会照着上面的例子把 JSESSIONID 换为 PHPSESSID,但是这样是不行的!如果你有时间看看代码 modules/proxy/mod_proxy_balancer.c lines 195 to 210 也许你会发现一些问题,Apache 实际上在找一个类似于“balancer.www1”的 SESSIONID,我们可以配置 TOMCAT 来实现这种形式的 SESSIONID 但是 PHP 却没有这个功能。但是,幸好我们能通过 Apache 的 Rewrite 功能来做这个事情。

首先,假设我们后台有两台机器 www1.james.com 和 www2.james.com 我们先为他们配置 VirtualHost :
RewriteEngine on
RewriteRule .* - [CO=BALANCEID:balancer.www{1或者2}:.james.com]
然后,我们在前台做负载均衡的机器上(假设为www.james.com)配置如下:
ProxyPass /bt balancer://sticky-cluster lbmethod=byrequests stickysession=BALANCEID nofailover=On
ProxyPassReverse /bt balancer://sticky-cluster
<Proxy balancer://sticky-cluster>
BalancerMember http://www2.james.com/6d/session_test.php route=www2
BalancerMember http://www1.james.com/session_test.php route=www1
</Proxy>

重启 Apache 大功告成,我们访问 http://mail.james.com/bt 发现 .james.com 的 COOKIE 中除了 PHPSESSID 还出现了 BALANCEID,到这里我们已经成功了一半;然后,我们可以到 apache 的 site_error log 中看到以下信息(设置 LogLevel debug):
第一次登录:
BALANCER: Found value (null) for stickysession BALANCEID
Entering byrequests for BALANCER (balancer://sticky-cluster)
第二次登录:
Found value balancer.www2 for stickysession BALANCEID
Found route www2
之后,该用户的 session 就不会跳到 www1 上去了,直到 cookie 或 session 过期。这样,我们就达到了“stick session”的目的了,真是形象啊,哈哈:)

以下是一些关于缓存的配置步骤摘要:
创建/var/www/proxy,设置apache服务所用户可写
mod_proxy配置样例:反相代理缓存+缓存
架设前台的www.example.com反向代理后台的www.backend.com的8080端口服务。
修改:httpd.conf
<VirtualHost *>
ServerName www.example.com
ServerAdmin admin@example.com
# reverse proxy setting
ProxyPass / http://www.backend.com:8080/
ProxyPassReverse / http://www.backend.com:8080/
# cache dir root
CacheRoot "/var/www/proxy"
# max cache storage
CacheSize 50000000
# hour: every 4 hour
CacheGcInterval 4
# max page expire time: hour
CacheMaxExpire 240
# Expire time = (now - last_modified) * CacheLastModifiedFactor
CacheLastModifiedFactor 0.1
# defalt expire tag: hour
CacheDefaultExpire 1
# force complete after precent of content retrived: 60-90%
CacheForceCompletion 80
CustomLog /usr/local/apache/logs/dev_access_log combined
</VirtualHost>

当然,现在主流的负载均衡技术绝不仅仅只是以上这些,文章最后,列举一些做备用知识:
1、DNS负载均衡(一种简单而有效的方法,但是存在不少问题,首先域名服务器无法知道服务结点是否有效;其次,由于DNS的数据刷新 时间TTL(Time to LIVE)标志,一旦超过这个TTL,其他DNS服务器就需要和这个服务器交互,以重新获得地址数据,因此为了使地址能随机分配,就应使TTL尽量短,然 而将TTL设置得过短,将使DNS流量大增,而造成额外的网络问题;最后,它不能区分服务器的差异,也不能反映服务器的当前运行状态。)
2、网络接入协议交换(大型的网络一般都是由大量专用技术设备组成的,如包括防火墙、路由器、第3、4层交换机、负载均衡设备、缓冲服 务器和Web服务器等。由于第四层交换基于硬件芯片,因此其性能非常优秀,尤其是对于网络传输速度和交换速度远远超过普通的数据包转发。然而,正因为它是 使用硬件实现的,因此也不够灵活,仅仅能够处理几种最标准的应用协议的负载均衡,如HTTP 。当前负载均衡主要用于解决服务器的处理能力不足的问题,因此并不能充分发挥交换机带来的高网络带宽的优点。)

总之,负载均衡是一种策略,它能让多台服务器或多条链路共同承担一些繁重的计算或I/O任务,从而以较低成本消除网络瓶颈,提高网络的灵活性和可靠性。


********************************

Centos基于Apache的Tomcat负载均衡和集群

********************************

一、背景原理
1、tomcat 做个WEB服务器有它的局限性,处理能力低,效率低。承受并发小(1000左右)。但目前有不少网站或者页面是JSP的。并采用了tomcat做为WEB,因此只能在此基础上调优。
2、目前采取的办法是Apache + Mod_JK + tomcat 来解决一部分请求,用户访问的是apache,但有jsp页面的时候才会去请求tomcat。如果量一大,那么tomcat无法承受,那么只能做tomat集群,Apache + Mod_JK 就是负载均衡器了(apache+tomcat通过ajp13协议做集群,,apache和tomcat用mod_jk连接器通信)。
3、Mod_JK2负载均衡可以把不同的jsp请求转发到不同的tomcat服务器,还可以侦测服务器存活。如果有条件可以给Mod_JK2做一个HA因为做完集群后压力就在JK上了。

1.jpg


4、反向代理负载均衡 (Apache+JK+Tomcat)
 使用代理服务器可以将请求转发给内部的Web服务器,让代理服务器将请求均匀地转发给多台内部Web服务器之一上,从而达到负载均衡的目的。这种代理方式与普通的代理方式有所不同,标准代理方式是客户使用代理访问多个外部Web服务器,而这种代理方式是多个客户使用它访问内部Web服务器,因此也被称为反向代理模式。

5、为什么要配置Tomcat 负载均衡和集群
负载均衡:负载均衡能处理高并发量的请求。
Tomcat 集群:Tomcat 集群配合负载均衡可以是系统达到高可用性,即任何一台服务器不可用,自动重新连接后,能保持session 数据一致,不需要重新输入密码。

6、简单原理介绍
 1.apatche 与tomcat 的之间的联系由jk 完成,用的是ajp协议。每个tomcat 都在监听ajp端口。默认的 AJP Connector 的端口是 8009 。 
 2.配置了集群的 tomcat 之间通过 tcp 协议通信复制 session,当然要在tomcat 应用中的web.xml 文件中加入<distributable/>或<Context distributable="true" /> ,标志着要复制session。
  复制session 是为了在某个服务器正在被请求时宕机,请求由apache 通过jk 转发到其他tomcat 服务器时,session 中的信息丢失采取的一中保持session 的方式,还有其他的解决方案,如把session 存到数据库中。
 3.jk 把请求分配给某个tomcat 服务器遵循着不同的原则,这里我们使用的是负载均衡。在 workers.properties 中定义了很多worker ,如果worker 的type 把定义成 lb,就表示这个worker 是负载均衡worker ,他知道怎样提供轮询来分配request 。而负载均衡也分很多平衡的方式,采用哪种方式决定于属性worker.balancer.method。

下面具体描述不同的负载均衡方式(默认的是R方式):
worker.balancer.method=Request (简写R ):负载均衡worker 将根据每个tomcat 服务器上处理的request 数来寻找最佳的tomcat 服务器。这种方式适合绝大数application 。
worker.balancer.method=Session (简写 S ):负载均衡worker 根据各个tomcat 上 session的数量来寻找最佳tomcat ,但是负载均衡worker 并没有状态,所以不知道session 个数,所以把没有session cookie 的请求或url 中没有encode sessionid 的请求当作new session 。
worker.balancer.method= Traffic (简写T ):负载均衡worker 根据jk 和tomcat 直接的网络状况来找最佳的tomcat 服务器。
worker.balancer.method= Busyness (简写B ):负载均衡worker 根据tomcat 的流量选择流量最少的tomcat 。

7、对应的安装介绍
 Apache服务器:是前端web 服务器,用来接收客户端的请求。
 mod_jk.so:是tomcat Connector ,用于把apache 接收到的请求分发给tomcat 来处理。JK要与Apache版本对应。JK 分为两个版本 1,x 和 2.x ,其中 2.x 并不是最新的版本,它是 JK 的另外一个分支,后不知何因没有继续开发,因此2.x 版本已经废弃。
 Tomcat :也是web 服务器,但在这里主要充当servlet 容器,用来处理jk 转发过来的请求。
 安装 apache ,并把 mod_jk.2.0.55 解压后拷贝到 apache 安装目录(Apache_HOME)/modules 下面,其实modules 下面是apache 的各个功能模块,可插拔。


二、需要的软件包
JDK:jdk-7u45-linux-x64.rpm
Tomcat:apache-tomcat-7.0.47.tar.gz
Apache:httpd-2.2.27.tar.gz
Mod_JK: tomcat-connectors-1.2.39-src.tar.gz

三、安装说明
参见: 
CentOS-6.3安装配置JDK-7  http://www.flybi.net/article/12
CentOS-6.3安装配置Tomcat7.0  http://www.flybi.net/article/2
CentOS-6.3安装配置Apache2.2.27  http://www.flybi.net/article/20
CentOS-6.3安装配置mod_jk1.2  http://www.flybi.net/article/22

三、配置
1、配置Apache
在apache的conf下,用vi编辑器打开httpd.conf,在该文件末尾加上如下行 (切记/usr/local/apache/conf 和 /etc/httpd/conf 下的httpd.conf里面都要添加)
Include /usr/local/apache/conf/mod_jk.conf 

2、配置mod_jk.conf文件
在/usr/local/apache/conf下建立mod_jk.conf文件。配置内容:

加载mod_jk Module

LoadModule jk_module /usr/local/apache/modules/mod_jk.so

加载集群中的workers

JkWorkersFile /usr/local/apache/conf/workers.properties

加载workers的请求处理分配文件

JkMountFile /usr/local/apache/conf/uriworkermap.properties

指定jk的日志输出文件

JkLogFile /usr/local/apache/logs/mod_jk.log

指定日志级别

JkLogLevel warn

指定日志的格式

JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"

指定哪些请求交给tomcat处理,"controller"为在 workers.propertise里指定的负载分配控制器名

JkMount /*.* controller

说明:
JkMount:设置apache分发器,/ 表示apache将所有文件都由分发器lbcontroller 进行分发,你可以自行设置 .jsp,*.do等;

3、配置workers.properties文件
在/usr/local/apache/conf下建立workers.properties文件。配置内容:

server 列表

worker.list=controller,tomcat1,tomcat2

========tomcat1========

worker.tomcat1.port=8008 #ajp13 端口号,在tomcat下server.xml配置,默认8009 worker.tomcat1.host=localhost #tomcat的主机地址,如不为本机,请填写ip地址 worker.tomcat1.type=ajp13 worker.tomcat1.lbfactor=1 #server的加权比重,值越高,分得的请求越多

========tomcat2========

worker.tomcat2.port=8009 #ajp13 端口号,在tomcat下server.xml配置,默认8009 worker.tomcat2.host=localhost #tomcat的主机地址,如不为本机,请填写ip地址 worker.tomcat2.type=ajp13 worker.tomcat2.lbfactor=1 #server的加权比重,值越高,分得的请求越多

========controller,负载均衡控制器========

worker.controller.type=lb #server名为controller,用于负载均衡 worker.retries=3 #重试次数 worker.controller.balance_workers=tomcat1,tomcat2

粘性Session(默认是打开的) 当该属性值=True(或1)时,代表Session是粘性的,即同一Session在集群中的同一个节点上处理,Session不跨越节点。在集群环境中,一般将该值设置为False

worker.controller.sticky_session=false

设置用于负载均衡的server的session可否共享 有不少文章说设置为1是可以的,也有设置为0才可以的

worker.controller.sticky_session=1

worker.controller.sticky_session_force=1

worker.status.type=status


说明:
1、注意上面的worker.tomcat1.port端口是Tomcat server.xml下的
<Connector port="8019" protocol="AJP/1.3" redirectPort="8443" /> 

4、配置uriworkermap.properties文件
在/usr/local/apache/conf下建立uriworkermap.properties文件。配置内容:

所有请求都由controller这个server处理

/*=controller

所有包含jkstatus请求的都由status这个 server处理

/jkstatus=status

这里的"!”是“非”的意思。

!/*.gif=controller !/*.jpg=controller !/*.png=controller !/*.css=controller !/*.js=controller !/*.htm=controller !/*.html=controller

5、修改tomcat1_Home\conf\server.xml配置
JK: ajp13 listening on /0.0.0.0:8009 修改端口必须与workers.propertise文件内worker.tomcat1.port=8009一致。
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

以上为负载均衡配置完毕!接下来可以配置Tomcat集群和Session复制!
<Engine name="Catalina" defaultHost="localhost" **jvmRoute="tomcat2"**>     <!--tomcat1将与tomcat2黏贴session 在这里指定黏贴对象-->
...
<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"
        port="45564" 
        frequency="500" 
        dropTime="3000" />
    <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" 
        address="auto"
        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>
...
</Engine>

说明:228.0.0.4是默认的配置集群默认的地址,不要改动。

Tomcat2的server.xml配置也做相应修改,因为本文测试使用同一台电脑,所以对应的微做修改端口。Tomcat分布于不同电脑上,不用改端口号。
<Engine name="Catalina" defaultHost="localhost" **jvmRoute="tomcat1"**>     <!--tomcat2将与tomcat1黏贴session 在这里指定黏贴对象-->
...
<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"
        port="45564" 
        frequency="500" 
        dropTime="3000" />
    <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" 
        address="auto"
        port="4001" 
        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>
...
</Engine>

6、最后要tomcat支持session复制,必须在web.xml里面加上一个标签。在发布项目的web.xml文件里面添加及对应的tomcat_Home\conf\web.xml也要添加
<!-- 集群 表明要复制session,一般放在最后-->
<distributable/>

  注意:session黏贴(共享)方面,如果session中存放的为javabean,javabean必须实现Serializable接口,如果没有实现会报错误 Exception thrown: class java.lang.IllegalArgumentException。
7、测试
在tomcat1和tomcat2的\webapps下建立test文件夹,建立test.jsp文件
<%System.out.println("==============");%>

启动Tomcat1、Tomcat2、Apache。浏览器中输入: http://localhost/test/test.jsp 。不停刷新浏览器,可以在Tomcat1和2的控制台看到=====交替输出。
结果:在不同的客户端发起请求,请求会被平均分配给tomcat。关闭其中一个tomcat 1,tomcat 1 原来处理的请求会被其他tomcat2 接收,如果此前被关闭的tomca 1t 的session 中存在信息, tomcat2 中tomcat1 的session 信息依然存在,表现为登录——tomcat 宕机——请求被转到另外一个tomcat ,并仍然处于登录状态。
8、其他总结
不同类型的worker,worker.controller.type配置:
ajp12 这种类型的worker 知道使用ajp12 协议把请求转向tomcat,最终它将被jk 使用,用来与tomcat 服务器交互。
ajp13 这种类型的worker 知道使用ajp13 协议把请求转向tomcat,最终它将被jk 使用,用来与tomcat 服务器交互。
jni   这种类型的worker 知道使用jni 协议把请求转向tomcat,最终它将被jk 使用,用来与tomcat 服务器交互。
lb    这种类型的worker 是负载均衡worker,他知道怎样提供轮询来分配请求。(常用)
status 这种类型的worker 负责管理负载均衡。


三、 apache jkstatus JK运行状态管理权限
在已配置完成的 apache 项目中 workers.properties 配置文件中加入 下面两行
worker.list = status
worker.status.type=status

mod_jk.conf 配置文件中加入下面一行
JkMount /jkstatus status

在地址栏访问 http://ip 地址:端口号/jkstatus 就能看到了。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值