最近想把博客分类栏中数量为0的博客补点东西,那些都是长久之前自己向自己许愿要开的坑。今天说话算话一次。先写个activeMQ。
消息中间件解决的问题和应用场景
先看这样一种传统的服务调用场景
通过服务调用让其他系统感知时间发生
比如一个大型网站系统,登录系统在用户登录后,需要短信提醒,那么登录系统需要调用其他系统的短信服务;后来,我们追加了登录之后赚积分的业务,登录系统登录之后需要调用积分业务系统的积分服务;后来我们建立的独立的日志服务等等各类外部系统的外部服务,都需要在登录系统发生登录事件后进行外部服务调用。这种调用关系的耦合度非常高,用户登录必须服务调用全部成功才会返回用户登录结果。这样就导致用户登录后等待结果需要很久的时间,其实用户登录不需要等待积分等各式服务的完成,用户仅仅是希望登录成功进入系统而已。
通过消息中间件解耦服务调用
消息中间件的作用:解耦上面提供的服务调用
用户登录后发送一个消息给消息中间件,然后就可以返回客户端了,告知用户登录成功可以开始使用系统了。
消息中间件会异步地把这些消息发送给下游对应的各个系统。其他系统可以在后端接收这个消息,然后去处理消息。
通过消息中间件,用户不再需要等待完成短信、积分等各类服务之后才返回登录结果。
(本文出自oschina博主happyBKs的博文:https://my.oschina.net/happyBKs/blog/1811711)
消息中间件的好处
解耦:消息的生产方系统和消息的消费方系统之间不再是相互耦合的同步调用和数据传递,而是低耦合的异步消息的生产和消费;解耦业务系统的追加的耦合。
异步:参见解耦。
横向扩展:加入某个业务系统性能出现瓶颈,需要横向扩展几台机器,那么消息中间件也可以被多个机器的服务订阅,同时为它们提供消息。
安全可靠:消息中间件会对我们的消息进行保存,知道我们的业务系统把这条消息消费掉为止。如果某个业务系统没有消费、或者发生故障一时间不能消费,那么消息中间件可以等到这个业务系统服务恢复之后继续消费。
顺序保证:消息的顺序要求也可以做到。比如Kakka就是就顺序的日志消息中间件系统。
消息中间件概述
什么是中间件
非底层操作系统软件、非业务应用软件,不能给最终用户使用的,不能直接给用户带来价值的软件统称为中间件。
什么是消息中间件
关注数据的发送和接收,利用高效可靠的异步数据传递机制集成分布式系统。
Java消息服务(JMS)
JMS(Java Message Service)即Java消息服务,是一个java平台中关于消息中间件的API,用于两个应用程序之间或在一个分布式系统中发送消息,进行异步通信。
JMS不是协议,只是一个API的规范。
消息中间件的协议倒是有,即AMQP。
AMQP(Advanced Message Query Protocol)是一个提供统一消息服务的应用层消息协议。基于此协议的客户端和消息中间件可传递消息,不受客户端、中间件的产品不同、开发语言不同等因素限制。
JMS和AMQP的区别
首先最本质的区别,一个是API规范,一个是协议。
附:线协议请参考:https://en.wikipedia.org/wiki/Wire_protocol
各类消息中间件对比
ActiveMQ
ActiveMQ是Apache出品的,最流行,能力强劲的开源消息总线。ActiveMQ是一个完全支持JMS1.1和J2EE1.4规范的JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演者特殊的地位。
特性
ActiveMQ支持多种语言和协议编写客户端:Java、C、C++、C#、Perl、Python、PHP
支持应用协议:OpenWire、Stomp REST、WS NotificationXMPP、AMQP
ActiveMQ完全支持JMS1.1和J2EE1.4规范(持久化,XA消息,事务)
ActiveMQ还支持一些高级特性:虚拟主题、组合目的、镜像队列
RabbitMQ
RabbitMQ是一个开源的AMQP实现,服务端用Erlang语言编写。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。
特性:
支持多种客户端,如Python、Ruby、.NET、Java、JMS、C、PHP、Actionscript等
AMQP的完整实现(vhost、Exchange、Binding、Routing Key等)
支持事务、发布确认
支持消息持久化
Kafka
Kafka是一个高吞吐量的分布式发布订阅消息系统,是一个分布式的、分区的、可靠的分布式日志存储服务。它公国一种独一无二的设计提供了一个消息系统的功能。
Kafka本身不是一个严格意义上的消息中间件,它本身是用来做日志储存的。所以kafka对消息的顺序要求的非常严格。
特性
Kafka通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于及时数以TB的消息存储也能够保持长时间的稳定性能。Kafka储存算法在持久化方面做得非常好,即使面对TB级别的消息(日志)数据也能给偶偶保持长时间的稳定。
高吞吐量:即使是非常普通的硬件。Kafka也可以支持每秒数百万的消息。
kafka支持分区(Partition)、消费者分组(Consumer Group)
各个消息中间件综合对比与评价
附:Kafka因为本身处理的是日志,消息可指定追溯
这里我没有对比阿里爸爸的RocketMQ,留个坑。
JMS规范
重要概念
提供者:实现JMS规范的消息中间件服务器。
JMS是一种接口规范,需要服务商提供服务,这就是提供者。
客户端:发送或接收消息的对象。这是我们应用开发所主要编写的对象。
客户端里又分为生产者(发布者)和消费者(订阅者)
生产者(发布者):它是创建并发送消息的客户端。
消费者(订阅者):接收并处理消息的客户端。
消息:在应用程序之间传递的数据内容。
消息模式:在客户端之间传递消息的方式,JMS定义了 主题 和 队列 两种模式
注意:生产者和消费者对应的是队列模式,发布者和订阅者对应的主题模式。
JMS消息模式
消息模式是JMS中非常重要的概念。
队列模式
队列模式的客户端主包括了生产者和消费者。
队列中的一条消息只会被一个消费者消费。
消费者可以随时消费队列中的消息。即消费者不需要预先订阅这个队列也能够获取之前的数据。
示例:
首先我们有一个JMS消息队列,以及两个生产者客户端应用1和2。
应用1和应用2作为生产者客户端向JMS消息队列建立连接。
然后发送M1~M6的消息。
JMS存储M1~M6的消息。
然后我们创建两个消费者客户端应用3和4。
假设,客户端应用3向JMS消息队列建立了两个连接,应用4建立了一个连接。
JMS每个连接均分了JMS队列中的消息,每个消息只能由一个连接发送给一个应用。
主题模式
客户端包括发布者和订阅者。
主题中的每一条消息会被所有的订阅者消费。
消费者不能消费订阅之前就发送到主题中的消息。
示例
首先我们有一个JMS主题。
创建两个订阅者客户端应用3和应用4。
应用3向主题下面建立了两个连接,应用4建立了一个连接,它们订阅了JMS主题。
然后我们创建两个发布者,应用1和应用2。它们分别向JMS主题各自建立一个连接,发送M1~M6消息。
JMS存储M1~M6的消息。
然后,订阅者客户端应用3和应用4的每一条连接分别收到了JMS主题中的所有完整的消息M1~M6。
这里,你可能看到了主题模式和队列模式的明显区别,一个是消费者的每个连接均分JMS队列中的消息,一个是订阅者的每一个连接都接收同样的完整的所有JMS主题中的消息。
但是还有一个更重要的区别请注意:主题模式要求订阅者必须在发布者发布消息之前先与JMS主题建立连接进行订阅,否则收不到消息。即主题模式下,订阅者客户端无法获取订阅之前的消息。
JMS编码接口
ConnectionFactory(连接工厂):用于创建连接到消息中间件的连接的工厂
Connection(连接):代表了应用程序和消息中间件的通信链路
Destination(目的地):指消息发布和接收的地点,包括队列和主题。
Session(会话):会话是一个单线程的上下文,用于发送和接收消息。
MessageConsumer:由会话创建的,用于接收发送到目标的消息。
MessageProducer::由会话创建的,用于发送消息到目标。
Message(消息):是在消费者和生产者之间发送的对象,一般是由消息头、一组属性,一个消息体组成。
一个消息对象,它的消息头是必须存在的。
JMS编码接口之间的关系
首先ConnectionFactory(连接工厂)创建一个Connection(连接)。(一个ConnectionFactory可以创建多个Connection,一个连接可以供多个线程同时使用)。
有了这个Connection(连接)之后就可以用这个Connection(连接)创建一个Session(会话)。(一个Connection可以创建多个Session,而每一个Session是在一个单独的线程上线文的,即会话是单线程的,只在当前的上下文中有效。,也就是说Session会话可以做一些事务方面的处理。
由Session(会话)可以创建生产者和消费者,即MessageProducer和MessageConsumer;并且Session(会话)也可以用来创建一个新的Message(消息)。
然后我们可以使用生产者MessageProducer将我们的消息发送到我们指定的Destination(目的地)。
然后可以用消费者MessageConsumer到指定的Destination(目的地)接收消息。
注意:如果是主题模式,注意要先订阅才能收到消息。