记录在Sungard工作时对ejb3.1的研究(2)--ejb3 集群(ejb timer/MDB)

以前和人家谈论sungard的工作时,总是被质疑:"你们还在使用ejb啊?太老了吧". "早就是spring的年代了". 我总是反击,你们真的了解ejb吗?了解ejb在分布式应用里集群部署和spring比较有多方便吗?不要总是把什么IOC, AOP肤浅的挂在嘴上, 现在早已不是ejb2的时代了. ejb3 dependency injection也很容易,除了在非javaee容器管理的资源里受限(需要借助javaee6 CDI). AOP?ejb也有intercepter, transaction management? ejb CMT更simple. opensessioninviewfilter? 嗯这个真是一个很好的practice吗?自己实现一个也不难. ejb3.1有不弱于quartz的timer service, singleton bean, 异步bean等等feature,你们都了解吗?好了牢骚发到这儿,这里没有贬低spring的意思,我也承认spring的生态圈更加为大家所接受而且发展更快,只是在贬低一门技术的时候,你得先问下自己,我真的了解它的方方面面吗?

考虑如下的场景,我们的分布式系统里有8个节点,其中1个节点作为primary node, 启动定时任务, 然后发布需要处理的data. 需要8个节点同时取得data pool里的数据, 使用ejbtimer+MDB集群就很容易实现.架构图大致如下:(这里借用自己presentation的一张图.可以把左半边看成primary node, 右半边看成MDB集群同时取data pool数据并且消费)

好了,这里左半边我们create 1个timer service, 并且发送data到queue里. 同时,我们create一个temporary reply queue作为replyTo并且创建一个listener.MDB集群消费queue里的message并且发回到reply queue.

问题是ejb timer。这里我们需要解决的问题是:

1) timer只能有1个instance, 否则集群里每个节点都启动timer就会有问题

2) timer需要支持HA

3) 进1步,我们需要支持多个集群里只有1个timer instance

对于JbossAS6 里的timer service, cluster支持并不完美。可以把timer部署成1个HASingleton bean以支持HA,fail over和one instance. 创建jboss.xml在meta-inf下

<?xml version="1.0" encoding="UTF-8"?>
<jboss
        xmlns="http://www.jboss.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee
                            http://www.jboss.org/j2ee/schema/jboss_5_1.xsd"
        version="5.1">
     <enterprise-beans>
          <session>
                <ejb-name>SchedulerManagementServiceBean</ejb-name>
                <depends>jboss.ha:service=HASingletonDeployer,type=Barrier</depends>
          </session>
     </enterprise-beans>
</jboss>

现在启动jbossas6, hasingleton会自己选定一个节点作为primary node并deploy. 问题来了,我们去找SchedulerManagementServiceBean的remote接口时,如果我们不在primary节点, 则会抛错....

这是因为下面的配置:

ejb3-intecepters-aop.xml:

 <stack name="ClusteredStatelessSessionClientInterceptors">
      <interceptor-ref name="org.jboss.ejb3.async.impl.interceptor.AsynchronousInterceptorFactory" />
      <interceptor-ref name="org.jboss.ejb3.remoting.ClusteredIsLocalInterceptor"/>
      <interceptor-ref name="org.jboss.ejb3.security.client.SecurityClientInterceptor"/>
      <interceptor-ref name="org.jboss.aspects.tx.ClientTxPropagationInterceptor"/>
      <interceptor-ref name="org.jboss.aspects.remoting.ClusterChooserInterceptor"/>
      <interceptor-ref name="org.jboss.aspects.remoting.InvokeRemoteInterceptor"/>
   </stack>

其中<interceptor-ref name="org.jboss.ejb3.remoting.ClusteredIsLocalInterceptor"/>会告诉容器,当我们在集群环境寻找remote bean时,任然prefer去当前节点去找!

那么就注释掉这一行,ok问题解决了. 哦对了jndi别忘了用HA port啊(as default, 1100 is the ha port and offset is 100)

最后支持多个集群里一个节点. 当时哪个客户提出需要部署双jboss集群,一台为主一台备份,连接同一个oracle RAC. 问题又来了, 这样同一个环境我们任然会有2个ejb timer启动!

解决方案也很简单,把一个jboss集群下的timer关闭, 并且在这个jboss集群里call timer bean的时候指定jndi为远程的jndi即可:

