安怡的相公

前面有光

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 

    都是从网上搜集,再通过自己的实践总结出来的,相信对没做过Load Balancing的同学会有一定帮助。

先来三章概念:

1.     JBoss集群配置概念

JBoss集群(Cluster)是 一组计算机节点的集合,它们作为一个整体向用户提供一组网络资源。一个理想的集群对用户是透明的。用户由单一入口访问集群的资源,从来不会意识到集群中的 节点。在他们看来,集群是一个系统,而非多个计算机系统。集群还应该支持随意增加和减少集群系统的节点,而这同样不会影响到用户的访问。

2.     JBoss集群分类

习惯上,JBoss集群配置的关键是把集群分为高可用(HighAvailability,简称HA)集群和高性能计算(HighPerfermanceComputing,简称HPC)集群两类。HA集群的目标是提高系统的可使用性(availability),即可靠性(reliability)和可维护性(maintainability)。请不要将集群中的可使用性(availability)与UE和交互设计中的可用性(Usability)混淆。HA集群的核心是防止单点失效,这一般是通过失败转移来实现的,即在一个节点失效后由另一个节点接替服务。不丢失用户状态。HA集群的其他主要特性还包括负载均衡、session同步等。我们使用的SQLServer数据库的双机热备和Oracle的RAC都属于HA集群。HPC集群采用并行计算技术提供超大规模计算和存储能力,多数超级计算机都是HPC集群。这不是我们关注的集群。

3.     JBoss集群架构

JBoss集群是HA集群。JBoss集群有2种架构。一是客户端拦截器(Client-sideinterceptor)架构,一是负载均衡器(Loadbalancer)架构。客户端拦截器架构适于用C/S结构,负载均衡器架构适用于B/S结构。本文只叙述负载均衡器架构的JBoss集群。

 

 

负载均衡器架构由负载均衡器和n个集群节点组成。每个节点是一个JBoss服 务器实例。负载均衡器是全局唯一的前置机,全部用户请求都发到负载均衡器,由其转发到各节点。当负载均衡器发现一个节点失效后,会将请求转发到另一个节点 上,从而保证服务得以延续。负载均衡器同时负责加权静态负载均衡调度。总之,负载均衡器的健康程度决定了集群的全局健康度,负载均衡器失败将导致集群全部 失效。这是前置机架构集群的主要潜在问题。

JBoss的负载均衡器架构集群实际是由Tomcat的HTTP集群实现的。JBoss有自己的负载均衡器,但效果不佳,官方文档没有介绍,几乎没有人使用。一般情况下,我们都是采用apache+mod_jk作为负载均衡器。下文叙述的都是基于这种架构。mod_jk是apache的一个插件,负责apache与tomcat之间的通讯,是JBoss集群配置(tomcat集群)的关键。

4.准备环境

文件都上传在金山网盘上

文件名:mod_jk-1.2.28-httpd-2.2.3.so, 访问地址: http://www.kuaipan.cn/file/id_55504313337774089.htm ,访问密码:T5P6iu

文件名: jboss-4.2.3.GA.zip , http://www.kuaipan.cn/file/id_55504313337774088.htm  访问密码:Tt6aA4

文件名:apache_2.2.11-win32-x86-no_ssl.msi,  http://www.kuaipan.cn/file/id_55504313337774087.htm 访问密码:epzU33

如果失效了搜索下面文件名下载:

1)jboss-4.2.3.GA.zip

2)apache_2.2.11-win32-x86-no_ssl

3)mod_jk-1.2.28-httpd-2.2.3.so

5、安装JDK什么的不用说了吧 略过N字

6、安装apache_2.2.11-win32-x86-no_ssl

  安装无非就是下一步下一步,不过有几点要注意:

  1)路径不要有中文,不要空格(地球上的程序员都知道)

  2)apache安装时提示占用的端口为80和8080 ,这两个端口都是容易占用的端口,安装的时候最好确保没被占用,

    虽然安装之后可以修改他的端口,但是安装的时候要是被占用,不知道会不会有什么影响。

       正确安装后可以在电脑右下角看到图标,还是先把他关掉吧,下面要做配置了

7、修改apache配置文件

  1)、找到安装apache时的目录下 conf/httpd.conf文件,在最后一行添加 Include conf/mod_jk.conf

  2)、把mod_jk-1.2.28-httpd-2.2.3.so 文件 更名为 mod_jk.so后,复制到安装目录下/modules文件夹中。注意同目录下有个manual,不要搞错了。

  3)、在 conf文件夹下新建文件mod_jk.conf

     文件内容 

     mod_jk.conf
