Active MQ (一)
Active MQ是Apache一个开源的消息中间件,也可以理解为其是一个消息总线,ActiveMQ是一个完全支持JMS1.1规范和J2EE1.4规范的JMS的Provider的实现,其需要有Java环境,且是一个面向Java的消息中间件。
ActiveMQ的原理
原理就是生产者将消息发送给ActiveMQ服务端,服务端会根据该消息对应的目标模型(p2p/topic)将消息发送给可以接受的消费者,期间默认会将数据进行持久化,并等待消费者签收消息后才会将消息删除,避免消息丢失。ActiveMQ发送消息的方式有两种,一种是持久化消息,一种是非持久化消息,如果发送的消息是持久化消息的话,消息是不会丢失的,ActiveMQ默认的是使用kahaDB来做数据的持久化,但是我们也可以用效率更高的levelDB,并且leverDB可以和zookeeper结合,实现ActiveMQ集群,持久化同步的问题。
什么是 MOM、JMS
MOM 就是面向消息中间件(Message-oriented middleware),是用于以分布式应用或系统中的异步、松耦合、可靠、可扩展和安全通信的一类软件。MOM 的总体思想是它作为消息发送器和消息接收器之间的消息中介,这种中介提供了一个全新水平的松耦合。
JMS 叫做 Java 消息服务(Java Message Service),是 Java 平台上有关面向 MOM 的技术规范,旨在通过提供标准的产生、发送、接收和处理消息的 API 简化企业应用的开发,类似于 JDBC 和关系型数据库通信方式的抽象。
对应解释一下:
- Provider:纯 Java 语言编写的 JMS 接口实现(比如 ActiveMQ 就是)。
- Domains:消息传递方式,包括点对点(P2P)、发布/订阅(Pub/Sub)两种。
- Connection factory:客户端使用连接工厂来创建与 JMS provider 的连接。
- Destination:消息被寻址、发送以及接收的对象。
Active MQ能够干什么?
1. 消除并发高峰、提高响应速度
这是第一个主要的作用,例如在现在的一些大型的电子商务如京东,淘宝等或者支付类的网站,同样的例如一些订单为主的如去哪网等都会遇到大量的并发的场景,消息队列的最大的特点也就是其最直接的任务就是消除并发高峰。在不使用消息队列的情况下,用户请求的数据则会直接卸乳数据库,随着并发量的增加数据库的读写压力也会随之增高,同时网络的响应延时也会继续增加。
当使用了消息队列之后,则会实现一个异步的返回,此时一般会有个中间状态显示“您提交的订单正在等待系统确认”。于返回上述信息的同时,也会将消费队列中的消费者进程从消息队列中获取数据,并写入数据库。从整体上看,这个过程是异步的,并且消息队列的处理速度要远高于数据库,所以在这一点上,用户体验层面的响应延迟能够得到改善。这类似于计算机结构里面的分级缓存,其有着异曲同工之妙,CPU和内存之间存在着一级二级缓存,其主要解决的就是CPU的高速处理和内存的读取速度不匹配的问题,在这里虽然解决的问题不同,但本质是有些相似。使用和不使用消息队列的示意图如下:
2. 业务异步处理
同样就着上述的业务场景继续说明,如果我们不使用消息队列,那么考虑下下面这个具体的业务场景两种方式会有什么不同?
例如用户注册后,需要使用邮件和短信通知注册成功,那么使用消息队列和不使用消息队列业务的处理方式上有什么区别呢?
不使用消息队列:串行工作–> 将用户注册信息写入数据库后发送邮件通知,再发送短信通知。三个任务完成后返回给客户端。
使用消息队列:将注册信息写入数据库成功后发送邮件注册的同时也进行短信的发送,与上述处理方式不同的是,发送短信和邮件是并行的。所以这种处理方式会节约一定的时间。以上面的示意图,串行比并行多花费了50ms。假如CPU再单位时间内处理请求的次数是一定的:100次/s,那么串行是7次,并行是10次。
对此得到的经验就是:将不是必须在业务逻辑中执行的部分抽出来,在处理方式上选择异步的方式,改造后的结构如下:
可以看到,在注册邮件后发送短信的操作直接写入消息队列,然后直接返回,所以此时时间耗费基本可以忽略,因此用户的响应时间可以理解为基本维持在50ms,所以系统改造后的吞吐量提高到20QPS,比串行高3倍。比并行高2倍。
3. 应用层面的解耦
考虑下面的应用场景:订单系统需要通知库存系统,传统的方法是我们去调用库存系统的接口,将其注入到订到系统的业务中,例如下图所示:
这种方式的缺点如下:
- 假设库存系统无法访问,那么订单生成后,需要在库存中对应减去库存的操作将会失败,从而使得订单功能失败,这个就是由于其他业务线出现问题导致当前也会出现问题的典型场景。
- 订单系统的业务和库存系统的业务本质上是可以分开的,但是目前这个方式将库存业务逻辑耦合到已有的订单系统的业务逻辑中,这也是导致1中库存失败导致订单功能失败的原因之一。
那怎么去解决这个问题,实现两个业务线的解耦合呢?
- 订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功,请等待物流配送。
- 库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作。
- 假如在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦。
4. 流量削峰
本质上是通过消息队列对流量进行一步缓存,还是类似于计算机组成里面的多级缓存类似。流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛。
应用场景如上图所示:例如某个电商平台搞活动–秒杀活动,一般会因为流量过大,导致流量暴增,应用容易挂掉。为解决这个问题,一般需要在应用前端加入消息队列。这样做一方面可以控制活动的人数,另一方面可以缓解短时间内高流量压垮应用。
上图所示意的业务处理逻辑可描述如下:(1)首先用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户的请求或跳转到错误页面。(2)秒杀业务根据消息队列中的请求信息,再做后续处理。
5. 应用消息通信
消息通信是指消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通信。比如实现点对点消息队列,或者聊天室等。例如下面的这个模式:
本质上有点像blockingQueue,不同的客户端A,B都向消息队列发送消息和消费消息,就好像在blockingQueue中不断的put和take,没有则可以理解为阻塞,并同时通知或者根据业务实现做进一步的处理,使得两端的客户端A,B好像是基于一个blockingQueue在进行通信。如果随着客户端接入的多了,那么我们可以使用观察者模式实现订阅消息,例如按照主题,按照消费群体等。
参考博客:
参考资料1:【基础知识】ActiveMQ基本原理
参考资料2: ActiveMQ总结