比如我们cluster1是10.110.173.150(8180,8280.8380,8480)/10.110.173.151(8180,8280.8380,8480), cluster2则是10.110.173.152,10.110.173.153

那么我们可以把cluster2的timer 关闭,并且在每次call SchedulerManagementServiceBean的时候,指定jndi成10.110.173.150:1200;10.110.173.150:1300;10.110.173.150:1400;即可。

关于weblogic timer的集群,下面链接很详细而且HA支持完美,我们只需要默认配置就可以了.

https://blogs.oracle.com/muraliveligeti/entry/ejb_timer_ejb

MDB集群:

JBOSS6 AS, JBOSS7默认的hornetq对message driven bean的集群support很好,无需过多配置.

jboss-6.1.0.Final-GETPAID\server\node1\deploy\hornetq

<!--
  ~ Copyright 2009 Red Hat, Inc.
  ~  Red Hat licenses this file to you under the Apache License, version
  ~  2.0 (the "License"); you may not use this file except in compliance
  ~  with the License.  You may obtain a copy of the License at
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~  Unless required by applicable law or agreed to in writing, software
  ~  distributed under the License is distributed on an "AS IS" BASIS,
  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  ~  implied.  See the License for the specific language governing
  ~  permissions and limitations under the License.
  -->

<configuration xmlns="urn:hornetq"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="urn:hornetq /schema/hornetq-configuration.xsd">

   <!--  Don‘t change this name.
         This is used by the dependency framework on the deployers,
         to make sure this deployment is done before any other deployment -->
   <name>HornetQ.main.config</name>

   <clustered>true</clustered>

   <log-delegate-factory-class-name>org.hornetq.integration.logging.Log4jLogDelegateFactory</log-delegate-factory-class-name>

   <bindings-directory>${jboss.server.data.dir}/${hornetq.data.dir:hornetq}/bindings</bindings-directory>

   <journal-directory>${jboss.server.data.dir}/${hornetq.data.dir:hornetq}/journal</journal-directory>

   <!-- Default journal file size is set to 1Mb for faster first boot -->
   <journal-file-size>${hornetq.journal.file.size:1048576}</journal-file-size>

   <!-- Default journal min file is 2, increase for higher average msg rates -->
   <journal-min-files>${hornetq.journal.min.files:2}</journal-min-files> 

   <large-messages-directory>${jboss.server.data.dir}/${hornetq.data.dir:hornetq}/largemessages</large-messages-directory>

   <paging-directory>${jboss.server.data.dir}/${hornetq.data.dir:hornetq}/paging</paging-directory>

   <connectors>
      <connector name="netty">
         <factory-class>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</factory-class>
         <param key="host"  value="${jboss.bind.address:localhost}"/>
         <param key="port"  value="${hornetq.remoting.netty.port:5445}"/>
      </connector>

      <connector name="netty-throughput">
         <factory-class>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</factory-class>
         <param key="host"  value="${jboss.bind.address:localhost}"/>
         <param key="port"  value="${hornetq.remoting.netty.batch.port:5455}"/>
         <param key="batch-delay" value="50"/>
      </connector>

      <connector name="in-vm">
         <factory-class>org.hornetq.core.remoting.impl.invm.InVMConnectorFactory</factory-class>
         <param key="server-id" value="${hornetq.server-id:0}"/>
      </connector>

   </connectors>

   <acceptors>
      <acceptor name="netty">
         <factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
         <param key="host"  value="${jboss.bind.address:localhost}"/>
         <param key="port"  value="${hornetq.remoting.netty.port:5445}"/>
      </acceptor>

      <acceptor name="netty-throughput">
         <factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
         <param key="host"  value="${jboss.bind.address:localhost}"/>
         <param key="port"  value="${hornetq.remoting.netty.batch.port:5455}"/>
         <param key="batch-delay" value="50"/>
         <param key="direct-deliver" value="false"/>
      </acceptor>

      <acceptor name="in-vm">
        <factory-class>org.hornetq.core.remoting.impl.invm.InVMAcceptorFactory</factory-class>
        <param key="server-id" value="0"/>
      </acceptor>

   </acceptors>

   <broadcast-groups>
      <broadcast-group name="bg-group1">
         <group-address>231.7.7.7</group-address>
         <group-port>9876</group-port>
         <broadcast-period>5000</broadcast-period>
         <connector-ref>netty</connector-ref>
      </broadcast-group>
   </broadcast-groups>

   <discovery-groups>
      <discovery-group name="dg-group1">
         <group-address>231.7.7.7</group-address>
         <group-port>9876</group-port>
         <refresh-timeout>10000</refresh-timeout>
      </discovery-group>
   </discovery-groups>

   <cluster-connections>
      <cluster-connection name="my-cluster">
         <address>jms</address>
         <connector-ref>netty</connector-ref>
          <discovery-group-ref discovery-group-name="dg-group1"/>
      </cluster-connection>
   </cluster-connections>

   <security-settings>
      <security-setting match="#">
         <permission type="createNonDurableQueue" roles="guest"/>
         <permission type="deleteNonDurableQueue" roles="guest"/>
         <permission type="consume" roles="guest"/>
         <permission type="send" roles="guest"/>
      </security-setting>
   </security-settings>

   <address-settings>
      <!--default for catch all-->
      <address-setting match="#">
         <dead-letter-address>jms.queue.DLQ</dead-letter-address>
         <expiry-address>jms.queue.ExpiryQueue</expiry-address>
         <redelivery-delay>0</redelivery-delay>
         <max-size-bytes>10485760</max-size-bytes>
         <message-counter-history-day-limit>10</message-counter-history-day-limit>
         <address-full-policy>BLOCK</address-full-policy>
      </address-setting>
   </address-settings>

