JBoss-4.2.3GA+Apache负载均衡及集群方案配置过程详解

来源:互联网 发布:汇通易贷 知乎 编辑:程序博客网 时间:2024/05/01 01:53

JBoss-4.2.3GA+Apache负载均衡及集群方案配置过程详解

(2011-03-06 22:36:46)
from http://blog.sina.com.cn/s/blog_4c925dca0100qh2l.html

  因为公司需要做apache+jboss的负载均衡和集群方面的要求,但阿堂原来没有这方面的经验,便开始了两天的拓荒之旅,其间的痛苦就不用说了,因为网上的文章,基本上大同小异,估计很多都是互相转载的,作了一些变动,都基本上有些错务,加上网上介绍的jboss版本都基本与我的的版本不一致,造成网上提到的jboss目录,我这里有可能没有,这样就更增加了一些麻烦,而向网上一些哥们寻找帮助的过程中,有的要么没做过,有的就只是做了 apaceh+tomcat的负载均衡,这样就增加阿堂解决问题的难度!最后总算解决了!先不说最终的实施效果是否如期望的那样,但这个方案能正常实施,可以说成功了90%了,至于apache等的调优等,就另当别论了!阿堂就不想在此说了!有感于自己配置的麻烦,就写了这篇总结文章和朋友们来一起分享了,希望能对其它网友有所帮助或借签,阿堂就很开心了!

布署环境

(1)两台Linux服务器 192.168.80.13   192.168.80.14

(2)JBOSS版本 4.2.3.GA(在上述两台Linux服务器分别装有此版本的JBoss服务器)

(3) Apache 2.2.17版本  (httpd-2.2.17.tar.gz可从官方网站下载此文件),Apache负载均衡服务器安装在192.168.80.13

Apache -Http server

(4)Mod_jk版本1.2.3  (版本是  mod_jk-1.2.31-httpd-2.2.x.so,可从官方网站下载) -

Apache Tomcat - Tomcat Connectors


特别说明

(1)Mod_jk版本必须与Apache版本配套,否则,可能安装好了,apache能正常运行,但是负载均衡还是不会起作用的,mod_jk-1.2.31-httpd-2.2.x.so   (如前面的红色文字是mod_jk的版本,后面的红色文字是Apache Server的版本)


部署测试结果

(1)Apache负载均衡已经正常使用,如说,http://192.168.80.13/test/index.jsp前面192.168.80.13地址实际上是Apache服务器的地址,它会拦截随机调用集群中的两个结点192.168.80.13  192.168.80.14对应的JBoss服务器


如下所示

 

JBoss-4.2.3GA+Apache负载均衡及集群方案配置过程详解





JBoss-4.2.3GA+Apache负载均衡及集群方案配置过程详解





 


(2)JBoss的集群功能已经生效。集群中的两个JBoss结点能进行Ajp集群通信了

 

本项目负载均衡方式:

目前是选择用的基于用户的负载均衡,因为基于request的负载均衡与我们目前需要的多并发,高频操作的情况不适应. (两种情况参照下面的说明)


JBoss-4.2.3GA+Apache负载均衡及集群方案配置过程详解



1、基于request的负载均衡

该种方式下,负载均衡器 (load balancer)会根据各个node的状况,把每个http request进行分发。使用这样的均衡策略,就必须在多个node之间复制用户的session,实时保持整个cluster的用户状态同步,这种操作被称为session复制(session replication)Jboss的实现原理是使用拦截器(interceptor),根据用户的同步策略拦截request,做同步处理后再交给server产生响应。

该方法的优点是客户不会被绑定都具体的node,只要还有一个node存活,用户状态都不会丢失,cluster都能够继续工作。缺点是node之间通信频繁,响应速度有影响,多并发、高频操作的情况下性能下降比较厉害。

2、基于用户的负载均衡

该种方式下,当用户发出第一个request后,负载均衡器动态的把该用户分配到某个节点,并记录该节点的jvm路由,以后该用户的所有request都会被绑定这个jvm路由,用户只会与该server发生交互,这种策略被称为粘性session(session sticky)

