ActiveMQ知识整理 + 面试题

AcitveMQ

首先,说起ActiveMQ,就必须先聊聊JMS(Java Message Service)规范,也就是Java消息服务,它定义了Java中访问消息中间件的接口的规范。JMS只是接口,并没有给予实现,实现JMS接口的消息中间件称为 “JMS Provider”,目前知名的开源 MOM (Message Oriented Middleware,也就是消息中间件)系统包括Apache的ActiveMQ、RocketMQ、Kafka,以及RabbitMQ,可以说他们都 “基本遵循” 或 “参考” JMS规范,都有自己的特点和优势。

mq能解决什么问题:
异步:调用者无需等待
解耦:解决系统之间的耦合调用
削峰:抵御洪峰流量,保护核心业务

activemq的简单介绍:
activemq有两种模式,一种是queue模式,一种的topic模式。queue模式的消息默认是持久化的,被消费者消费完就没了,一个消息只能被一个消费者消费。topic是一种主题订阅模式,消费者需要先订阅一个topic,然后消息出现了才会发送给订阅者,如果没有订阅者,消息会被丢弃。

五种消息格式
typeMessage、StreamMessage、TextMessage、ObjectMessage、MapMessage

传输协议
activemq支持很多种的传输协议,默认是使用http协议,可以更改为nio协议提升activemq传输性能

持久化
queue默认是持久化的,topic默认不是
底层实现:

  • amq message store基于文件的存储形式
  • kahadb 基于索引和日志文件的存储形式
  • jdbc 基于数据库的存储
  • level db基于文件的数据库存储
    目前默认使用kahadb

kahadb:
包含四个文件: db.data da.free db.redo lock
大致流程:消息以追加的形式加到db-< number>.log文件中,如果文件满了,就新建一个log文件(默认最大大小为32M),同时number + 1。db.data存的是btree索引,指向log文件,如果一个log文件没有引用了,就会被归档或者删除
db.data:btree索引,指向log文件。维护了一个FIFO队列,消息被消费后就出队(被移除)
db.free:表示哪些文件是空的
db.redo:在一次硬件停机之后,用来进行消息恢复Btree索引。
lock:表示获得的锁的broker

jdbc存储
有三个表,activemq-msgs:用于放消息,queue和topic都存放在这里

ID:自增的数据库主键
CONTAINER:消息的Destination
MSGID_PROD:消息发送者客户端的主键
MSG_SEQ:是发送消息的顺序,MSGID_PROD+MSG_SEQ可以组成JMS的MessageID
EXPIRATION:消息的过期时间,存储的是从1970-01-01到现在的毫秒数
MSG:消息本体的Java序列化对象的二进制数据
PRIORITY:优先级,从0-9,数值越大优先级越高

activemq-acks:订阅者和服务器的关系放在这里表里

CONTAINER:消息的Destination
SUB_DEST:如果是使用Static集群,这个字段会有集群其他系统的信息
CLIENT_ID:每个订阅者都必须有一个唯一的客户端ID用以区分
SUB_NAME:订阅者名称
SELECTOR:选择器,可以选择只消费满足条件的消息。条件可以用自定义属性实现,可支持多属性AND和OR操作
LAST_ACKED_ID:记录消费过的消息的ID。

activemq-lock:获取了锁的broker,集群环境下生效

LevelDB
目前已经被不推荐使用的

The main reason is that KahaDB continues to be the main focus where bugs are fixed and not much attention is paid to LevelDB. There seems to be several issues with corruption (especially with replication) so I don’t think it should be a recommended store unless the stability is sorted out. Unfortunately nearly every JIRA reported against LevelDB goes ignored.

大概意思是:KahaDB仍然是BUG修复的主要关注点,并且没有对LevelDB给予太多关注。它似乎有一些问题(特别是在replication),所以并不推荐它作为存储方式,除非稳定性能够得到保证。

没啥了解,以后在补充吧。。。

面试题

activemq有几种通信方式?
publish(发布)-subscribe(订阅)(发布-订阅方式)

发布/订阅方式用于多接收客户端的方式.作为发布订阅的方式,可能存在多个接收客户端,并且接收端客户端与发送客户端存在时间上的依赖。一个接收端只能接收他创建以后发送客户端发送的信息。作为subscriber ,在接收消息时有两种方法,destination的receive方法,和实现message listener 接口的onMessage 方法。

如何解决消息重复问题?
所谓消息重复,就是消费者接收到了重复的消息,一般来说我们对于这个问题的处理要把握下面几点,
①.消息不丢失(上面已经处理了)
②.消息不重复执行

一般来说我们可以在业务段加一张表,用来存放消息是否执行成功,每次业务事物commit之后,告知服务端,已经处理过该消息,这样即使你消息重发了,也不会导致重复处理

大致流程如下:
业务端的表记录已经处理消息的id,每次一个消息进来之前先判断该消息是否执行过,如果执行过就放弃,如果没有执行就开始执行消息,消息执行完成之后存入这个消息的id

ActiveMQ消息发送失败?

ActiveMQ有两种通信方式,点到点形式和发布订阅模式。如果是点到点模式的话,如果消息发送不成功,此消息默认会保存到ActiveMQ服务端直到有消费者将其消费,所以此消息是不会丢失的。如果是发布订阅模式的通信方式,默认情况只通知一次,如果接受不到此消息就没有了,这种场景使用于对消息发送率要求不高的情况,如果要求消息必须送达不可以丢失的话,需要配置持久订阅。每个订阅端定义一个id,在订阅是向ActiveMQ注册,发布消息和接受消息时需要配置发送模式为持久化,此时如果客户端接受不到消息,消息会持久化到服务端,直到客户端正常接收后为止。

丢消息怎么办?

解决方案:用持久化消息【可以使用对数据进行持久化JDBC,AMQ(日志文件),KahaDB和LevelDB】,或者非持久化消息及时处理不要堆积,或者启动事务,启动事务后,commit()方法会负责任的等待服务器的返回,也就不会关闭连接导致消息丢失了。

你可能感兴趣的:(activemq,java,java)