</configuration>

唯一需要注意的是,如果同一网段有多个jboss集群,我们需要把组播broadcast-groups,discovery-groups配置成每个集群唯一,否则会互相干扰, hoho...

weblogic里又有不同。weblogic推荐UDD(Unique distributed destination)的配置方式,我们需要建立几个jms server,并且在 ear/meta-inf下create一个weblogic-jms-config-cluster.xml文件.

    <uniform-distributed-queue name="SAMPLEPROB">
        <sub-deployment-name>SubModule-SAMPLE</sub-deployment-name>
        <jndi-name>java:global/queue/SAMPLEDPROB</jndi-name>
        <load-balancing-policy>Round-Robin</load-balancing-policy>
    </uniform-distributed-queue>

同时ejb的meta-inf下create weblogic-ejb-jar.xml:

<weblogic-enterprise-bean>
        <ejb-name>SampleMessageServiceBean</ejb-name>
        <message-driven-descriptor>
            <destination-jndi-name>java:global/queue/SAMPLEDPROB</destination-jndi-name>                <distributed-destination-connection>EveryMember</distributed-destination-connection>          </message-driven-descriptor></weblogic-enterprise-bean> <timer-implementation>Clustered</timer-implementation>

这种方式是在disable weblogic server affinity情况下的集群方式。这里不再介绍server affinity, 以下link更加详细

http://docs.oracle.com/cd/E11035_01/wls100/jms_admin/advance_config.html#jms_distributed_destination_config

如果server affinity is on, 则我们不需要额外再指定<distributed-destination-connection>EveryMember</distributed-destination-connection>

时间: 2024-11-04 21:48:28

记录在Sungard工作时对ejb3.1的研究(2)--ejb3 集群(ejb timer/MDB)的相关文章

mongoDB研究笔记:分片集群的工作机制

