JMS基础

来源:互联网 发布:matlab编程实例并解析 编辑:程序博客网 时间:2024/05/22 15:05

         默认情况下,jms发送和接收消息都是同步的,也是主动的,即需要我们显式(主动)sendreceive。同时,规范里定义了一个 MessageListener接口,可以在有消息到达时(异步)被动的处理消息。


       消息传递一个常见场景:   request/response模式不光光是发出去一消息,还要等回来响应的消息。

 

        那么,靠什么机制知道当前发出去的消息已经返回响应了呢?如果发送出去的消息返回响应的时候失败了,会做些什么处理?

       其实我们不光要传递消息,还要保障消息传递的高效和高可靠性。所以,JMS引入了两个概念确认和事务。

       (1) 确认的对象是消息,可以在收取一消息时自动确认。也可在一次会话过程,像jdbc那样,设置一个手动事务,处理完成后,提交,确认所有的消息。

       (2) 遗憾的是,JMS发送不支持事务。淘宝内部的MQ框架,实现了发送的事务性。

 

        那么生产者如何知道的消息发送成功了呢?或者是接收者已经成功接收了呢?

        生产者不知道。生产者和消费者是透明的它们不知道彼此的存在。那生产者需不需要jms server发给他确认消息?这样才知道他的信息已经确实的发出去了啊不然中间丢了咋办?相当于邮局,但是如邮局把你的信件搞丢了,你还是木有办法。其中隐含的一个假设就是,消息一旦发出,我们就完全的信任邮局。我们相信MQ是可靠的。

 

 MQ内部的东西,生产者是看不见的,我们怎么能相信消费者一定能接收到呢?

 我们知道,接收我们信件的人不签收,消息会重新发送,所以,消息可能会在消费者处重复。但是,生产者不知道这个过程消费者获取一个消息,如何没有确认,MQ还会重试再次发送给你可以看做是你没有签收消息,它要给你补发一份。消费者在接受到信息后,发一个确认给jms serverjms server没收到这个确认就在一定的时间内一直发

 

  如果jms server没有可靠性的处理,如果MQ不负责任,把消息放在内存,MQ崩溃后,消息都丢失了怎么办?

 所以,jms规范定义了消息的持久化。把消息分为两种一种是严格的不能丢失的消息,一种是可以偶尔丢失的消息

 前者性能明显会比后者慢,因为后者可以完全在内存处理,系统崩溃时内存中的消息会丢失。前者(转存加发送)需要MQ做持久化,内存放一份,持久化的介质中放一份。然后MQ告诉消息生产者,我接收到了你发送的消息,你放心吧。这比不持久化的消息,明显会慢。消息被消费者消费掉了以后,MQ再从介质中删除掉消息。系统崩溃时也不要紧,重启后从介质中恢复消息。

 queue默认是持久化的topic,默认是非持久化的因为要发送给多个人。

 topic里的消息放在内存里,只发给在线的订阅者如果想要收到topic里所有的消息怎么办呢(LDAP那样,把上次同步数据后的数据都给我)这时,又有一个新的概念了,持久订阅。你可以想象成,你在线期间,你接收了第123条数据。你掉线了,不在线期间,系统里多了第45条数据,发送给所有的订阅者后,删除了。 你又上线了……你想要你上次获取的最后一条数据后的第45条数据这个是MQ里比较麻烦的地方。原理就是同时持久化订阅者和topic的消息。

     我持久订阅了后长期不上线,咋整?我几年都不上线.那得保留多少消息....总不能我不上线耗费了服务器的所有存储空间吧

 有可能。这个就是持久订阅不常用的原因之一吧。持久订阅还有一个问题是,你断线以后,再连上jms serverserver怎么知道你是以前的那个你呢?跟httpsessionid一个道理。你每次来,都用一个相同的clientid就成了。MQ把持久订阅者的信息存到本地,在其不在线期间,也把它当做一个订阅者,把该发给它的消息持久化到存储。等这条消息被所有的持久订阅者确认后删除。所以,MQ还需要持久化确认的数据。因为对有持久订阅的TOPIC来讲,可能有些持久订阅者上线拿到数据并确认了,有些木有确认。

 

Queue还是Topic?

我的建议是尽量用queue.如果你的项目用到了JMS,那么你的系统也应该用到了broker集群配置了。topic在集群环境下会带来很多麻烦的问题。