# Load mod_jk module. Specify the filename
# of the mod_jk lib you’ve downloaded and
# installed in the previous section
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 indicate to send SSL KEY SIZE,
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
# JkRequestLogFormat set the request format
JkRequestLogFormat "%w %V %T"
JkMount /* loadbalancer 

 

            或者我网盘中也有 mod_jk.conf    http://www.kuaipan.cn/file/id_55504313337774090.htm 访问密码:ejLrRQ

  4)、在conf文件夹下 新建文件 workers.properties

    

workers.properties
worker.list=loadbalancer,node1,node2

# Define the first node...
worker.node1.port=8009
worker.node1.host=10.0.0.114
worker.node1.type=ajp13
worker.node1.lbfactor=1
worker.node1.local_worker=1
worker.node1.cachesize=10
worker.node1.cache_timeout=600
worker.node1.reply_timeout=100
worker.node1.socket_timeout=300

# Define the first node...
worker.node2.port=9711
worker.node2.host=10.0.0.114
worker.node2.type=ajp13
worker.node2.lbfactor=1
worker.node2.local_worker=1
worker.node2.cachesize=10
worker.node2.cache_timeout=600
worker.node2.reply_timeout=100
worker.node2.socket_timeout=300


# Now we define the load-balancing behaviour
worker.loadbalancer.type=lb
worker.loadbalancer.balanced_workers=node1,node2
worker.loadbalancer.sticky_session=0 
workers.properties中的属性解释,很重要
reply_timeout:此属性告诉web server在接到远端的Tomcat已死并实时的切换到集群中的另外一个Tomcat的回应之前等待一段时间。默认情况下web server将永远等待。属性值为web server要等待回应的时间(以ms为单位),所以如果具有运行时间较长的servlet时设置其值要小心。此属性在jk 1.2.6版本被增加进来,以求避免Tomcat的死机和在支持ajp13的servlet引擎上发生的问题。此属性默认为失效的。



cache_timeout:本属性用于声明JK在cache中保留一个打开的socket的时间,它对减少web serer的线程数有所帮助。众所周知,一个身背重负的web server(例如apache)建立childs/threads来处理负载,而当负载减少时它将销毁无用的childs/threads。每个 child在转发请求给Tomcat时要打开一个ajp13连接,而在Tomcat那一端也将建立一个ajp13线程与之通讯。



socket_timeout:此属性说明连接在未激活的状况下持续多久,web server将主动切断之。这是一个使Tomcat端的陈旧线程不致过多的好方法,但是也带来了在下一次请求到来时需要重新打开socket的开销。此属性与cache_timeout有类似的功效,但是它工作在non-cache模式。


本例采用一台计算机同时启动2个jboss的方案实现的。所以ip一样,AJP/1.3端口不一样。JBoss的Web集群使用apache的 mod_jk,浏览器请求apache服务器,apache服务器根据workers.properties中的配置进行request分发,apache服务器和Jboss中的Tomcat可以用ajp1.3进行通信的,request通过ajp1.3协议的包装被发送到 Jboss,Jboss执行后返回结果。

其中对于node的命名规则是worker.节点名.xxxx。所以上述文件定义了两个节点:node1和node2。8009端口是jboss默认的ajp端口,另外需要注意的是worker.node2.lbfactor参数,它是节点的负载加权,它的值越大,获得负载的机会就越大。可以根据node的硬件性能进行调整。

上面的文件中配置了两个节点,name分别为 node1,node2,指定两个节点的IP,并在worker.loadbalancer.balance_workers中指定所有的node列表,worker.loadbalancer.sticky_session设置是否启用“粘着的”Session,sticky session是指来自同一IP的请求将被发送到同一个Jboss节点,sticky session设为0的话同一session的不同请求会被负载均衡分发到不同的jboss节点上。 

   5)、在conf/目录创建新文件uriworkermap.properties 内容如下

uriworkermap.properties
/jmx-console=loadbalancer
/jmx-console/*=loadbalancer
/web-console=loadbalancer
/web-console/*=loadbalancer 

   至此apache的配置基本结束唯一剩下的就是workers.properties中节点的IP还需要根据之后的部署环境来改变

8、Jboss集群节点配置

  1) 修改 JBOSS_HOME/server/all/deploy/jboss-web.deployer/server.xml

     将Engine 修改如下:<Engine name="jboss.web" defaultHost="localhost" jvmRoute="node1"> 

       这个node1 应该是与workers.properties中节点名字一样,还有一个jboss 就应该是node2了。

  2)修改  JBOSS_HOME/server/all/deploy/ jboss-web.deployer/META-INF/ jboss-service.xml

    找到<attributename="UseJK">改为:<attribute name="UseJK">true</attribute>  

9、部署(到此关于负载均衡的配置就结束了。当然还差一点点,关于session的复制,稍后再说,先把基本的跑起来。)

     1)部署之前先把之前的workers.properties 中的两个ip改成待部署的两台服务器的ip 和端口,注意 文件中设置的端口并非server.xml        中的TCP端口,而是下面一点的AJP端口

     2)启动你的Apache服务器 必须先启动Apache

     3)启动jboss 这边要注意了 启动时一定要这样启动:  搞一个快捷方式到桌面 ,右键 属性 在目标中 加上参数  -c all -b xxx.xxx.xxx.xxx(jboss所在服务器的ip)

10、部署完也该测试下

  1)测试的话自己建个web程序,然后写个servlet 打印一句话,然后把web工程放到jboss/server/all/frame/下 ,

    这样两个jboss下就都有了,如果不行再放一次,然后重启jboss。

    2)访问 http://localhost:<port>/    port  是apache的端口,不要访问错了。首先应该可以看到jboss的欢迎页。

    如果可以看到,那应该没问题了,可以把和apache在同一服务器的那个jboss关掉,如果还可以访问,说明99% OK

    3)进一步测试, 访问你之前写的那个servlet, 它打印的语句应该分别在两台服务器的jboss控制台中轮流显示。

11、Jboss集群的session复制

    集群的缺陷和粘着session

  截止到现在,Jboss集群工作得很完美,除了session。

    目前配置的Jboss集群中,各节点是被动的、相互独立的,相当于增加了节点状态检测的DNS轮询,所以session也是相互独立的。当同一用户的2个请求被转发到不同的Jboss    节点  上时,会出现session信息假”丢失”的现象。

    为此,Jboss提出粘着session(stickysession)概念。使用粘着session后,来自同一IP的请求将被发送到同一个Jboss节点,从而保证session使用的连续性。如果应用中没有   使用  session,则可以使用非粘着session的jboss集群。这样,负载分布更为合理。

  设置方法是编辑负载均衡器的/usr/local/apache2/conf/workers.properties的worker.loadbalancer.sticky_session。设置为1使用粘着session,设置为0不使用粘着session。

  使用粘着session还存在一种隐患,当某个节点发生故障时,该节点的session将全部丢失。要彻底解决这个问题,就要用到jboss session复制

   Jboss session复制原理

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

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

  

12、配置Jboss节点

  JBOSS_HOME/server/all/deploy/jbossweb-cluster.sar/META-INF/jboss-service.xml,

  找到<attribute name="ClusterConfig">,有udp和tcp两种方式,任选一种即可,将bind_addr改为本机ip,

  <tcpping initial_hosts 值设为:node1 IP[7810],node2 IP[7810] ;

     找到 server/all/deploy/tc5-cluster.sar/META-INF/jboss-service.xml

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

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

·  

·   将全部down_thread和up_thread的false都改为true. 

·  

· 在<tcp bind_addr=后填入本机的IP,比如<TCP bind_addr=

·  

· 在<tcpping initial_hosts=后填入本机和集群其他全部Jboss节点的IP[7810],比如

  <tcpping initial_hosts=192.168.130.95[7810],192.168.130.99[7810],192.168.130.112[7810]></tcpping> 

· 

其他参数还包括:

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

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

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

在应用程序的web.xml的<web-app>段中增加<distributable />,如下所示:

<?xml version="1.0" encoding="UTF-8"?>  

<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee ;    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd ;">  

<distributable />  

</web-app>

在web-inf中添加jboss-web.xml文件,内容如下:

<!DOCTYPE jboss-web PUBLIC  

    "-//JBoss//DTD Web Application 4.2//EN"  

    "http://www.jboss.org/j2ee/dtd/jboss-web_4_2.dtd">  

<jboss-web>  

    <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>  

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

</jboss-web> 

 

13、测试session 复制

新建servlet  然后下面是测试的代码

testSession
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class testSession
 */
public class testSession extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public testSession() {
        super();
        // TODO Auto-generated constructor stub
    }

  
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        synchronized (request) {
            doPost(request, response);
        }
        
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Object o =  request.getSession().getAttribute("index");
    if(o==null){
        request.getSession().setAttribute("index", 1);
        System.out.println(1);
    }else{
        request.getSession().setAttribute("index", new Integer(o.toString()).intValue()+1);
        System.out.println(request.getSession().getAttribute("index").toString());
    }
    
    
    }

}

 

 

 

      红色字都是满重要的地方,或者是我在看网上资料是含糊不清的地方,在此做下总结。方便以后工作。

 

posted on 2012-12-09 01:19  包子先森  阅读(2312)  评论(3编辑  收藏  举报