上面的(http://www.cnblogs.com/guoyuanwei/p/3565088.html)介绍了部署了一个默认的分片集群,对mongoDB的分片集群有了大概的认识,到目前为止我们还没有在集群上建立其它数据库,mongoDB的分片是基于集合(表)来进行的,因此要对一个集合分片,必须先使其所在的数据库支持分片.如何使一个集合分片?如何选择分片用到的片键?平衡器如何使chunks块在片中迁移?分片的读写情况怎么样?接下来将探讨这些问题. 使集合分片 (1)连接到上面所配置集群中的mon

关于找工作时的境遇与情绪波动

前言:投了很多公司,大公司小公司,在专门的网站上投的基本是石沉大海了,找人内推的还在静候佳音中...大三结束升大四,压力远远不是大二升大三时能够想象的,就业难的问题到底还是重重的压下来了... 正文: 其实说就业难是大环境的一方面,还有同样很重要的一方面就是个人条件,我所谓的个人条件=实力证明+个人能力. 先说实力证明,至少可以追溯到高考,你考取了985,211的学校,在找工作时,就确乎可以得到比别的学校的学生更好的机会.等到了大学,你学习成绩不错,获得了很多奖状:还有兴趣和动力参加各种比赛,如

JS获取时间段内的工作时长

需求 1.给一个开始时间和结束时间: 2.计算在时间段内工作时间长度: 3.工作时间是9点-18点: 4.工作时长是8小时: 5.不记录周六和周日时间: 插件 使用了moment.js 代码 1 function GetWorkHours(beginDateTime, endDateTime) { 2 var _totalHour = 0; 3 //1.获取开始时间和结束时间之间的日 4 var _beginDate = moment(beginDateTime); 5 var _endDate

Ext,保存输入记录并在输入时进行提示

Ext的ComboBox组件用法很多,通过配置可以让其变成一个输入框,并且可以存储输入的记录,然后再之后的输入中根据记录进行提示,以提高输入操作的用户体验. 代码很简单,基本操作如下: // 输入提示 Ext.create("Ext.form.ComboBox", { renderTo: "放置的组件ID", name: "input", labelWidth: 40, width: 400, hideEmptyLabel: true, // 隐

浅谈人们工作时存在的2种思维模式

工作的思维模式分2种:即时回报型和延时回报型. 即时回报型的表现:注重立刻见效的方式,比如刀钝了舍不得花时间磨,提刀急忙去砍柴:比如每天都大老远的去提水,而舍不得花时间和钱去修条水管:比如工作上遇到难题了,直接上网搜答案,而舍不得花时间从基础学起:比如执行某个软件操作时舍不得花时间去找快捷键,每次都从菜单里点. 相对的是延时回报式,表现为:刀钝了就先去磨刀,磨快了再去砍柴:修水管而不是去提水:学习先从基础的开始:注意使用快捷键. 表现远远不止这些.从表面上看,即时回报的方式短期见效快,长期效率差

make工作时的执行步骤

GNU的make工作时的执行步骤 (1)读入所有的Makefile (2)读入被include的其它Makefile (3)初始化文件中的变量 (4)推导隐晦规则,并分析所有的规则 (5)为所有的目标文件创建依赖关系链 (6)根据依赖关系,决定哪些目标重新生成 (7)执行生存命令 定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标.如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标. 为了避免和文件重名的情况,可以使用一个特殊的标记".PHONY

在汇报工作时,我需要做些什么

最近在更新计划文档或是汇报工作时,总有一些点讲不到位或是遗漏:针对此问题,想了下大概可以从以下几个方面去尝试描述,后续如有新的想法,继续补充. 1.结论.一般给领导汇报工作,首先要把结论说明,然后再详细说明过程,遇到的问题等 2.讲清楚问题 + 优先级高的问题:问题描述清楚,才能让领导更好的分析及判断怎么解决问题,如果连问题都说不清楚,就别提多上火了:另外就是高优先级问题提前识别出来,重点汇报. 3.计划:了解了问题后,就得有明确.详细的解决措施及计划,做定期做跟踪,及时汇报进展.   如果有问

3星|《工作生活双全法则》:我们很容易掉入注重工作时长而非成果的陷阱

工作生活双全法则(<哈佛商业评论>增刊) 工作生活双全法则(<哈佛商业评论>增刊) <哈佛商业评论>讲兼顾工作与生活的3篇文章.总体来说,这在全世界都是个难题.作者的调查和统计结果表明,有些时候工作的压力来自于公司对工作时长的关注超过了对工作成果的关注. 以下是书中一些内容的摘抄: 1:上述两位作者基于对全球4000名高管的访谈,发现成功的高管往往能巧妙地将工作和家庭融合在一起,这样他们就在取得职业成就的同时,保持了与家庭成员的和谐关系.#16 2:最后一点是高管的普遍

找工作时单位普遍要求 35 岁以下,那 35 岁以上的人都干嘛去了?

本文来源于微信公众号:LinkedIn 微信ID:LinkedIn-China LinkedIn领英是全球知名的职业社交网站,每个<财富>500强公司均有高管加入. 1987年,那会,大街上还能买到几毛钱的棒棒冰和1块钱的沙示汽水. 有一名当了5年校办企业经销部业务员的老干部,骑着一辆破旧的三轮车,载着橡皮.作业本.铅笔.汽水和冰棍,奔忙在一次又一次的送货路上. 六月的天气,烈日炎炎,他每次搬汽水都要小心翼翼.因为玻璃瓶一旦碰烂了,他不舍得. 这个小小的经销部,让他见识了从古到今都亘古不变的现