天天看点

JBoss企业级应用服务平台群集指南(七)第二部分

    在章节 5.3中, “在mod_jk中配置工作节点”, 我们涵盖了如何使用”会话粘贴”,以确保为了维持会话状态客户在一个会话上总是请求相同的服务节点。可是, 它并不是完美的。随着时间的过去,在所有分布式节点上的负载可能是不平均,如果一个节点当掉(关闭了),那么在它上面的所有会话数据就丢失了。一个更好和更可靠的办法就是在集群中的所有节点之间复制会话数据。这样,客户可以连接到任何服务节点上,并获得同样的会话数据。

    jboss.cache:service=TomcatClusteringCache MBean在JBoss Tomcat集群的HTTP负载平衡中使用JBoss缓存提供HTTP会话复制服务。该MBean已经在deploy/tc5-cluster.sar/META-INF/jboss-service.xml文件中定义。

注意: 

    在AS 4.0.4 CR2以前, HTTP会话缓存配置文件是deploy/tc5-cluster-service.xml文件. 更多的细细请见AS 4.0.3的文档

  下面是一个典型的deploy/tc5-cluster.sar/META-INF/jboss-service.xml 文件。在TomcatClusteringCache MBean中这个配置属性与部分 2, “JBossCache配置”非常相似。

<mbean code="org.jboss.cache.aop.TreeCacheAop" 

name="jboss.cache:service=TomcatClusteringCache"> 

<depends>jboss:service=Naming</depends> 

<depends>jboss:service=TransactionManager</depends> 

<depends>jboss.aop:service=AspectDeployer</depends> 

<attribute name="TransactionManagerLookupClass"> 

org.jboss.cache.BatchModeTransactionManagerLookup 

</attribute> 

<attribute name="IsolationLevel">REPEATABLE_READ</attribute> 

<attribute name="CacheMode">REPL_ASYNC</attribute> 

<attribute name="ClusterName"> 

Tomcat-${jboss.partition.name:Cluster} 

<attribute name="UseMarshalling">false</attribute> 

<attribute name="InactiveOnStartup">false</attribute> 

<attribute name="ClusterConfig"> 

... ... 

<attribute name="LockAcquisitionTimeout">15000</attribute> 

</mbean>

对于TreeCache MBean的详细配置见部分2, “JBossCache 配置”。下面,我们将仅仅讨论与HTTP集群会话复制关联的几个属性。

•  TransactionManagerLookupClass 设置事务管理工厂。默认值是 org.jboss.cache.BatchModeTransactionManagerLookup.。它通知缓存不要参与JTA-specific事务。代替, 它的缓存管理自己的事务以支持细微的卵复制。

•  IsolationLevel 设置隔离级别为更新对于事务处理分布式缓存。有效的值有 SERIALIZABLE, REPEATABLE_READ, READ_COMMITTED, READ_UNCOMMITTED,和 NONE. 这些隔离级别设定与在数据库上的隔离级别是相同的东西。默认隔离值REPEATABLE_READ对于大多数web应用程序是有意义的。

•  CacheMode控制缓存的复制方式。有效值包括 REPL_SYNC 和 REPL_ASYNC, 来确定改变是同步的或者是异步的。使用同步复制确保改变在web请求完成之前传播到集群。然而, 同步复制是非常慢的. 对于异步方式, 你必须应该启用(enable)并调整复制队列。

•  ClusterName指定了缓存所服务的群集的名字。缺省的群集名是 "Tomcat-" 后面跟着当前的 JBoss 分区名。所有节点都应该使用相同的群集名。虽然会话复制能够和 JBoss 的其他群集服务共享同一通道(多点传送地址和端口),复制还是应该有自己的群集名。

•  UseMarshalling和InactiveOnStartup属性必须有相同的值。如果需要使用 FIELD 级会话复制(请参考后面的内容),它们的值必须是 true。否则,它们的缺省值是 false。

•  ClusterConfig配置底层的 JGroups 栈。最重要的配置元素是用于群集通讯的多点传送地址和端口,分别是mcast_addr 和mcast_port。这些值对你的网络该很有用。请参考章节 1, “JGroups 配置”来获得更多信息。

•  LockAcquisitionTimeout 设置等待获得一个锁的最大时间,单位是毫秒。默认值是15000.

•  UseReplQueue 确定当使用异步复制的时候是否激活复制队列。这允许若干缓存更新被绑定在一起提高性能。复制队列的性能由ReplQueueInterval 和ReplQueueMaxElements的性能约束。

