消息中间件与JMS标准
初识消息中间件
维 基百科上对于消息中间件的定义是"Message-oriented middleware(MOM) is software infrastructure focused on sending and receiving messages between distrubuted systems"。解释起来就是消息中间件是在分布式系统中完成消息的发送和传递的基础软件。看张图来更直观地理解消息中间件:
看到消息中间件有两个好处:
1、异步
2、解耦
应用A和应用B都和消息中间件打交道,这两个应用之间并不直接联系,这样就完成了解耦,目的是希望收发消息的双方彼此不知道对方的存在,也不受对方的影响,所以将消息投递给接收者实际上都采用了异步的方式。
透过示例看消息中间件对应用的解耦
以苹果的App Store为例吧,App Store有一个功能:用户充值成功后向用户手机发送一条短信,算是一个安全选项。最直观的,我们会这么实现:
然后,我们需要把用户付款的信息(用户名、时间、IP等数据)传给安全系统,安全系统会根据安全策略进行相关的判断和处理,因此结构变成:
这么看起来还好,那么如果再增加一些要被调用的系统呢?比如:
这会让付款系统变得非常复杂,每增加一个在付款成功之后需要调用的系统,就需要修改付款系统来进行相关的调用。优雅一点的实现是把这个付款成功后的 服务调用变为一种可扩展的配置,甚至可以动态生效,但这只能降低变更时的开发和部署成本,并没有降低复杂性。付款系统被迫要依赖非常多的系统。
引入消息中间件进行服务解耦
可以考虑一下,从付款的角度看,这些系统是付款系统必须依赖的吗?答案是否定的, 付款系统只需要验证用户账号、付款账号、付款密码的合法性,所以付款系统依赖的是能够系统用户账号、付款账号、付款密码的系统,而上图中的系统其实都不是 付款系统必须依赖的系统。相反,这些系统都是必须依赖付款系统的,因为它们都关心付款是否成功。
在这样的场景中,我们需要通过消息中间件把上面的结构解耦,上面结构中的服务调用将会被固定格式的消息传递所取代。付款系统负责向消息中间件发送消息,而其他的系统则向消息中间件来订阅这个消息,然后完成自己的工作,如图所示:
这样,通过消息中间件,付款系统就不需要关心到底有多少个系统需要知道付款成功这 件事情了,也不用关心如何通知它们,只需要把登陆成功这件事情转化为一个消息发送到消息中间件就好了,这样,需要了解付款成功这件事情的系统自己去消息中 间件订阅就行了,并且各个系统之间也是互不影响的。
JMS概述
JMS是Java Message Service的缩写,即Java消息服务,它是Java EE中一个关于消息的规范,而Hornetq、ActiveMQ等产品是对这个规范的实现。如果是企业内部或者一些小型的系统,直接使用JMS的实现产品 是一个经济的选择,而在大型系统中有一些场景不适合使用JMS。
在大型互联网中,我们采用消息中间件可以进行应用之间的解耦以及操作的异步,这是消息中间件两个最基础的特点,也正是我们所需要的。在此基础上,我们着重思考的是消息的顺序保证、扩展性、可靠性、业务操作与消息发送一致性,以及多集群订阅者等方面的问题。当然,这些我们要思考的东西,JMS都已经想到了,先看下JMS能帮开发者做什么:
1、定义一组消息公用概念和实用工具
所有Java应用程序都可以使用JMS中定义的API去完成消息的创建、接收与发送,任何实现了JMS标准的MOM都可以作为消息的中介,完成消息的存储转发
2、最大化消息应用程序的可移植性
MOM提供了有保证的消息发送,应用程序开发人员无需了解远程过程调用(PRC)和网络/通信协议的细节,提供了程序的可移植性
3、最大化降低应用程序与应用程序之间的耦合度
由于MOM的存在,各个应用程序只关心和MOM之间如何进行消息的接收与发送,而无须关注MOM的另一边,其他程序是如何接收和发送的
JMS两种消息模型
1、点对点模型
点对点模型(Pointer-to-Pointer)类似这样:
这种模型总结几点:
(1)一个消息中间件关联多个队列生产者和消费者
(2)一条消息仅仅能被一个消费者消费
(3)多个消费者正在监听队列上的消息,那么中间件将根据先来先得的原则确定由哪个消费者接收下一条消息,如果没有消费者正在监听队列,那么消息将保留在中间件中,直至消费者连接到中间为止
(4)收到消息后消费者必须确认消息已被接收,否则中间件江认为该消息没有被接收,那么这条消息仍然可以被其他消费者接收。程序可以自动确认,不需要人工干预
(5)生产者和消费者的运行先后没有限制
(6)此模型中,消息不是自动推送给消费者的,而是要消费者中间件中请求获得
2、发布/订阅模型
发布/订阅(Publish-Subscribe)模型类似这样:
这种模型中,还是以分点的形式总结:
(1)有一个重要的概念topic,可以认为是主题
(2)生产者发布消息,消费者订阅感兴趣的消息,生产者将消息和一个特定的topic(主题)连在一起,中间件将根据消费者注册的topic,将消息传递给消费者
(3)发布/订阅模式允许多个消费者接收同一条消息,只要这些消费者注册了同一个主题
(4)消费者必须先运行,订阅主题,然后再等待生产者运行,这么点对点模型有所差别
(5)该模型中,消息会自动广播,消费者无须通过主动请求或者轮训主题的方法来获得新的消息
JMS为提供的要素
JMS为发开者提供了很多的要素,看一下比较重要的几个:
要 素 | 作 用 |
Destination | 表示消息所走通道的目标定义,,用来定义消息从发送端发出后要走的通道,而不是接收方。Destination属于管理类对象 |
ConnectionFactory | 顾名思义,用于创建连接对象,ConnectionFactory属于管理类的对象 |
Connection | 连接接口,所负责的重要工作时创建Session |
Session | 会话接口,这是一个非常重要的对象,消息发送者、消息接收者以及消息对象本身,都是通过这个会话对象创建的 |
MessageConsumer | 消息的消费者,也就是订阅消息并处理消息的对象 |
MessageProducer | 消息的生产者,也就是用来发送消息的对象 |
XXXMessage | 指各种类型的消息对象,包括ByteMesage、ObjectMessage、StreamMessage和TextMessage这5种 |
在JMS消息模型中,根据点对点模式和发布/订阅模式,这些要素由扩展出了各自的内容:
JMS标准 | 点对点模式 | 发布/订阅模式 |
ConnectionFactory | QueueConnectionFactory | TopicConnectionFactory |
Connection | QueueConnection | TopicConnection |
Destination | Queue | Topic |
Session | QueueSession | TopicSession |
MessageProducer | QueueSender | TopicPublisher |
MessageConsumer | QueueReceiver | TopicSubscriber |
JMS是一个标准,具体还是依赖实现,当前常见的JMS实现有ActiveMQ、ZeroMQ、RabbitMQ等,Kafka是一种类似JMS的实现,下一篇文章将会重点讲解一下Kafka,至于为什么,还是和以前写文章一样的原因,因为工作用,呵呵。