该方法的优点是响应速度快,多个节点之间无须通信。缺点也很明显,某个node死掉以后,它负责的所有用户都会丢失session


配置JBoss

  1. 修改虚拟机的参数run..conf 文件中的jvm堆大小,如果是用Sun或HP的JDK需要设置MaxPermSize

set JAVA_OPTS=%JAVA_OPTS% -Xms256m -Xmx1024m -XX:MaxPermSize=128m

2. 应用部署将EJB的jar包和WEB的 war 复制到$JBOSS_HOME/server/default/deplay

(后面这句话,我感觉好象没有用什么用的)如果是集群环境则复制到$JBOSS_HOME/server/default/farm

3. 部署JBOSS集群服务
用 $JBOSS_HOME/server/all的配置来部署集群则不需这一步,只有下面1、2两步是default配置要多做的工作。

(1).将$JBOSS_HOME/server/all/deploy 下的cluster-service.xml和jboss-web-cluster.sar复制到$JBOSS_HOME /server/default/deploy

(2). 将$JBOSS_HOME/server/all/lib 下的jgroups.jar、jbossha.jar、jboss-cache.jar复制到$JBOSS_HOME /server/default/lib

  jbossha.jar(加载org.jboss.ha.framework.server.ClusterPartition)
  jgroups.jar(JBoss集群底层通信协议)
  jboss-cache.jar(加载org.jboss.cache.aop.TreeCacheAop)

4. 配置Jboss节点
session复制配置

jboss session复制是jboss session同步的一种实现。原理是在各Jboss节点间建立横向联系,每个节点都将本节点的session变化同步到其他所有节点上。

jboss的session复制与HTTP集群是相互配合、相互独立的两个系统。session复制是节点间的横向联系,HTTP集群是负载均衡器与节点的纵向联系。

$JBOSS_HOME/ server/default/deploy/jboss-web-cluster.sar /META-INF/jboss-service.xml和 $JBOSS_HOME/ server/default/deploy/cluster-service.xml

注意:集群的各节点需要在同一网段.

两个文件都要修改,前者是web session复制的,后者是jboss EJB等集群

找到<config><udp,将><config>到</config>全部注释掉. jboss session复制有UDP和TCP两种方式.UDP采用多播方式,但问题比较多,所以采用TCP方式。

找到<config> <tcp,将><config>到</config>生效.并对该部分进行以下修改:

将全部down_thread和up_thread的false都改为true.
在<tcp bind_addr=” ${jboss.bind.address}”> 
在<tcpping initial_hosts=”后填入本机和集群其他全部Jboss节点的IP[7810],比如<tcpping initial_hosts=” ${jboss.bind.address} [7810],192.168.80.14[7810]”></tcpping> 

$JBOSS_HOME/ server/default/deploy/jboss-web-cluster.sar /META-INF/jboss-service.xm中的其他参数

ClusterName是集群名称在同一局域网内,可以存在多个jboss集群,根据集群名称区分它们.所以,集群中各节点配置的集群名称必须一致(实际项目中我配置的集群名称是wenshi),而机器IP则没有特殊要求,只要它们能 相互连通. 理论上,可以在一台机器上安装多个Jboss实例,分属于不同的集群.但这会极大地增加复杂度,是不好的配置方式.严重不建议给自己找麻烦。

IsolationLevel是隔离等级. 可选值包括:SERIALIZABLE, REPEATABLE_READ, READ_COMMITTED, READ_UNCOMMITTED, 和 NONE。这里的隔离级别和数据库的隔离级别有同样的含义,对于大多数WEB应用程序来讲通常设置为REPEATABLE_READ。

CacheMode是缓存模式。由于session复制是通过缓存实现的,所以实际上是复制模式.可选值包括:REPL_SYNC 和REPL_ASYNC,确定改变是应该同步还是异步复制。缺省值是REPL_ASYNC.使用同步复制,确保在请求完成之前传播改变,session同步没有滞后,但效率低。

