实现无session集群的负载均衡

来源:互联网 发布:sql 的not in中的为空 编辑:程序博客网 时间:2024/06/03 16:28

1、安装apache,resin,可以把apache安装在独立的一台服务器上,如果硬件资源有限,也可以与其中一台后端resin装在同一台硬件机上。

2、  下载mod_caucho.so、安装mod_caucho.so模块(插件)。mod_caucho.so是apaceh与resin实现负载均衡的插件。把mod_caucho.so放于apache安装目录的modules目录中。在apache的httpd.conf文件中加:
#

# mod_caucho Resin Configuration

#

LoadModule caucho_module /usr/local/apache/modules/mod_caucho.so

#这里apache安装在/usr/local/apache/里,根据情况自定

ResinConfigServer 192.168.3.158 6802 #注意这里要用具体的IP,曾经试过,apache和其中后端resin安装在同一台服务器上,用localhost会出错,但用具体的IP时就正常了;这里是用于负载均衡的端口,一般为6802。

#这里可以只列出其中一台后端resin服务器的IP和端口,apache会根据以下ressin.conf的配置来获得其它后端服务器的信息。

CauchoStatus yes

<Location /caucho-request>

SetHandler caucho-request

</Location>

到此,通过地址/caucho-status可以检查是否完成安装,出现一个表格显示一些数据就表明安装成功了,一些错误可以暂时不管,因为resin还没有配好,所以会出现一些红色的错误。
3、修改conf/resin.conf文件,配置后端resin服务器。在<server>à<http >标签中加以下代码:

    <cluster>

      <srun server-id="a" host="192.168.3.158" port="6802" index="1"/>

      <srun server-id="b" host="192.168.4.242" port="6802" index="2"/>

   </cluster>

server-id:表示服务器的名称。caucho_module生成的sessionId会以这个名称开头,以区分session的属主。

host:服务器的的IP地址

port:端口

另一台resin服务器的resin.conf加同样的代码。

启动a服务器用: httpd.sh -server a start

启动b服务器用: httpd.sh -server b start

关闭a服务器用: httpd.sh -server a stop

关闭b服务器用: httpd.sh -server b stop



四、启动后端resin服务器

用httpd.sh -server a start启动192.168.3.158服务器

用httpd.sh -server b start 启动192.168.4.242服务器

注意:在192.168.3.158服务器只启动a;在192.168.4.242服务器只启动B。





五、查看配置的状态。

两台服务器都启动后通过/caucho-status查看状态,如果正常相应的服务器会用绿色(ok)显示,如果仍然有问题会以红色(down)显示。

以下是配置正常的截图:

以下是其中一台后台服务器没有配置正确(或关闭)的截图:

至此,没有实现session集群的负载均衡就配置完成了。现在写起来就这么少,真正摸索的时候可花了不少功夫。J

带session集群的负载均衡在以下会继续探讨,这步是最基本的,把这步完成了才能做下面的工作。