那么,如果不用topic的话,怎么来实现topic这种性质的消息处理呢?可以写一个消息转发器, 把一个queue上的消息转发给所有关注这个queue的其它queue例如,有一个queue,名为SampleQ1,一个消息发送者sender,一个消息转发器router,有三个handler A,B,C需要处理这个queue中的消息.那么,sender发送消息到SampleQ1,router接收SampleQ1的消息后分别发送到SampleQ1_A,SampleQ1_B,SampleQ1_C,handler A,B,C分别从队列SampleQ1_A,SampleQ1_B,SampleQ1_C中接收消息.

  

 可靠的原则是宁可重复也不少发,存入持久化保证安全,数据被消费后才能丢弃。

  可靠天生就和高可用是冲突的。所以,优化JMS性能的几个要点就是根据使用的场景,在可靠性和高性能之间做出权衡:
 1、优化存储
 2、优化确认
 3、尽量快速的消费掉消息
 4、尽量异步处理消息 

    

处理消息永远比发送消息慢!

要保证你的JMS应用稳定的运行,那么你必须在开发,部署的时候时刻重视这个问题.

首先,需要把发送消息的连接池与接收消息的连接池分开.以避免接收消息的连接过多而导致发送消息的应用拿不到连接.在一个连接上并发的处理消息,而不是连接打开,处理一个消息,马上关闭连接.

合理的设置消息的过期时间,否则消息日积月累,最终超出queuesize

对于非关键业务的消息处理,可以采用异步处理的方法: 接收到消息后并不是立刻处理,而是放到一个任务池或者线程池中处理.

如果消息处理失败,则把消息重新发送回队列中.

 

影响ActiveMQ性能的几个重要因素

Queue
1Send/dispatch Async 影响非常大

     同步异步的发送和投递,都非常影响吞吐量。另外,SystemUsagePFC流控对同步发送有直接影响。
2Not transacted 去掉了记录redo日志
3Auto_ACK/Optim_ACK 优化确认,减少交互次数
4Non-persistence 持久化消息,跟下面几点有关

    持久化和非持久化,也是数量级的影响,毕竟为了提高可靠性,使用数据库或文件来存消息,开销非常大。
5pendingQueuePolicy/vmQueueCursor 决定了消息存储+发送模式,影响很大

     内存最快,文件和jdbc方式更安全,但是非常慢。。。
6producerFlowControl/memoryLimit  可能会直接blockproducer

      vmCursor+非持久时,直接变成一个内存MQ,为了不爆掉jvm,在消息积压到指定数量的时候,PFC会阻止生产消息。
7fast/slow consumer      决定了消息处理模式,跟上面几点有关系。

8、在connectionconnectionFactory上关闭掉 copyMessageOnSend

<!--StartFragment -->

根据JMS规范,消息是不可变的。send的时候,会自动的添加一些属性。有时候,可能会重用,或者多线程处理。为了不影响消息的不可变性,发送的时候,先复制一份,这样,发送时处理的消息对象和你的代码持有的消息对象,是两个不同对象了。相互之间就不会互相影响了。
一般情况下,这个选项可以关闭,从而获得一定的性能提升。

9consumer端,获取消息时候的prefetchSize设置。 一定范围情况下,一次预获取越大,总体性能越好。

 


提问时间
问题2:使用mq的典型场景

系统间集成传递数据,同步转异步。甚至可以用来做通知。其实可以把MQ看做是BlockingQueue 的一个自然的延伸。 

MQ最大的作用是(解耦系统间的依赖关系)(缺2张图)

 

问题3MQ存在单点问题么?

一个很明显的缺陷就是,引入了一个单点。如果中间的MQ挂了,那么所有的系统都不能交互了。 但是mq一般都可以集群,或者做master-slave。集群的主要目的是负载均衡还是灾难恢复抑或两者皆有。有多种集群方式。针对各种场景。master-slave,是针对 disaster recovery的。


问题3springmq相关的实现嘛?

spring好像没有mq,spring下有个spring-jms的子项目。跟springjdbcsupport的功能差不多。封装了一些jms的常用操作。这个是spring的强项。spring很少做轮子。一般是集成, spring是到处做别人的东西到spring的适配。

感兴趣的人请关注:http://code.google.com/p/activemq-store-mongodb/


完。感谢 ,谢谢大家~^_^ActiveMQ研究群(62835781)更多0

 

 

 

0 0
原创粉丝点击