<config>
<TCP bind_addr="172.16.80.13" start_port="7810" loopback="true"/>
<TCPPING initial_hosts="172.16.80.13[7810],172.16.80.14[7810]" port_range="3" timeout="3500"
num_initial_members="3" up_thread="true" down_thread="true"/>
<MERGE2 min_interval="5000" max_interval="10000"/>
<FD shun="true" timeout="2500" max_tries="5" up_thread="true" down_thread="true" />
<VERIFY_SUSPECT timeout="1500" down_thread="false" up_thread="false" />
     <pbcast.NAKACK down_thread="true" up_thread="true" gc_lag="100"
          retransmit_timeout="3000"/>
     <pbcast.STABLE desired_avg_gossip="20000" down_thread="false" up_thread="false" />
     <pbcast.GMS join_timeout="5000" join_retry_timeout="2000" shun="false"
print_local_addr="true" down_thread="true" up_thread="true"/>
<pbcast.STATE_TRANSFER up_thread="true" down_thread="true"/>
</config>


5. 配置应用程序
在应用程序的/%jboss%/server/default/deploy/jboss-web.deployer/ROOT.war/web.xml文件中的<web-app>段中增加<distributable />。

jboss-web.xml(这个文件在哪个目录,我一直不是很清楚,网上均没有说明是哪个目录中的文件,最后是新生成一个jboss-web.xml,放在与上面的web.xml同目录下)中增加以下内容:

<?xml version="1.0"?>

<jboss-web>

<context-root>trms</context-root>

<replication-config> 

<replication-trigger>SET_AND_NON_PRIMITIVE_GET</replication-trigger> 

<replication-granularity>SESSION</replication-granularity> 

<replication-field-batch-mode>true</replication-field-batch-mode> 

</replication-config> 

</jboss-web>


Apache负载均衡配置

(1)下载且安装。(安装过程略)

Apache Server下载地址

http://httpd.apache.org/download.cgi

Mod_jk下载地址

http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/linux/jk-1.2.31/i386/

(2)修改%apache%/conf/httpd.conf
在文件末尾添加:    Include conf/mod_jk.conf

(3) 在%apache%/conf下新建文件mod_jk.conf

文件内容如下

# Load mod_jk module

# Specify the filename of the mod_jk lib

LoadModule jk_module modules/mod_jk.so

# Where to find workers.properties

JkWorkersFile conf/workers.properties

# Where to put jk logs

JkLogFile logs/mod_jk.log

# Set the jk log level [debug/error/info]

JkLogLevel info

# Select the log format

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

# JkOptions indicates to send SSK KEY SIZE

JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories

# JkRequestLogFormat

JkRequestLogFormat "%w %V %T"

# Mount your applications

