名词解释
Broker
消息服务器,作为server提供消息核心服务
应用场景
异步通行
把同步任务转为异步任务
异构
消费者生产者可以用不同语言实现
过载保护
可以熔断保护
缓冲
把大量的生产者产生的数据,放在mq中,消费者可以慢慢处理
解耦
生产者做生产者的事情,消费者做消费者的事情。可以各自扩容和修改
冗余
MQ把queue数据一直持久化,一直到消费才会删除
扩展性
消费者和生产者可以各自扩容
可恢复性
系统的一部分挂掉,另外的系统不影响,因为信息在MQ中
顺序保证
queue是有顺序的,FIFO
数据流处理
ActiveMQ的安全机制
WEB网页权限
访问的时候需要有账号密码,在jetty.xml中配置
访问activeMQ密码
在acivteMQ.xml中增加插件,配置密码
持久化
持久化默认是放到file中,但是可以通过配置,放到数据库中,内存中等等,如果放到数据库中,则可以做到持久化,重启也不会丢失数据。
事务
// 开启事务
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
// 可以批量提交
session.commit();
// try catch 可以回滚
session.rollback():
高级API
监听器
采用监听器去处理数据,可以避免线程阻塞。
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
try {
System.out.println(((TextMessage) message).getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
});
send object msg
需要在接受端增加信任列表
// 设置trust列表
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(ActiveMQConnectionFactory.DEFAULT_USER, ActiveMQConnectionFactory.DEFAULT_PASSWORD,
"tcp://0.0.0.0:61616");
factory.setTrustedPackages(Lists.newArrayList(Object.class.getPackage().getName()));
// 其他正常操作即可
死信队列
当provider发送信息到mq之中,但是没有客户端消费,这些信息会保存在内存中。当信息超时后,会进入死信队列。provider可以拿到死信队列中的数据,进行再次投递,成为***重投***
默认只有持久化msg才会进入死信队列
// 设置超时,超时后进入死信队列
producer.setTimeToLive(1000);
消息延迟投递
在配置文件中配置schedulerSupport=true,接着在代码中
textMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, 10 * 1000);
重复投递
textMessage.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, 10);
等待投递
textMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, 10);
消息选择器
可以有类似sql的写法,session.createConsumer(queue, “type=1 AND groupSize >1”);
like '李%四‘
客户端只会消费当前选择器选择的msg
生产者,设置额外属性
textMessage.setLongProperty("week", 1);
消费者,指定选择器
MessageConsumer consumer = session.createConsumer(queue, "week=1");
独占消费
选择器的一种
设置之后,只要客户端拿到一个队列后,其他客户端都拿不到了
Queue queue = session.createQueue("HelloWorld?consumer.exclusive=true");
消息的优先级
可以打乱消费数据。
需要在配置文件中,开启优先级策略
消息发送时的同步异步
Queue
ACK的几种模式
- Session.AUTO_ACKNOWLEDGE:当客户成功的从recive方法返回的时候,或者从MessageListener.onMessage方法成功返回的时候,会话会自动确认客户收到的消息
- Session.CLIENT_ACKNOWLEDGE:客户通过消息的acknowagledge方法确认。这种确认会一次性确认该次会话消费的所有的消息。(当客户端收到消息之后没有立刻ack或者宕机了,别的客户端就可以收到该条消息)
- Session.DUPS_OK_ACKNOWLEDGE:
开始事物模式,在一个客户端消费的数据,没有comit的时候,发送端也会hold住,不给其他人消费。但当持有的客户端关闭,其他客户端就可以拿到
message info
空
TOPIC
高级使用
queue brower
只能浏览,不参与消费
JMSCorrelationId
用于消息之间的关联,给人会话的感觉。reply to只有地址,不知道是哪条的回复,所以用这个属性。
Message.setJMSCorrelationId
queueRequestor
完全的同步消息。发送端发送消息给broker,并且创建一个temp queue,且用阻塞方法reviver()去等待消息。接收端收到信息后,从reply to中获得temp queue地址,然后发送消息给temp queue
preFetchSize
consumer端的缓冲区大小,建立connectionFactory或者queue,topic时候,指定prefetchSize的条数。当broker推送的消息并且没有接到ack的消息,大于这个条数的时候,就不推送了。
如果没有设置,则是consumer主动去broker拉取消息
高可用(主备)
同时起两个broker,但是用一个db fild,只会有一个broker抢到db的锁,此时其他broker会启动阻塞。当抢到锁的broker挂掉,其他的broker就会拿到锁,启动成功
高性能集群
静态网络配置
通过actviemq.xml的配置文件,配置 networkConnectors,则2个broker可以互相访问。
此时注意:queue尽量从对应的broker获取数据,不要利用集群的broker从目标queue所在的broker拉取数据,很消耗io。这种方式针对topic的效果最佳
动态网络配置
通过multicast协议,配置networkConnectors,并且在transportConnectors中配置discoverUri。通过udp协议自动发现。
常见问题
- 如何保证消费顺序:
- queue就是顺序的
- 如何防止不丢数据:
- 做高可用
- 死信队列
- 持久化
- ack
- 消息重投
- 记录日志
- 消费确认,reply to
- broker负载/限流
- 检查独占消费者
- 如何防止重复消费
- 消息幂等处理,用map或者concurrentHashMap的putIfAbsent方法(如果没有才会往map里面put)。注意别内存溢出,可以替代map用guava的cahe,弄ttl超时