1.ActiveMQ 的作用以及原理
ActiveMQ 的作用就是系统之间进行通信。 当然可以使用其他方式进行系统间通信, 如果使用 Activemq 的话可以对系统之间的调用进行解耦, 实现系统间的异步通信。 原理就是生产者生产消息, 把消息发送给ActiveMQ。ActiveMQ接收到消息, 然后查看有多少个消费者, 然后把消息转发给消费者, 此过程中生产者无需参与。 消费者接收到消息后做相应的处理和生产者没有任何关系
2.ActiveMQ 的通信方式
- publish-subscribe(发布-订阅方式)
发布/订阅方式用于多接收客户端的方式.作为发布订阅的方式,可能存在多个接收客户端,并且接收端客户端与发送客户端存在时间上的依赖。一个接收端只能接收他创建以后发送客户端发送的信息。作为subscriber ,在接收消息时有两种方法,destination的receive方法,和实现message listener 接口的onMessage 方法。 - p2p(point-to-point)(点对点)
p2p的过程则理解起来比较简单。它好比是两个人打电话,这两个人是独享这一条通信链路的。一方发送消息,另外一方接收,就这么简单。在实际应用中因为有多个用户对使用p2p的链路。在p2p的场景里,相互通信的双方是通过一个类似于队列的方式来进行交流。和前面pub-sub的区别在于一个topic有一个发送者和多个接收者,而在p2p里一个queue只有一个发送者和一个接收者。
3.如何解决消息重复问题
所谓消息重复,就是消费者接收到了重复的消息,一般来说我们对于这个问题的处理要把握下面几点,
①.消息不丢失
②.消息不重复执行
一般来说我们可以在业务段加一张表,用来存放消息是否执行成功,每次业务事物commit之后,告知服务端,已经处理过该消息,这样即使你消息重发了,也不会导致重复处理
解决方法:增加消息状态表。通俗来说就是一个账本,用来记录消息的处理状态,每次处理消息之前,都去状态表中查询一次。如果已经有相同的消息存在,那么不处理,可以防止重复发送。
大致流程如下:
业务端的表记录已经处理消息的id,每次一个消息进来之前先判断该消息是否执行过,如果执行过就放弃,如果没有执行就开始执行消息,消息执行完成之后存入这个消息的id
4.queue 与 topic 区别
- Queue消息传递模型在该消息传递模型下,一个消息生产者向消息服务器端一个特定的队列发送消息,一个消费者从该队列中读取消息。在这种模型下,消息生产者知道消息消费者的队列并直接将消息发送到消息消费者的队列。特点:能够保证数据安全。
- Topic消息传递模型:在该消息传递模型下,一个消息发布者向一个特定的消息主题发布消息,0或多个对此消息主题感兴趣的并且处于活动状态的消息订阅者或者建立了持久订阅的消息订阅者才可以接收到所发布的消息。特点: 数据容易丢失。
5.消息的不均匀消费
有时在发送一些消息之后,开启2个消费者去处理消息。会发现一个消费者处理了所有的消息,另一个消费者根本没收到消息。原因在于ActiveMQ的prefetch机制。当消费者去获取消息时,不会一条一条去获取,而是一次性获取一批,默认是1000条。这些预获取的消息,在还没确认消费之前,在管理控制台还是可以看见这些消息的,但是不会再分配给其他消费者,此时这些消息的状态应该算作“已分配未消费”,如果消息最后被消费,则会在服务器端被删除,如果消费者崩溃,则这些消息会被重新分配给新的消费者。但是如果消费者既不消费确认,又不崩溃,那这些消息就永远躺在消费者的缓存区里无法处理。更通常的情况是,消费这些消息非常耗时,你开了10个消费者去处理,结果发现只有一台机器吭哧吭哧处理,另外9台啥事不干。
解决方案:将prefetch设为1,每次处理1条消息,处理完再去取,这样也慢不了多少。
6.死信队列
如果你想在消息处理失败后,不被服务器删除,还能被其他消费者处理或重试,可以关闭AUTO_ACKNOWLEDGE,将ack交由程序自己处理。
消费消息有2种方法:
基于异步调用时,消息的确认是在onMessage方法返回之后,如果onMessage方法异常,会导致消息重发。
- 一种是调用consumer.receive()方法,该方法将阻塞直到获得并返回一条消息。这种情况下,消息返回给方法调用者之后就自动被确认了。
- 另一种方法是采用listener回调函数,在有消息到达时,会调用listener接口的onMessage方法。在这种情况下,在onMessage方法执行完毕后,消息才会被确认,此时只要在方法中抛出异常,该消息就不会被确认,会被退回服务器重新分配或重试。
7.ActiveMQ如果消息发送失败怎么办
如果是点到点模式的话,如果消息发送不成功,此消息默认会保存到activemq服务端知道有消费者将其消费,所以此时消息是不会丢失的。
如果是发布订阅模式的通信方式,默认情况下只通知一次,如果接收不到此消息就没有了。这种场景只适用于对消息送达率要求不高的情况。如果要求消息必须送达不可以丢失的话,需要配置持久订阅。每个订阅端定义一个id,在订阅是向activemq注册。发布消息和接收消息时需要配置发送模式为持久化。此时如果客户端接收不到消息,消息会持久化到服务端,直到客户端正常接收后为止。
8.jsm的同步与异步
消息通信的基本方式有两种:
1、同步方式
两个通信应用服务之间必须要进行同步,两个服务之间必须都是正常运行的。发送程序和接收程序都必须一直处于运行状态,并且随时做好相互通信的准备。
发送程序首先向接收程序发起一个请求,称之为发送消息,发送程序紧接着就会堵塞当前自身的进程,不与其他应用进行任何的通信以及交互,等待接收程序的响应,待发送消息得到接收程序的返回消息之后会继续向下运行,进行下一步的业务处理。
2、异步方式
两个通信应用之间可以不用同时在线等待,任何一方只需各自处理自己的业务,比如发送方发送消息以后不用登录接收方的响应,可以接着处理其他的任务。也就是说发送方和接收方都是相互独立存在的,发送方只管方,接收方只能接收,无须去等待对方的响应。
Java中JMS就是典型的异步消息处理机制,JMS消息有两种类型:点对点、发布/订阅。