•  ReplQueueInterval 指定JBoss Cache 在发送请求到复制队列之前的等待时间,单位是毫秒。

•  ReplQueueMaxElements: 指定JBoss缓存将发送一个更新之前,在复制队列里允许的元素的最大数量。

    要在你的web应用程序中启用集群,你必须在web.xml描述符中声明distributable。这里有一个例子:

<?xml version="1.0"?> 

<web-app    [url]http://java.sun.com/xml/ns/j2ee[/url]="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 

[url]http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd[/url]" 

version="2.4"> 

<distributable/> 

<!-- ... --> 

</web-app>

你可以在jboss-web.xml文件中用replication-config 元素进一步配置会话复制。这里有一个例子:

    replication-trigger元素决定用什么触发一个会话复制(或什么时候会话被认为是 dirty 的)。它有四个选项:

•  SET: 在这个选项下,只有在会话里设置了属性,会话才被认为是 dirty。如果你的应用程序总把改变的写回到会话里,从性能角度来讲这个选项可能是最优化的。如果只从会话里取出一个对象而不把它写回到会话里,对这个对象的修改将不会被复制。

•  SET_AND_GET: 如使用这个策略,所有 get 或 set 的属性都会被标记为 ditry。如果从会话里取出一个对象并修改它,但没有写回到这个会话里,这些修改也将被复制。这个选项对性能有比较大的影响。

•  SET_AND_NON_PRIMITIVE_GET: 这个策略和 SET_AND_GET 相似,除了只有非基本(non-primitive)get 操作被当作 dirty。例如,http 会话请求可能从属性里取出一个非基本对象实例,然后修改了这个实例。如果我们没有指定非基本 get 应该考虑为 dirty,这个修改就不会正确地被复制。这个选项是缺省值。

•  ACCESS: 这个选项表示,只要会话被访问,就把会话标记为 ditry。因为在每个 HTTP 请求的过程中,会话都会被访问,所以会话每次都会被复制。会话实例里的时间戳也会相应地更新。由于复制并没有包括时间戳,其他群集节点的时间戳可能不会被更新。如果 HTTP 请求没有取出或修改任何会话属性,其他节点的会话就可能会先于活动节点过期。当设置了这个选项,会话的时间戳将在所有群集节点中同步。注意采用这个选项对性能影响很大,需要小心行事。

     replication-granularity 元素控制复制单位的大小。支持的选项包括:

•  SESSION: 复制基于每一会话实例。只要当调用 snapshot manager 时它被认为有修改,整个会话对象都将串行化。

•  ATTRIBUTE: 复制仅针对于会话里的 ditry 属性加上某些会话数据,如 lastAccessTime。对于承载大量数据的会话,这个选项可以提高复制性能。

•  FIELD: 复制仅针对于会话属性对象里的数据字段(后面会有更多内容)。

replication-field-batch-mode 指出你是否在每个 HTTP 请求之间进行批量更新。它的缺省值是 true。

    如果你的会话通常很小,使用 SESSION 选项是更好的策略。如果你的会话更大些而且某些部分并不常被访问,ATTRIBUTE 方式的复制就会更有效。如果你的应用程序在会话属性里拥有非常大的数据对象,而且只有这些对象里的某些字段被经常修改,采用 FIELD 策略将是最佳选择。在后面的内容里,让我们讨论一下怎样使用 FIELD 级的复制。

    字段级复制只复制存储在会话里的对象内部的被修改的数据字段。它能够极大地减少群集节点之间的数据通信,也因此提高了整个群集系统的性能。为了使用字段级复制,你首先得用 Java 类来指出哪个字段要被复制。它是通过在 JavaDocs 嵌入的 JDK 1.4 风格的注解(annotations)来完成的:

    为了注解(annotate)你的 POJO,我们提供两个注解方式:@@org.jboss.web.tomcat.tc5.session.AopMarker 和

@@org.jboss.web.tomcat.tc5.session.InstanceAopMarker. 当你用 AopMarker 注解你的类时,你可以指出这个类的实例字段级复制。例如:

/* 

* My usual comments here first. 

* @@org.jboss.web.tomcat.tc5.session.AopMarker 

*/ 

public class Address 

... 

}

   如果你用InstanceAopMarker注解类时,它所有的子类都将自动被注解。例如,

* @@org.jboss.web.tomcat.tc5.session.InstanceOfAopMarker 

public class Person 

当你有一个子类,如:

