JMS简介
2015-09-03 17:06
344 查看
如果手机只能进行实时通话,没有留言和短信功能会怎么样?一个电话打过来,正好没有来得及接上,那么这个电话要传递的信息肯定就收不到了。为什么不能先将信息存下来,当用户需要查看信息的时候再去获得信息呢?伴随着这个疑惑,短息和留言应运而生,无论手机是否开机、是否未及时接到,我们都能得到其中的信息。JMS提供了类似这样的功能,本章我们将系统的学习JMS中的相关重要内容。
Ø 掌握JMS基本概念及适用范围
Ø 点对点模型与发布/订阅模型的区别和使用场合
Ø 熟悉核心和通用的JMS API
Ø 熟悉并理解JMS客户端开发的步骤
Ø 消息的同步和异步接收的实现方式
Ø 串包问题的解决办法
企业消息系统,即面向消息的中间件(MOM),提供了以松散耦合的灵活方式集成应用程序的一种机制。它们提供了基于存储和转发的应用程序之间的异步数据发送,即应用程序彼此不直接通信,而是与作为中介的MOM 通信。MOM提供了有保证的消息发送,应用程序开发人员无需了解远程过程调用(PRC)和网络/通信协议的细节。ActiveMQ正是MOM中优秀的一员。
企业消息系统的好处
我们先来看看下图,应用程序A将Message发送到服务器上,然后应用程序B从服务器中接收A发来的消息,通过这个图我们一起来分析一下JMS的好处
图 1 JMS通讯示意图
提供消息灵活性
应用程序A与应用程序B通过使用MOM的应用程序编程接口(API)发送消息进行通信。MOM 将消息路由给应用程序B,这样消息就可以存在于MOM中,MOM 负责处理网络通信。如果网络连接不可用,MOM会存储消息,直到连接变得可用时,再将消息转发给应用程序B。
灵活性的另一方面体现在,当应用程序A发送其消息时,应用程序B甚至可以不处于执行状态。MOM将保留这个消息,直到应用程序B开始执行并试着检索消息为止。这还防止了应用程序A因为等待应用程序B检索消息而出现阻塞。
这种异步通信要求应用程序的设计与现在大多数应用程序不同,不过对于时间无关或并行处理,它可能是一个极其有用的方法。
松散耦合
企业消息系统的真正威力在于应用程序的松散耦合。在上面的图中,由应用程序A发送消息指定一个特定目标,如“订单处理”。而现在,是由应用程序B提供订单处理功能。
但是在将来,我们可以用不同的订单处理程序替换应用程序B,应用程序A将不再是明智之选。替换应用程序将继续发送消息完成“订单处理”,而消息也仍将得到处理。
同样,我们也可以替换应用程序A,只要替换应用程序继续发送消息进行“订单处理”,订单处理程序就无需知道是否有一个新的应用程序在发送订单。
在JMS之前,每一家MOM厂商都用专有API为应用程序提供对其产品的访问,通常可用于许多种语言,其中包括Java语言。JMS通过MOM为Java程序提供了一个发送和接收消息的标准的、便利的方法。用JMS编写的程序可以在任何实现JMS标准的MOM上运行。
JMS可移植性的关键在于:JMS API是由Sun作为一组接口而提供的。提供了JMS功能的产品是通过提供一个实现这些接口的提供者来做到这一点的。开发人员可以通过定义一组消息和一组交换这些消息的应用程序,建立JMS应用程序,实现异步通讯。
JMS的目标
JMS从提出以来,致力于完成如下几个目标:
定义一组消息公用概念和实用工具。
所有Java应用程序都可以使用JMS中定义的API去完成消息的创建、接收与发送,任何实现了JMS标准的MOM都可以作为消息的中介,完成消息的存储转发。
最大化消息应用程序的可移植性。
MOM提供了有保证的消息发送,应用程序开发人员无需了解远程过程调用(PRC)和网络/通信协议的细节,提供了程序的可移植性。
最大化降低应用程序与应用系统之间的耦合度。
由于MOM的存在,各个应用程序只关心和MOM之间如何进行消息的接收与发送,而无需关注MOM的另一边,其他程序是如何接收和发送的。
Ø 点到点(P2P)模型
Ø 发布/订阅(Pub/Sub)模型
图 2 JMS通讯模型
从图中可以看出,ClientA和ClientB是消息生产者,通过两种不同的目的地分别向ClientC、ClientD、ClientE和ClientF发送消息。
在ClientA、C、D之间的消息是点对点模型,使用这种模型,客户端发送消息到队列目的地(Queue),从这个队列里面只有一个消息接收者可以收到那个消息,其他访问同一目的地的接收者不会接收到该消息。如ClientC接收Queue中的Msg1消息,ClientD接收Queue中的Msg2消息。
在ClientB、E、F之间的消息是发布/订阅模型。使用这种广播模型,一个客户端发送消息给主题目的地(Topic),任何数量的消费订阅者可以从这个主题目的地来接收它们。如:ClientE和ClientF都接收这个Msg3这条消息。
点到点模型
点对点传递模型:生产者发送消息到一个特定的队列(Queue)中,而消费者从一个消息队列中得到消息,如下图所示:
图 3 点到点通讯模型示意图
点对点模型的特点:
Ø 每条消息有一个消费者
每条只有一个消费者,如果一条消息被消息者接收,那么其他的消费者就不能得到这条消息了。
Ø 发送和接受消息与时间没有关系
也就是说,生产者在发送消息后,消费者可以在任意的时刻接收,但有两个前提:
1、消息未过期
2、消息没有被其他的用户接收
消费者也可以先运行,当生产者一运行,将消息发送到队列中,消费者即可从队列中获得消息,这叫“守株待兔“。
Ø 消费者必须确认对消息的接收
收到消息后消费者必须确认消息已被接收,否则JMS服务提供者会认为该消息没有被接收,那么这条消息仍然可以被其他人接收。程序可以自动进行确认,不需要人工干预。
Ø 非持久的消息最多只发送一次
非持久的消息最多只发送一次,表示消息有可能未被发送,造成未被发送的原因可能有:
1、 JMS服务提供者出现宕机等情况,造成非持久信息的丢失
2、 队列中的消息过期,未被接收
Ø 持久的消息严格发送一次
我们可以将比较重要的消息设置为持久化的消息,持久化后的消息不会因为JMS服务提供者的故障或者其他原因造成消息丢失。
发布/订阅模型
发布/订阅模型:发布/订阅传递消息类型与主题(Topic)有关。生产者发布消息,而消费者订阅感兴趣的消息,生产者将消息和一个特定的主题(Topic)连在一起,消息传递系统(MOM)根据消费者注册的兴趣,将消息传递给消费者。这种类型非常类似出版报纸、杂志的形式,如下图所示:
图 4 发布/订阅通讯模型示意图
发布/订阅模型的特点:
Ø 每个消息都可以有多个(0,1,……)订阅者
每条消息可以有多个消费者,如果报纸和杂志一样,谁订阅了谁都可以获得。
Ø 订阅者只能消费他们订阅之后出版的消息
这就要求订阅者必须先订阅,生产者再发布。即订阅者必须先运行,再等待生产者的运行,这和点对点类型有所差异。
Ø 订阅者必须保持为活动状态才能使用这些消息
即订阅者必须保持活动状态等待发布者发布的消息,如果订阅者在发布者发布消息之后才运行,则不能获得先前发布者发布的消息。
------------------------------------------------------------------------------
ppt下载地址:
http://code.google.com/p/activemq-store-mongodb/downloads/list
下面开始:
kimmking:介绍下jms和ActiveMQ。在讲JMS之前,我们聊聊相关的背景。谁知道JMS是什么意思?
kimmking:对,是message service。那,什么事message呢?嗯,对了,就是信息。
kimmking::所有的信息,我们都可以说是消息。
kimmking:前提是,它必须是动态的,可流动的,或者说是可传递的。这个过程,就是messaging
大家:请问jms的消息传递跟常用的通信协议有什么区别?
答:通信协议一般是针对一种具体的通信业务场景,制定了一个规定。是多方都需要遵守的。而jms消息机制,在更加抽象和通用的层度上定义了一个消息传递的规约。适用场景不一样。
大家:继续。
kimmking:ok,如何描述消息呢,如何传递消息呢?考虑这些问题,JMS规范就出场了。
kimmking:jcp组织02-03年定义了jsr914规范,http://jcp.org/en/jsr/detail?id=914
kimmking:jsr914就是jms规范。
kimmking:主要干了两件事,定义通用的消息格式,和消息传递的模式。
kimmking:一个通用的消息格式,应该是什么样子的呢?
大家:啥样~?
kimmking:消息头 消息体
大家:头 主体 这样子吗 ?和soap类似?
kimmking:对,和soap类似,主要分header,properties,body
大家:那和soap有什么区别呢
kimmking:就是ppt的第8页。
kimmking:soap描述的是xml格式的数据格式。关注于rpc,与wsdl组成一个体系。
kimmking:jms描述更通用的消息。
kimmking:或者可以说是,soap专注于远程服务调用,jms专注于信息交换。
kimmking:soap是两个点的连接系统,jms是3个点。
kimmking:header和properties都是键值对,jms消息头预定义了一些消息的元数据。peoperties一般用来保存一些附加信息。body用来保存数据内容。
kimmking:一般来说,ws是同步的,jms是异步或同步的。
大家:题外话,那rmi跟soap里面的rpc是啥关系?
kimmking:rpc是remote process call
kimmking:rmi是一种rpc,rpc本身没有规范,
kimmking:只要是实现了远程调用的,都是rpc
kimmking:比如rmi .net-remoting ws/soap/rest hessian xmlrpc thrift potocolbuffer 等等。
kimmking:rpc有一个通用的结构,就是serialization/deserialization+stub+skeleton
林木森:这么说rpc是一种远程调用设计思维,强调的是透明的调用远程的方法,看起来就跟本地调用一样是伐?
大家:哦,那rpc强调的是透明的远程方法调用,而ms强调的是通用的信息交流。
kimmking:正解。有兴趣的可以自己了解下,ps:dwr也算一种标准的rpc
kimmking:回到jms。
kimmking:jms定义了消息格式以后,我们就可以考虑消息如何交互了。
kimmking:消息不是凭空出现的,所以,一定有传出消息的消息生产者。
大家:请问header,properties,body各自主要存哪一类型的信息?
kimmking:
header和properties都是键值对。
body是具体要传递的内容。
header一般是要消息的元数据。前面说过了。
properties可以放一些自定义的附加信息。
kimmking:消息需要由生产者产生。同样的道理,消息也需要传递到需要它的消息消费者手中。
kimmking:除了消息以外,我们又得到两个概念,生产者和消费者。
大家:恩。
kimmking:其实还有一个隐含的东西,那就是MQ
kimmking:或者叫jms server
kimmking:生产者产生的消息,一般先发到jms server,然后由server传递给消费者处理。
大家:之前说的jms的3点结构就是指生产者,消费者和server嘛?
kimmking:对。
kimmking:消息可以看做是一个实物的抽象,也可以是抽象的概念。
kimmking:server应该说是用来暂存或者中转消息的吧
kimmking:假设存在多个消费者,如果一条消息代表一个实物,或是不可分的数据,那么将只有一个消息者可以获取到每条消息。
kimmking:我们称这种模式叫point to point,也就是ptp。
林木森:为什么只有一个消息者可以获取到每条消息?
kimmking:就是一条数据不能重复发给两个消费者。
kimmking:比如我有一个苹果,你们三个人要,我只能给一个人。再来一个苹果,我还是只能给一个人。
kimmking:这个人和前面那个人,可能不是同一个人。
大家:取了就没了嘛。相当于每条消息只有一个实例。取了就没有了。
kimmking:对。
kimmking:但是,如果消息是一个可以复制的,或者是抽象的东西,
kimmking:情况就不同了。
kimmking:比如消息是一句话:6木同学是泡妞高手。
6木:。。。。
kimmking:你们都想问我6木同学的情况,我就可以分别告诉你们这个消息。
大家:那相当于多播。。微薄那种。。
kimmking:我们称这个模式为发布订阅模式。
kimmking:publish/subscribe。就是每一个发布出阿里的消息,都可以被多个人共享。
kimmking:这个消息的发送者叫发布者,拿到各个消息的人,叫订阅者。
kimmking:消息发出来以后,需要放到server上的一个“地方”,这个地方我们叫目的地destination
kimmking:ptp时的destination我们叫queue
kimmking:pub/sub时的destination我们叫topic
kimmking:注意一点:jms规范和jdbc规范很类似,都是单纯的客户端视角,没有涉及任何server段的概念和描述。
kimmking:jms 和 jms server的关系 等价于
jdbc和数据库的关系
kimmking:从这个意义上,ActiveMQ相当于mysql
大家:这么说activeMQ就是支持jms规范的一个server!
kimmking:jms规范本身没对server做任何详细规范~
kimmking:所以,它主要是实现了一个MQ,其中的很小一部分,是实现jms规范,就是怎么去用mq,相当于mysql java驱动。
kimmking:”ActiveMQ是jms的一个实现“,这句话其实是很不科学的。
kimmking:jms还定义了一个selector,类似js框架的selector
kimmking:可以定义条件过滤消息,其语法是sql92的一个子集。
kimmking:ActiveMQ加强了一下,可以使用XPath。
大家:xpath不是xml的东西么。。消息的发送难道不是xml格式么? 异构的系统 不用xml用什么?
kimmking:消息是抽象概念,可以是任何格式。注意jms三个字母等于 java message service。一般都不是xml格式。
kimmking:xpath不仅仅可以用在xml.xpath本质上是一个针对树状层次数据的一个选择器。抛开语法怪异以外,xpath和 各种el(mvel\ognl\。。。)差不多
大家:选择的功能很强大。
kimmking:一般jms消息不是一个xml,而是一个java对象,很明显的是jms没考虑异构系统。
kimmking:它压根儿没考虑非java的东西。但是,MQ都必须自己去解决这个问题。
kimmking:JMS不是为了解决异构系统而定义的,好在它发展成熟以后,基本上所以的jms server的实现(各种MQ)都解决了异构问题。
kimmking:跟数据库的各个平台下实现各自的驱动一个道理.
kimmking:jms默认情况下,发送和接收消息都是同步的。
kimmking:或者说,是主动的。
kimmking:需要我们显式的 send或receive
kimmking:所以,规范里定义了一个MessageListener,可以在有消息到达时(异步)被动的处理消息。
kimmking:其实消息传递还有一个常见场景
kimmking:就是request/response模式
kimmking:不光光是发出去一个消息,我还要等一个回来的响应消息。
kimmking:是靠什么机制知道当前发出去的消息已经回来了呢?
kimmking:JMS不是为了解决异构系统而定义的,好在它发展成熟以后,基本上所以的jms server的实现(各种MQ)都解决了异构问题。
大家:如果发送出去的消息 回来响应的时候失败会做些什么处理?
kimmking:呵呵,你提出一个很有意义的问题。
kimmking:其实也是jms考虑的所有概念和功能之上的最重要的问题。
kimmking:就是我们不光要传递消息,还要保障消息的可靠性。
kimmking:再进一步,我们要保证消息传递的高效和高可靠性。
kimmking:所以,JMS引入了两个概念,确认和事务。
大家:像数据库的啊~
kimmking:Kimm不是一直拿DB做比方嘛 更好理解
kimmking:确认的对象是消息,可以在收取一个消息时自动确认。也可以在一次会话过程,可以像jdbc那样,设置一个手动事务,处理完成后,提交,确认所有的消息。
kimmking:遗憾的是,发送不支持事务。
kimmking:淘宝内部的MQ框架,实现了发送的事务性。
kimmking:确认就是说,消费者获取一个消息,如何没有确认,MQ还会重试再次发送给你。
kimmking:你可以看做是你没有签收消息。所以,它要给你补发一份。
kimmking:你的意思是消费者在接受到信息后,发一个确认给jms server
kimmking:jms server没收到这个确认就在一定的时间内一直发
大家:那么生产者如何知道他的消息发送成功了呢?或者是接收者已经成功接收了呢?
kimmking:生产者不知道。生产者和消费者是透明的。它们不知道彼此的存在。
大家:那生产者需不需要jms server发给他确认消息?这样才知道他的信息已经确实的发出去了啊.不然中间丢了咋办?
kimmking:其实也有确认的。相当于邮局,但是如何邮局给你搞丢了信件,你还是木有办法。\其中隐含的一个假设就是,消息一旦发出,我们就完全的信任邮局。
kimmking:我们相信mq是可靠的。
kimmking:MQ告诉我们,我们发送成功了,MQ内部的东西,生产者是看不见的,我们怎么能相信消费者一定能接收到呢?
kimmking: 我们知道,接收我们信件的人不签收,消息会重新发送,就是可能会在消费者处重复。
kimmking: 但是,生产者不知道这个过程,发送这头没有这个可靠性的处理,怎么办呢?
kimmking: 还有就是如果MQ不负责任,把消息放在内存,MQ崩溃后,消息都丢失了怎么办?
kimmking: 所以,jms规范定义了消息的持久化。
kimmking: 把消息分为两种,一种是严格的不能丢失的消息,一种是可以偶尔丢失的消息。
kimmking: 前者性能明显会比后者慢,因为后者可以完全在内存处理,系统崩溃时内存中的消息会丢失。
kimmking: 前者需要MQ做持久化,内存放一份,持久化的介质中放一份。
kimmking: 然后MQ告诉消息生产者,我接收到了你发送的消息,你放心吧。
kimmking: 这比不持久化的消息,明显会慢。
kimmking: 消息被消费者消费掉了以后,MQ再从介质中删除掉消息。
kimmking: 系统崩溃时也不要紧,重启后从介质中恢复消息。
kimmking: queue默认是持久化的。
kimmking: topic,因为要发送给多个人,默认是非持久化的。
kimmking: 就是说topic里的消息放在内存里,只发给在线的订阅者
kimmking: 如果想要收到topic里所有的消息怎么办呢(像LDAP那样,把上次同步数据后的数据都给我)
kimmking: 这时,又有一个新的概念了,持久订阅。
kimmking: 你可以想象成,你在线期间,你接收了第1、2、3条数据。你掉线了,不在线期间,系统里多了第4、5条数据,发送给所有的订阅者后,删除了。
你又上线了。。。你想要你上次获取的最后一条数据后的第4、5条数据
kimmking: 这个是MQ里比较麻烦的地方。
kimmking: 原理就是同时持久化订阅者和topic的消息。
ticmy:我持久订阅了后长期不上线,咋整?我几年都不上线.那得保留多少消息....总不能我不上线耗费了服务器的所有存储空间吧
kimmking: 有可能。这个就是持久订阅不常用的原因之一吧。
kimmking: 持久订阅还有一个问题是,你断线以后,再连上jms server,server怎么知道你是以前的那个你呢?
大家:按kk上面的说法,这个发送直接还存在一个会话状态才能收信息哦~
kimmking: 跟http的sessionid一个道理。你每次来,都用一个相同的clientid就成了。
kimmking: mq把持久订阅者的信息存到本地,在其不在线期间,也把它当做一个订阅者,把该发给它的消息持久化到存储。等这条消息被所有的持久订阅者确认后删除。
kimmking: 所以,MQ还需要持久化确认的数据。因为对有持久订阅的TOPIC来讲,可能有些持久订阅者上线拿到数据并确认了,有些 木有确认。
kimmking: 可靠的原则是宁可重复也不少发,存入持久化保证安全,数据没用以后才能丢弃。
kimmking: 可靠天生就和高可用是冲突的。
kimmking: 所以,优化JMS的几个要点就是
kimmking: 所以,优化JMS性能的几个要点就是根据使用的场景,在可靠性和高性能之间做出权衡:
1、优化存储
2、优化确认
3、尽量快速的消费掉消息
4、尽量异步处理消息
kimmking: 今天的JMS就到这里吧,1个半小时。。。。
kimmking: ActiveMQ找个时间再讲吧。
提问时间:
问题1:activeMQ是一款开源产品么?那个公司出的?目前在国内的使用情况如何?
kimmking: apache的,http://activemq.apache.org/
kimmking: 目前用的最多的MQ是 Websphere MQ(商业的) ActiveMQ(开源的)
kimmking: ActiveMQ从3.X以后非常稳定。很多大公司都在用。
kimmking: 最新正式版本 5.5.0 activemq6 正在开发,不是java的了,使用的是scala
kimmking: 快钱用的是sonicMQ
kimmking: 现在好像稍大点的公司都有自己的MQ实现
kimmking: 淘宝现在主要用的是自己实现的MQ
kimmking: 某些项目里还在用ActiveMQ
kimmking: 去哪儿网,用了很多年的ActiveMQ了。一直很稳定。
问题2:使用mq的典型场景,能举个现实中的例子么
kimmking: 系统间集成传递数据,同步转异步。甚至可以用来做通知。
问:系统间集成传递数据,用ws也可以把
kimmking: ws一般不是用来传递数据的。
kimmking: 前面以及说过了ws的关注点是service。是调用一个服务。可以看ppt里面有两个图很形象的说明了问题。
kimmking: 其实可以把MQ看做是BlockingQueue 的一个自然的延伸。
kimmking: 1、是在一个独立的jvm里了。2、概念和内容丰富了。
2、概念和内容丰富了。
kimmking: MQ最大的作用是 (解耦系统间的依赖关系)(缺2张图)
kimmking: jms还可以看做是一个退化的ESB。。。。
问题3:MQ存在单点问题么?
kimmking: 一个很明显的缺陷就是,引入了一个单点。如果中间的MQ挂了,那么所有的系统都不能交互了。
kimmking: 但是mq一般都可以集群,或者做master-slave
kimmking: 集群的主要目的是负载均衡还是灾难恢复抑或两者皆有
kimmking: 有多种集群方式。针对各种场景。master-slave,是针对 disaster recovery的。
问题3:spring有mq相关的实现嘛?
kimmking: spring好像没有mq
kimmking: spring下有个spring-jms的子项目。
kimmking: 跟spring的jdbcsupport的功能差不多。
kimmking: 封装了一些jms的常用操作。
kimmking: 这个是spring的强项。spring很少做轮子。一般是集成
kimmking: spring是到处做 别人的东西到spring的适配。
kimmking: 比如现在的spring-data项目。
kimmking: 意图包括所有场景类型的 nosql
kimmking: 愿景很远大。
kimmking: 今天讲座到此结束。
kimmking: 明天我会发布activemq-store-mongodb的第一个可用版本。支持queue的消息持久化到mongodb。还不支持持久订阅。
Ø 掌握JMS基本概念及适用范围
Ø 点对点模型与发布/订阅模型的区别和使用场合
Ø 熟悉核心和通用的JMS API
Ø 熟悉并理解JMS客户端开发的步骤
Ø 消息的同步和异步接收的实现方式
Ø 串包问题的解决办法
企业消息系统
Java Message Service是由Sun开发的,它为 Java程序提供一种访问企业消息系统的方法。在讨论JMS之前,我们分来析一下企业消息系统。企业消息系统,即面向消息的中间件(MOM),提供了以松散耦合的灵活方式集成应用程序的一种机制。它们提供了基于存储和转发的应用程序之间的异步数据发送,即应用程序彼此不直接通信,而是与作为中介的MOM 通信。MOM提供了有保证的消息发送,应用程序开发人员无需了解远程过程调用(PRC)和网络/通信协议的细节。ActiveMQ正是MOM中优秀的一员。
企业消息系统的好处
我们先来看看下图,应用程序A将Message发送到服务器上,然后应用程序B从服务器中接收A发来的消息,通过这个图我们一起来分析一下JMS的好处
图 1 JMS通讯示意图
提供消息灵活性
应用程序A与应用程序B通过使用MOM的应用程序编程接口(API)发送消息进行通信。MOM 将消息路由给应用程序B,这样消息就可以存在于MOM中,MOM 负责处理网络通信。如果网络连接不可用,MOM会存储消息,直到连接变得可用时,再将消息转发给应用程序B。
灵活性的另一方面体现在,当应用程序A发送其消息时,应用程序B甚至可以不处于执行状态。MOM将保留这个消息,直到应用程序B开始执行并试着检索消息为止。这还防止了应用程序A因为等待应用程序B检索消息而出现阻塞。
这种异步通信要求应用程序的设计与现在大多数应用程序不同,不过对于时间无关或并行处理,它可能是一个极其有用的方法。
松散耦合
企业消息系统的真正威力在于应用程序的松散耦合。在上面的图中,由应用程序A发送消息指定一个特定目标,如“订单处理”。而现在,是由应用程序B提供订单处理功能。
但是在将来,我们可以用不同的订单处理程序替换应用程序B,应用程序A将不再是明智之选。替换应用程序将继续发送消息完成“订单处理”,而消息也仍将得到处理。
同样,我们也可以替换应用程序A,只要替换应用程序继续发送消息进行“订单处理”,订单处理程序就无需知道是否有一个新的应用程序在发送订单。
JMS是什么
JMS是一系列的接口及相关语义的集合,通过这些接口和和其中的方法,JMS客户端如何去访问消息系统,完成创建、发送、接收和读取企业消息系统中消息。在JMS之前,每一家MOM厂商都用专有API为应用程序提供对其产品的访问,通常可用于许多种语言,其中包括Java语言。JMS通过MOM为Java程序提供了一个发送和接收消息的标准的、便利的方法。用JMS编写的程序可以在任何实现JMS标准的MOM上运行。
JMS可移植性的关键在于:JMS API是由Sun作为一组接口而提供的。提供了JMS功能的产品是通过提供一个实现这些接口的提供者来做到这一点的。开发人员可以通过定义一组消息和一组交换这些消息的应用程序,建立JMS应用程序,实现异步通讯。
JMS的目标
JMS从提出以来,致力于完成如下几个目标:
定义一组消息公用概念和实用工具。
所有Java应用程序都可以使用JMS中定义的API去完成消息的创建、接收与发送,任何实现了JMS标准的MOM都可以作为消息的中介,完成消息的存储转发。
最大化消息应用程序的可移植性。
MOM提供了有保证的消息发送,应用程序开发人员无需了解远程过程调用(PRC)和网络/通信协议的细节,提供了程序的可移植性。
最大化降低应用程序与应用系统之间的耦合度。
由于MOM的存在,各个应用程序只关心和MOM之间如何进行消息的接收与发送,而无需关注MOM的另一边,其他程序是如何接收和发送的。
JMS两种消息模型
JMS提供了两种消息通信模型:Ø 点到点(P2P)模型
Ø 发布/订阅(Pub/Sub)模型
图 2 JMS通讯模型
从图中可以看出,ClientA和ClientB是消息生产者,通过两种不同的目的地分别向ClientC、ClientD、ClientE和ClientF发送消息。
在ClientA、C、D之间的消息是点对点模型,使用这种模型,客户端发送消息到队列目的地(Queue),从这个队列里面只有一个消息接收者可以收到那个消息,其他访问同一目的地的接收者不会接收到该消息。如ClientC接收Queue中的Msg1消息,ClientD接收Queue中的Msg2消息。
在ClientB、E、F之间的消息是发布/订阅模型。使用这种广播模型,一个客户端发送消息给主题目的地(Topic),任何数量的消费订阅者可以从这个主题目的地来接收它们。如:ClientE和ClientF都接收这个Msg3这条消息。
点到点模型
点对点传递模型:生产者发送消息到一个特定的队列(Queue)中,而消费者从一个消息队列中得到消息,如下图所示:
图 3 点到点通讯模型示意图
点对点模型的特点:
Ø 每条消息有一个消费者
每条只有一个消费者,如果一条消息被消息者接收,那么其他的消费者就不能得到这条消息了。
Ø 发送和接受消息与时间没有关系
也就是说,生产者在发送消息后,消费者可以在任意的时刻接收,但有两个前提:
1、消息未过期
2、消息没有被其他的用户接收
消费者也可以先运行,当生产者一运行,将消息发送到队列中,消费者即可从队列中获得消息,这叫“守株待兔“。
Ø 消费者必须确认对消息的接收
收到消息后消费者必须确认消息已被接收,否则JMS服务提供者会认为该消息没有被接收,那么这条消息仍然可以被其他人接收。程序可以自动进行确认,不需要人工干预。
Ø 非持久的消息最多只发送一次
非持久的消息最多只发送一次,表示消息有可能未被发送,造成未被发送的原因可能有:
1、 JMS服务提供者出现宕机等情况,造成非持久信息的丢失
2、 队列中的消息过期,未被接收
Ø 持久的消息严格发送一次
我们可以将比较重要的消息设置为持久化的消息,持久化后的消息不会因为JMS服务提供者的故障或者其他原因造成消息丢失。
发布/订阅模型
发布/订阅模型:发布/订阅传递消息类型与主题(Topic)有关。生产者发布消息,而消费者订阅感兴趣的消息,生产者将消息和一个特定的主题(Topic)连在一起,消息传递系统(MOM)根据消费者注册的兴趣,将消息传递给消费者。这种类型非常类似出版报纸、杂志的形式,如下图所示:
图 4 发布/订阅通讯模型示意图
发布/订阅模型的特点:
Ø 每个消息都可以有多个(0,1,……)订阅者
每条消息可以有多个消费者,如果报纸和杂志一样,谁订阅了谁都可以获得。
Ø 订阅者只能消费他们订阅之后出版的消息
这就要求订阅者必须先订阅,生产者再发布。即订阅者必须先运行,再等待生产者的运行,这和点对点类型有所差异。
Ø 订阅者必须保持为活动状态才能使用这些消息
即订阅者必须保持活动状态等待发布者发布的消息,如果订阅者在发布者发布消息之后才运行,则不能获得先前发布者发布的消息。
------------------------------------------------------------------------------
ppt下载地址:
http://code.google.com/p/activemq-store-mongodb/downloads/list
下面开始:
kimmking:介绍下jms和ActiveMQ。在讲JMS之前,我们聊聊相关的背景。谁知道JMS是什么意思?
kimmking:对,是message service。那,什么事message呢?嗯,对了,就是信息。
kimmking::所有的信息,我们都可以说是消息。
kimmking:前提是,它必须是动态的,可流动的,或者说是可传递的。这个过程,就是messaging
大家:请问jms的消息传递跟常用的通信协议有什么区别?
答:通信协议一般是针对一种具体的通信业务场景,制定了一个规定。是多方都需要遵守的。而jms消息机制,在更加抽象和通用的层度上定义了一个消息传递的规约。适用场景不一样。
大家:继续。
kimmking:ok,如何描述消息呢,如何传递消息呢?考虑这些问题,JMS规范就出场了。
kimmking:jcp组织02-03年定义了jsr914规范,http://jcp.org/en/jsr/detail?id=914
kimmking:jsr914就是jms规范。
kimmking:主要干了两件事,定义通用的消息格式,和消息传递的模式。
kimmking:一个通用的消息格式,应该是什么样子的呢?
大家:啥样~?
kimmking:消息头 消息体
大家:头 主体 这样子吗 ?和soap类似?
kimmking:对,和soap类似,主要分header,properties,body
大家:那和soap有什么区别呢
kimmking:就是ppt的第8页。
kimmking:soap描述的是xml格式的数据格式。关注于rpc,与wsdl组成一个体系。
kimmking:jms描述更通用的消息。
kimmking:或者可以说是,soap专注于远程服务调用,jms专注于信息交换。
kimmking:soap是两个点的连接系统,jms是3个点。
kimmking:header和properties都是键值对,jms消息头预定义了一些消息的元数据。peoperties一般用来保存一些附加信息。body用来保存数据内容。
kimmking:一般来说,ws是同步的,jms是异步或同步的。
大家:题外话,那rmi跟soap里面的rpc是啥关系?
kimmking:rpc是remote process call
kimmking:rmi是一种rpc,rpc本身没有规范,
kimmking:只要是实现了远程调用的,都是rpc
kimmking:比如rmi .net-remoting ws/soap/rest hessian xmlrpc thrift potocolbuffer 等等。
kimmking:rpc有一个通用的结构,就是serialization/deserialization+stub+skeleton
林木森:这么说rpc是一种远程调用设计思维,强调的是透明的调用远程的方法,看起来就跟本地调用一样是伐?
大家:哦,那rpc强调的是透明的远程方法调用,而ms强调的是通用的信息交流。
kimmking:正解。有兴趣的可以自己了解下,ps:dwr也算一种标准的rpc
kimmking:回到jms。
kimmking:jms定义了消息格式以后,我们就可以考虑消息如何交互了。
kimmking:消息不是凭空出现的,所以,一定有传出消息的消息生产者。
大家:请问header,properties,body各自主要存哪一类型的信息?
kimmking:
header和properties都是键值对。
body是具体要传递的内容。
header一般是要消息的元数据。前面说过了。
properties可以放一些自定义的附加信息。
kimmking:消息需要由生产者产生。同样的道理,消息也需要传递到需要它的消息消费者手中。
kimmking:除了消息以外,我们又得到两个概念,生产者和消费者。
大家:恩。
kimmking:其实还有一个隐含的东西,那就是MQ
kimmking:或者叫jms server
kimmking:生产者产生的消息,一般先发到jms server,然后由server传递给消费者处理。
大家:之前说的jms的3点结构就是指生产者,消费者和server嘛?
kimmking:对。
kimmking:消息可以看做是一个实物的抽象,也可以是抽象的概念。
kimmking:server应该说是用来暂存或者中转消息的吧
kimmking:假设存在多个消费者,如果一条消息代表一个实物,或是不可分的数据,那么将只有一个消息者可以获取到每条消息。
kimmking:我们称这种模式叫point to point,也就是ptp。
林木森:为什么只有一个消息者可以获取到每条消息?
kimmking:就是一条数据不能重复发给两个消费者。
kimmking:比如我有一个苹果,你们三个人要,我只能给一个人。再来一个苹果,我还是只能给一个人。
kimmking:这个人和前面那个人,可能不是同一个人。
大家:取了就没了嘛。相当于每条消息只有一个实例。取了就没有了。
kimmking:对。
kimmking:但是,如果消息是一个可以复制的,或者是抽象的东西,
kimmking:情况就不同了。
kimmking:比如消息是一句话:6木同学是泡妞高手。
6木:。。。。
kimmking:你们都想问我6木同学的情况,我就可以分别告诉你们这个消息。
大家:那相当于多播。。微薄那种。。
kimmking:我们称这个模式为发布订阅模式。
kimmking:publish/subscribe。就是每一个发布出阿里的消息,都可以被多个人共享。
kimmking:这个消息的发送者叫发布者,拿到各个消息的人,叫订阅者。
kimmking:消息发出来以后,需要放到server上的一个“地方”,这个地方我们叫目的地destination
kimmking:ptp时的destination我们叫queue
kimmking:pub/sub时的destination我们叫topic
kimmking:注意一点:jms规范和jdbc规范很类似,都是单纯的客户端视角,没有涉及任何server段的概念和描述。
kimmking:jms 和 jms server的关系 等价于
jdbc和数据库的关系
kimmking:从这个意义上,ActiveMQ相当于mysql
大家:这么说activeMQ就是支持jms规范的一个server!
kimmking:jms规范本身没对server做任何详细规范~
kimmking:所以,它主要是实现了一个MQ,其中的很小一部分,是实现jms规范,就是怎么去用mq,相当于mysql java驱动。
kimmking:”ActiveMQ是jms的一个实现“,这句话其实是很不科学的。
kimmking:jms还定义了一个selector,类似js框架的selector
kimmking:可以定义条件过滤消息,其语法是sql92的一个子集。
kimmking:ActiveMQ加强了一下,可以使用XPath。
大家:xpath不是xml的东西么。。消息的发送难道不是xml格式么? 异构的系统 不用xml用什么?
kimmking:消息是抽象概念,可以是任何格式。注意jms三个字母等于 java message service。一般都不是xml格式。
kimmking:xpath不仅仅可以用在xml.xpath本质上是一个针对树状层次数据的一个选择器。抛开语法怪异以外,xpath和 各种el(mvel\ognl\。。。)差不多
大家:选择的功能很强大。
kimmking:一般jms消息不是一个xml,而是一个java对象,很明显的是jms没考虑异构系统。
kimmking:它压根儿没考虑非java的东西。但是,MQ都必须自己去解决这个问题。
kimmking:JMS不是为了解决异构系统而定义的,好在它发展成熟以后,基本上所以的jms server的实现(各种MQ)都解决了异构问题。
kimmking:跟数据库的各个平台下实现各自的驱动一个道理.
kimmking:jms默认情况下,发送和接收消息都是同步的。
kimmking:或者说,是主动的。
kimmking:需要我们显式的 send或receive
kimmking:所以,规范里定义了一个MessageListener,可以在有消息到达时(异步)被动的处理消息。
kimmking:其实消息传递还有一个常见场景
kimmking:就是request/response模式
kimmking:不光光是发出去一个消息,我还要等一个回来的响应消息。
kimmking:是靠什么机制知道当前发出去的消息已经回来了呢?
kimmking:JMS不是为了解决异构系统而定义的,好在它发展成熟以后,基本上所以的jms server的实现(各种MQ)都解决了异构问题。
大家:如果发送出去的消息 回来响应的时候失败会做些什么处理?
kimmking:呵呵,你提出一个很有意义的问题。
kimmking:其实也是jms考虑的所有概念和功能之上的最重要的问题。
kimmking:就是我们不光要传递消息,还要保障消息的可靠性。
kimmking:再进一步,我们要保证消息传递的高效和高可靠性。
kimmking:所以,JMS引入了两个概念,确认和事务。
大家:像数据库的啊~
kimmking:Kimm不是一直拿DB做比方嘛 更好理解
kimmking:确认的对象是消息,可以在收取一个消息时自动确认。也可以在一次会话过程,可以像jdbc那样,设置一个手动事务,处理完成后,提交,确认所有的消息。
kimmking:遗憾的是,发送不支持事务。
kimmking:淘宝内部的MQ框架,实现了发送的事务性。
kimmking:确认就是说,消费者获取一个消息,如何没有确认,MQ还会重试再次发送给你。
kimmking:你可以看做是你没有签收消息。所以,它要给你补发一份。
kimmking:你的意思是消费者在接受到信息后,发一个确认给jms server
kimmking:jms server没收到这个确认就在一定的时间内一直发
大家:那么生产者如何知道他的消息发送成功了呢?或者是接收者已经成功接收了呢?
kimmking:生产者不知道。生产者和消费者是透明的。它们不知道彼此的存在。
大家:那生产者需不需要jms server发给他确认消息?这样才知道他的信息已经确实的发出去了啊.不然中间丢了咋办?
kimmking:其实也有确认的。相当于邮局,但是如何邮局给你搞丢了信件,你还是木有办法。\其中隐含的一个假设就是,消息一旦发出,我们就完全的信任邮局。
kimmking:我们相信mq是可靠的。
kimmking:MQ告诉我们,我们发送成功了,MQ内部的东西,生产者是看不见的,我们怎么能相信消费者一定能接收到呢?
kimmking: 我们知道,接收我们信件的人不签收,消息会重新发送,就是可能会在消费者处重复。
kimmking: 但是,生产者不知道这个过程,发送这头没有这个可靠性的处理,怎么办呢?
kimmking: 还有就是如果MQ不负责任,把消息放在内存,MQ崩溃后,消息都丢失了怎么办?
kimmking: 所以,jms规范定义了消息的持久化。
kimmking: 把消息分为两种,一种是严格的不能丢失的消息,一种是可以偶尔丢失的消息。
kimmking: 前者性能明显会比后者慢,因为后者可以完全在内存处理,系统崩溃时内存中的消息会丢失。
kimmking: 前者需要MQ做持久化,内存放一份,持久化的介质中放一份。
kimmking: 然后MQ告诉消息生产者,我接收到了你发送的消息,你放心吧。
kimmking: 这比不持久化的消息,明显会慢。
kimmking: 消息被消费者消费掉了以后,MQ再从介质中删除掉消息。
kimmking: 系统崩溃时也不要紧,重启后从介质中恢复消息。
kimmking: queue默认是持久化的。
kimmking: topic,因为要发送给多个人,默认是非持久化的。
kimmking: 就是说topic里的消息放在内存里,只发给在线的订阅者
kimmking: 如果想要收到topic里所有的消息怎么办呢(像LDAP那样,把上次同步数据后的数据都给我)
kimmking: 这时,又有一个新的概念了,持久订阅。
kimmking: 你可以想象成,你在线期间,你接收了第1、2、3条数据。你掉线了,不在线期间,系统里多了第4、5条数据,发送给所有的订阅者后,删除了。
你又上线了。。。你想要你上次获取的最后一条数据后的第4、5条数据
kimmking: 这个是MQ里比较麻烦的地方。
kimmking: 原理就是同时持久化订阅者和topic的消息。
ticmy:我持久订阅了后长期不上线,咋整?我几年都不上线.那得保留多少消息....总不能我不上线耗费了服务器的所有存储空间吧
kimmking: 有可能。这个就是持久订阅不常用的原因之一吧。
kimmking: 持久订阅还有一个问题是,你断线以后,再连上jms server,server怎么知道你是以前的那个你呢?
大家:按kk上面的说法,这个发送直接还存在一个会话状态才能收信息哦~
kimmking: 跟http的sessionid一个道理。你每次来,都用一个相同的clientid就成了。
kimmking: mq把持久订阅者的信息存到本地,在其不在线期间,也把它当做一个订阅者,把该发给它的消息持久化到存储。等这条消息被所有的持久订阅者确认后删除。
kimmking: 所以,MQ还需要持久化确认的数据。因为对有持久订阅的TOPIC来讲,可能有些持久订阅者上线拿到数据并确认了,有些 木有确认。
kimmking: 可靠的原则是宁可重复也不少发,存入持久化保证安全,数据没用以后才能丢弃。
kimmking: 可靠天生就和高可用是冲突的。
kimmking: 所以,优化JMS的几个要点就是
kimmking: 所以,优化JMS性能的几个要点就是根据使用的场景,在可靠性和高性能之间做出权衡:
1、优化存储
2、优化确认
3、尽量快速的消费掉消息
4、尽量异步处理消息
kimmking: 今天的JMS就到这里吧,1个半小时。。。。
kimmking: ActiveMQ找个时间再讲吧。
提问时间:
问题1:activeMQ是一款开源产品么?那个公司出的?目前在国内的使用情况如何?
kimmking: apache的,http://activemq.apache.org/
kimmking: 目前用的最多的MQ是 Websphere MQ(商业的) ActiveMQ(开源的)
kimmking: ActiveMQ从3.X以后非常稳定。很多大公司都在用。
kimmking: 最新正式版本 5.5.0 activemq6 正在开发,不是java的了,使用的是scala
kimmking: 快钱用的是sonicMQ
kimmking: 现在好像稍大点的公司都有自己的MQ实现
kimmking: 淘宝现在主要用的是自己实现的MQ
kimmking: 某些项目里还在用ActiveMQ
kimmking: 去哪儿网,用了很多年的ActiveMQ了。一直很稳定。
问题2:使用mq的典型场景,能举个现实中的例子么
kimmking: 系统间集成传递数据,同步转异步。甚至可以用来做通知。
问:系统间集成传递数据,用ws也可以把
kimmking: ws一般不是用来传递数据的。
kimmking: 前面以及说过了ws的关注点是service。是调用一个服务。可以看ppt里面有两个图很形象的说明了问题。
kimmking: 其实可以把MQ看做是BlockingQueue 的一个自然的延伸。
kimmking: 1、是在一个独立的jvm里了。2、概念和内容丰富了。
2、概念和内容丰富了。
kimmking: MQ最大的作用是 (解耦系统间的依赖关系)(缺2张图)
kimmking: jms还可以看做是一个退化的ESB。。。。
问题3:MQ存在单点问题么?
kimmking: 一个很明显的缺陷就是,引入了一个单点。如果中间的MQ挂了,那么所有的系统都不能交互了。
kimmking: 但是mq一般都可以集群,或者做master-slave
kimmking: 集群的主要目的是负载均衡还是灾难恢复抑或两者皆有
kimmking: 有多种集群方式。针对各种场景。master-slave,是针对 disaster recovery的。
问题3:spring有mq相关的实现嘛?
kimmking: spring好像没有mq
kimmking: spring下有个spring-jms的子项目。
kimmking: 跟spring的jdbcsupport的功能差不多。
kimmking: 封装了一些jms的常用操作。
kimmking: 这个是spring的强项。spring很少做轮子。一般是集成
kimmking: spring是到处做 别人的东西到spring的适配。
kimmking: 比如现在的spring-data项目。
kimmking: 意图包括所有场景类型的 nosql
kimmking: 愿景很远大。
kimmking: 今天讲座到此结束。
kimmking: 明天我会发布activemq-store-mongodb的第一个可用版本。支持queue的消息持久化到mongodb。还不支持持久订阅。
相关文章推荐
- Spring注解@Scope("prototype") Spring在Action上面注解@Scope("prototype")
- 2015年9月3日总结
- LeetCode_maximum-depth-of-binary-tree
- Android UI设计(引导界面):ViewPager之三PagerTabStrip与PagerTitleStrip添加标题栏的区别
- 利用JAXP开发包进行SAX方式进行解析
- 5、ASP.NET MVC入门到精通——NHibernate代码映射
- 记录每一天
- jquey.fullpage详解
- 字符串中第一个只出现一次的字符
- SPOJ 题目1812 LCS2 - Longest Common Substring II(后缀自动机求多个串的最长公共子串)
- android中ListView的定位:使用setSelectionFromTop
- 用python写一个温度转换程序
- C++入门经典 笔记 (第九章)高级类
- The Skyline Problem -- leetcode
- Full Multi-thread Client/Server Socket Class with ThreadPool
- c++中输入和输入语句
- 给Button加上圆角
- 关于jQuery中的offset()和position()
- Linux系统管理-(7)-压缩与归档
- 一笔画问题