以下由官方网站介绍的用来调试负载均衡的方法:

   1. First, check your configuration with Resin standalone.sh. In other words, add a <http port='8080'/> and check port 8080.
   2. Check http://localhost/caucho-status. That will tell if mod_caucho has properly connected to the backend Resin server.
   3. Each srun host should be green and the mappings should match your resin.conf.
   4. If caucho-status fails entirely, the problem is in the mod_caucho installation and the Apache httpd.conf.
   5. If caucho-status shows the wrong mappings, there's something wrong with the resin.conf or the pointer to the backend server in httpd.conf.
   6. If caucho-status shows a red servlet runner, then Resin hasn't properly started.
   7. If you get a "cannot connect to servlet engine", caucho-status will show red, and Resin hasn't started properly.
   8. If Resin doesn't start properly, you should look at the logs in resin-3.0.x/log. You should start httpd.sh -verbose or httpd.exe -verbose to get more information.
   9. If Resin never shows a "srun listening to *:6802" line, it's not listening for connections from mod_caucho. You'll need to add a <srun> line.
  10. If you get Resin's "file not found", the Apache configuration is good but the resin.conf probably points to the wrong directories.

      二、带session 集群的负载均衡配置

      前面已经配置好不带有session 集群的负载均衡了,这时候我们的基本任务就已完成了。但不带session 集群的负载均衡还不是最完美的,当其中一台服务(A)停止响应而将请求交给另外一台服务器(B)处理时,由于不能保存前一台服务器(A)的session,导致所有保存在在A服务器session中的信息都会丢失,这虽然比没有实现负载均衡前打不开网站要好很多,但我们的要求不应就此满足,我们要实现多台服务器之间无缝转接,要让客户端不会觉察到服务器端所做的变动。这时候就需要实现session的集群了(其实还可以通过数据库的方式实现,由于随着并发量的提高,可能会出现数据库的瓶颈,因此我不建议使用这种方法)。Resin已经可以支持这一功能了。下面会介绍这种实现的原理,知道实现原理,我们做起事件来才会事半功倍。如果暂时不想知道这些原理,只想知道如何配置,可以跳过这些原理的说明。

      1、原理说明

       首先要说明点实现分布式session的很基本的前提------序列化。resin分布式的session是基于java序列化机制来保存session的,因此应用程序的对象必须要实现java.io.Serializable这个接口,这样分布式的session才能正常的工作。也就是说放在session里的对象必须是实现了java.io.Serializable这个接口的。

      以下说明请求session的两种方式:普通的请求方式和高效的请求方式

          普通的请求方式

          首先,在session集群中,每台服务器会以另一台服务器作为它的备份服务器,当session的值有改变时,除了在本服务器上保存新的session外,还会把这些更新发送给备份服务器,,在备份服务器上也保存一份session,当服务器重启后,会查找备份服务器中的session来更新自身的session。

      要看清楚集群式的session是如何工作的,可以看作负载均衡器是随机的发送一个请求到后端集群服务器中其中一个服务器的。服务器C拥有一个当前的session,但负载均衡器把请求转发给了A,在以下的示图中,这个请求将会修改这个session的值,因此在这里除了要加载这个session之外,还要保存这个session的值。

      session ID会包含有当前服务器的信息,举个例子,一个sessionID值为ca8MbyA,分析后知道这个session在C,同时resin也可以通过cookie知道备份session所在的服务器,A必须知道每一个cookie所反映的session所在在的服务器,以便跟这些主机进行通信。以上的示例的配置定义了所有A需要知道的服务器群。如果C发生了故障,A可以通过这个配置为ca8MbyA找D作为C的替代。

      当请求过来时,A会向C发出请求获取session的序列化数据(2:load),由于A不会缓存C的session的数据,针对每一个请来它必须向C获取最新过session数据。由于请求都只是读取数据,A唯一要做的事情是基于TCP协议的加载,会跳过第3—5步。但如果设置了always-save-session,将会执行保存的动作,也就是会执行3—5步。

      在请求的最后,A会把session的所有修改提交给C(3:store)。如果设置always-save-session为false,session并未做任何改动时,这一步会跳过。A把最新的序列化后的session内容提交给C。C把这个session保存到本地的硬盘(4:save),并且保存到备份的D(5:backup)。

      高效的session请求方式(sticky-Session)
      实现了sticky-session的高效的负载均衡器会改进session的处理方式。拿以上的请求来说,很大的代价将会花在网络的流量上,也就是花中第2(load)、第3步(store)中。高效的负载均衡器会避开第2、3步。看以下图示:


      举个例子,一个sessionId为caaMbyA的session,这个session是属于C,C直接把session提供给请求的servlet,不需要再经过A,不需要任何额外的工作,也不需要占用网络带宽。对于一个只读的请求,不需要任何的session集群的管理的成本。因此一个高效的负载均衡器会在这方面提高执行效率(apache就是采用这种方式)。通常的浏览器会没有任何session集群的管理成本,但AOL浏览器会采用non-sticky-session的处理方式,也就是上面所提到的那种方式。

      Session的恢复

      当C由于某些原因需要重启,重启后,C必须要使用最高版本的session,但它自身保存在文件中session很可能已经不是最新的了。这时候会怎样处理呢?当一个“新的”session请求到来时,C会从D加载备用session,D的会是最新版本的session。一旦最新的session被加载后,C就会正常工作,不会让人感觉到它重启过。

      2、配置

      (1)、配置session集群服务器。session的集群在<server>这个tag里配置。使用的标记是<srun>,这个标签在服务器的

      <cluster>标签里。用如下的设置:

      <server>

        <cluster>

          <srun id="a" host="192.168.0.1" port="6802" index="1"/>

          <srun id="b" host="192.168.0.2" port="6802" index="2"/>

          <srun id="c" host="192.168.0.3" port="6802" index="3"/>

      <srun id="d" host="192.168.0.4" port="6802" index="4"/>

      </cluster>

        <persistent-store type="cluster">

          <init path="cluster"/>

        </persistent-store>

      其实<cluster>就是共用之前我们设置好的配置。

      (2)、配置序列化session。在<web-app>标签里加上以下的配置:
      <web-app id='/foo'>

      ...
        <session-config>

          <use-persistent-store/>

        </session-config>

      ...

      </web-app>

      (3)、设置always-save-session

      分布式的session必须要知道session什么时候做了修改,以便保存新的session值。尽

      管resin知道应用程序什么时候调用了Httpsession.setAttribute方法,但它不清楚session

      内部的值是否已经被改变。用以下的例子说明这一点:

      Counter.java

      package test;

      public class Counter implements java.io.Serializable {

        private int _count;

        public int nextCount() { return _count++; }

      }

      把一个Counter对像做为session的一个attribute,resin不知道应用程序什么时候去调用

      nextCounte方法,它不能知道_count的值是否已经有了改动,resin不会去备份这个新的

      session,除非设置了always-save-session,当always-save-session为true时,resin会在

      每一个请求时备份session。因此为了保存最新的session值,<session-config>的配置还需要加上<always-save-session/>这一行。

      设置如下:

      <web-app id='/foo'>

      ...

      <session-config>

        <use-persistent-store/>

        <always-save-session/>

      </session-config>

      ...

      </web-app>

      

      附:

      使用apache与resin实现负载均衡的原理

      当使用apache作为web服务器时,mod_caucho.so所做的工作是实现负载均衡.它发挥的作用是相当于硬件或resin的LoadBalanceServlet的负载均衡的作用。

      要理解resin怎样通过插件实现负载均衡,知道mod_caucho.so如何分发请求到后端JVM是很重要的。以下的几点顺序说明了一个典型的请求。

      1、请求到达apache。

      2、mod_caucho.so验证这个请求是否属于由resin来处理。

      3、mod_caucho.so选择一个后端JVM,来处理请求。正常情况下分两种情况:

         A、如果这是个旧的session,会把请求发送到拥有这个session的JVM。(这是通过cookie里的sessionid来确定去到哪一个JVM的)

         B、如果这是一个新的请求,根据轮循的原则,把请求发送到其中一个JVM。

            注:经测试后发现,如果有一个旧的session,它的属主服务器(A)当机,不接受请求了,这个时候插件会把这个请求转给另一台服务器(B),在这个时候,如果session没有实现集群,实现多台服务器之间session同步,那么将会在另一台服务器(B)上建立一个新的session,原来的登录等信息将会丢失(但这比不能访问网站相比,这已是很大的进步了)。这时候尽管这个session属于A,但这时候请求还是会转发给B处理。如果A又重新正常工作了,这时候原来属于A的请求又会回归到A处理,不会再交给B处理了,这时候如果在B里又保存有登录信息,那么转移给B后,这些信息又会丢失了(大家想想,假如在A发生故障,这时候请求提由B处理,几分种后又恢复正常了,请求又交回给A处理,然后几分钟后A又当机了,请求又会再交由B处理,整个过程的时间在session超时的时间内,那么第二把请求转发给B处理时,是否还需登录呢?答案是不需要的,因为没有B里session没有超时,仍然保存着上一次登录的session,但如果A正常的那几分钟对session作了修改,那么将不会反映到B里。这是经过测试得出的结论)。换句话说,正常情况下插件按照sessionid的值自动把请求发送给相应的服务器,在其中一台服务器当机时,这个规则就会被打破。sessionId为AsessionIdvalue的请求不一定只能由A处理,sessionId为BsessionIdvalue的请求不一定只能由B来处理。另外要注意的一点是,由A转到B的时候,在交接过程中,会出现短暂的中断,这点暂时不清楚原因,仍需要进一步研究。

      4、mod_caucho.so通过TCP secket把请求发送到后端JVM。

      5、mod_caucho.so接收后端发通过TCP socket送过来的响应。

      mod_caucho.so必须知道哪一个请求应该去到resin,比如,servlet-mappings和jsp页面就应该去到resin。并且它必须知道后端服务器的TCP连接的主机名和端口,是通过<srun>这个标签获取这些信息。/caucho-status这个链接会在一个表格里显示所有的信息。mod_caucho.so通过正在运行的resin服务器获取这些信息。

      如何实现通过sessionId来判断某一请求是由A处理还是由B处理呢?以下介绍这个过程的实现原理。

         为了使同一session保留同一台JVM上,resin会使用服务器的编号来编码cookie的sessionId,用上面的例子,插件会按以下的规则来生成sessionId

      index
     

      cookie prefix

      1
     

      axxx

      2
     

      bxxx

      3
     

      cxxx

      在服务器端,mod_caucho会解码cookie,并把请求发送到正确的服务器。比如sesionId为bX8ZwooOz的请求,将会发送到第二台服务器。基本原理就是这样了。

原创粉丝点击