public class Student extends Person 

    你不需要注解Student。因为它是Person的子类,所以它将自动被注解。

    然而,既然目前我们只支持 JDK 1.4 风格的注解(由 JBoss Aop 提供),你将需要执行一个预处理步骤。在 Java 编译器编译之前和之后,你需要用 JBoss AOP pre-compiler annotationc 和 post-compiler aopc 来处理上面的源码。这里是一个怎样从命令行调用这些命令的例子。

$ annotationc [classpath] [source files or directories] 

$ javac -cp [classpath] [source files or directories] 

$ aopc [classpath] [class files or directories]

    请参考 JBoss AOP 文档关于怎样使用 pre- 和 post-compiler。JBoss AOP 项目也提供使用 ANT 来把上述步骤集成在应用程序的 build 过程中的简单方法。下一个 AS 发布版本将提供对 JDK 5.0 注解的更透明的支持。但是现在,你还得用 pre- 和 post-compiler来编译你的源码。

    或者,你也能够在[url]http://wiki.jboss.org/wiki/Wiki.jsp?page=Http_session_field_level_example[/url]里看到一个怎样构建(build),部署(deploy),和验证(validate)采用字段级复制的 web 应用程序的完整例子。这个例子捆绑了 pre- 和 post-compile 工具,所以你不需要再下载单独的 JBoss AOP 了。

   当你把 web 应用程序部署到 JBoss AS 时,请确保下面的配置是正确的:

•  在服务器的deploy/tc5-cluster.sar/META-INF/jboss-service.xml文件里,inactiveOnStartup和useMarshalling属性必须都为 true。

•  在应用程序的jboss-web.xml文件里,replication-granularity属性必须为 FIELD。

    最后,让我们看一个怎样在哪些数据类上使用字段级(FIELD-level)复制的例子。请注意你不需要在修改数据对象(data object)后调用session.setAttribute(),对字段的所有修改都自动跨群集地被复制了。

// Do this only once. So this can be in init(), e.g. 

if(firstTime) 

Person joe = new Person("Joe", 40); Person mary = new Person("Mary", 30); Address addr = new Address(); addr.setZip(94086); 

joe.setAddress(addr); 

mary.setAddress(addr); // joe and mary share the same address! 

session.setAttribute("joe", joe); // that's it. 

session.setAttribute("mary", mary); // that's it. 

Person mary = (Person)session.getAttribute("mary"); 

mary.getAddress().setZip(95123); // this will update and replicate the zip code.

除了简单的对象(plain objects),你还可以使用那些对象的常规 Java 集合(Java collection)作为会话属性。JBoss cache 会自动地判断怎样处理这些集合和复制它们的成员对象里的字段的变更。

    如果你已经部署和访问了你的应用程序,你可以使用jboss.cache:service=TomcatClusteringCache MBean 和调用printDetails操作。你应该看到下面的输出结果。

/JSESSION 

/quote 

/FB04767C454BAB3B2E462A27CB571330 

VERSION: 6 

FB04767C454BAB3B2E462A27CB571330: 

org.jboss.invocation.MarshalledValue@1f13a81c 

/AxCI8Ovt5VQTfNyYy9Bomw** VERSION: 4 

这个输出结果展示了在一个叫quote应用程序里的两个独立的 web 会话,它们通过 JBossCache 来共享。这个例子使用了session的replication-granularity。如果使用了attribute级的复制,应该可以看到展示每个被复制的会话属性的其他条目。在两种情况下,被复制的值都存储在一个不透明的MarshelledValue容器里。目前还没有任何工具可以让你查看这些被复制的会话值。如果你没有看到任何输出,要么是应用程序没有正确地标记为distributable,要么就是你根本没有访问把值写入 HTTP 会话的应用程序。org.jboss.cache 和org.jboss.web 日志类别提供了可用于调试目的对会话复制的其他视角。

    JBoss 支持群集的单点登录(single sign-on),允许用户在一个 JBoss 服务器上验证应用程序,然后被在同一个主机或群集里的其他节点里的被部署在同一个虚拟主机上的所有应用程序识别。HTTP 会话复制服务处理复制验证(Authentication replication)。虽然会话复制不需要显性地为这个应用程序启用,但 tc5-cluster-service.xml 文件必须被部署。

    为了启用单点登录,你必须在tomcat server.xml文件的Host元素里加入ClusteredSingleSignOn开关(valve)。这个开关(valve)的配置如下:

<Valve className="org.jboss.web.tomcat.tc5.sso.ClusteredSingleSignOn" />

本文转自xudayu 51CTO博客,原文链接:http://blog.51cto.com/xudayu/67634,如需转载请自行联系原作者