JkMount /* loadbalancer

# You can use external file for mount points.

# It will be checked for updates each 60 seconds.

# The format of the file is: /url=worker

# /examples/*=loadbalancer

JkMountFile conf/uriworkermap.properties

# Add shared memory.

# This directive is present with 1.2.10 and

# later versions of mod_jk, and is needed for

# for load balancing to work properly

JkShmFile logs/jk.shm

# Add jkstatus for managing runtime data

<Location /jkstatus/>

JkMount status

Order deny,allow

Deny from all

Allow from 127.0.0.1

</Location>

其中JkMount /* router的意思是,把所有的请求都发给router处理。可以通过修改url来控制发送某些request。

(4) 在%apache%/conf下新建文件workers.properties
    其内容为:

# Define list of workers that will be used

# for mapping requests

worker.list=loadbalancer,node1,node2

# Define Node1

# modify the host as your host IP or DNS name.

worker.node1.port=8009

worker.node1.host=192.168.80.13

worker.node1.type=ajp13

worker.node1.lbfactor=1

worker.node1.redirect=node2

# Define Node2

# modify the host as your host IP or DNS name.

worker.node2.port=8009

worker.node2.host= 192.168.80.14

worker.node2.type=ajp13

worker.node2.lbfactor=1

worker.node2.redirect=node1

# Load-balancing behaviour

worker.loadbalancer.type=lb

worker.loadbalancer.balance_workers=node1,node2

worker.loadbalancer.sticky_session=0

#worker.list=loadbalancer

# Status worker for managing load balancer

worker.status.type=status

其中对于node的命名规则是worker.节点名.xxxx。所以上述文件定义了两个节点:node1和node2。8009端口是jboss 默认的ajp端口,另外需要注意的是worker.node2.lbfactor参数,它是节点的负载加权,它的值越大,获得负载的机会就越大。可以根据 node的硬件性能进行调整。worker. router.sticky_session参数是指定是否使用粘性session。配置了http session复制就可以不需要粘性session。上面配置的是不使用粘性session。worker.server1.redirect=为 failover转移到哪个worker

(5) 配置JBOSS支持粘性mod_jk
修改$JBOSS_HOME/ server/default/deploy/jboss-web.deployer/META-INF/jboss-service.xml

<attribute name="UseJK">false</attribute> 改为ture

(6) 配置JBOSS支持粘性session
修改$JBOSS_HOME/ server/default/deploy/jboss-web.deployer/server.xml

<Engine name="jboss.web" defaultHost="localhost"> 改为

<Engine name="jboss.web" defaultHost="localhost"  jvmRoute="server1"

注意:jvmRoute的值必须和mod_jk中的节点名字正确对应,否则无法正确路由


测试文件

在%JBoss_Home%/server/default/deploy/jboss-web.deployer/ROOT.war/目录下添加一个新文件夹/test,并在里面添加如下3个jsp文件:


index.jsp

<%@ page contentType="text/html;charset=ISO-8859-1" %> 

<html>

<head>

<title>Test</title>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

</head>

<body onload="document.form.name.focus()">

<br><br><br>

<center>

The host is : <%=java.net.InetAddress.getLocalHost().toString()%><br>

Your session id is : <%=session.getId()%><br>

Your session detail is : <%=session.toString()%><br>

Your session context is : <%=session.getSessionContext()%><br><br>

Please input your name:<br>

<form action="test_action.jsp" method="POST" name="form">

   <input type="input" name="name"/>

   <input type="submit" value="submit">

</form> 

</center>

</body>

</html>

test_action.jsp

<%@ page contentType="text/html;charset=ISO-8859-1" %> 

<html>

<head>

<title>Test Action</title>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

</head>

<%

   String name = request.getParameter("name");

   session.setAttribute("name",name);

   String host = java.net.InetAddress.getLocalHost().toString();

%>

<body>

<br>

<br>

<center>

The host is : <%=host%><br><br>

Your session id is : <%=session.getId()%><br>

Your session detail is : <%=session.toString()%><br>

Your session context is : <%=session.getSessionContext()%><br><br>

Your name is : <%=name%><br>

This name is set into the session.<br>

Please click <a href="session.jsp">here</a> to check the session valid or not.

</center>

</body>

</html>

session.jsp

<%@ page contentType="text/html;charset=ISO-8859-1" %> 

<html>

<head>

<title>Test Action</title>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

</head>

<%

   String name = null;

   if(session.getAttribute("name")!=null)

     name = (String)session.getAttribute("name");

   String host = java.net.InetAddress.getLocalHost().toString();

%>

<body>

<br>

<br>

<center>

The host is : <%=host%><br>

Your session id is : <%=session.getId()%><br>

Your session detail is : <%=session.toString()%><br>

Your session context is : <%=session.getSessionContext()%><br><br>

<%

   if(name!=null){

     out.print("Your name is "+name+"<br>");

     out.print("The session is valid.");

   }

   else{

     out.print("The session is invalid!!!");

   }

%>

<a href="index.jsp">Return!</a>

</center>

</body>

<%

   if(session.getAttribute("name")!=null)

     session.invalidate();

%>

</html>


访问方式: http://192.168.80.14/test/index.jsp