RabbitMQ的高级特性
1.消息的可靠传递
RabbitMQ 为我们提供了两种方式用来控制消息的投递可靠性模式。
- confirm 确认模式
- return 退回模式
rabbitmq 整个消息投递的路径为:
producer—>rabbitmq broker—>exchange—>queue—>consumer
- 消息从 producer 到 exchange 则会返回一个 confirmCallback 。
- 消息从 exchange–>queue 投递失败则会返回一个 returnCallback 。
我们将利用这两个 callback 控制消息的可靠性投递.
1.1确认模式
- 确认模式开启:配置文件中开启publisher-confirms为"true"
spring:
rabbitmq:
host: 127.0.0.1
port: 49154
virtual-host: /
username: guest
password: guest
publisher-confirms: true #开启确认模式
mq:
exchange_name: "springboot_item_topic_exchange"
queue_name: "springboot_item_queue"
- 在rabbitTemplate定义ConfirmCallBack回调函数
public void testConfirms(){
//2.定义回调函数
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
/**
*
* @param correlationData 相关的配置信息
* @param b exchange交换机 是否成功收到了消息。true 成功,false代表失败
* @param s 接收的信息
*/
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
if(b){
System.out.println("接收成功"+s);
}else{
System.out.println("接收失败"+s);
//TODO
//做一些处理,让消息重新发送
}
}
});
//3.发送消息
rabbitTemplate.convertAndSend("springboot_item_topic_exchange","item.insert","插入");
}
1.2退回模式
回退模式: 当消息发送给Exchange后,Exchange路由到Queue失败是 才会执行 ReturnCallBack
1.开启回退模式:配置文件中publisher-returns设为"true"
spring:
rabbitmq:
host: 127.0.0.1
port: 49154
virtual-host: /
username: guest
password: guest
publisher-confirms: true #开启确认模式
publisher-returns: true #开启回退模式
mq:
exchange_name: "springboot_item_topic_exchange"
queue_name: "springboot_item_queue"
2.设置ReturnCallBack
public void testReturn(){
//设置交换机处理失败消息模式
rabbitTemplate.setMandatory(true);
//2.设置ReturnCallBack
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
/**
*
* @param message 消息对象
* @param i 错误码
* @param s 错误信息
* @param s1 交换机
* @param s2 路由键
*/
@Override
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
System.out.println("消息:"+message);
System.out.println("错误码:"+i);
System.out.println("错误信息:"+s);
System.out.println("交换机:"+s1);
System.out.println("路由键:"+ s2);
//TODO
}
});
//3.发送消息
rabbitTemplate.convertAndSend("springboot_item_topic_exchange","item.insert","插入");
}
2.Consumer Ack
ack指Acknowledge确认。 表示消费端收到消息后的确认方式。
有三种确认方式:
- 自动确认:acknowledge=“none”
- 手动确认:acknowledge=“manual”
- 根据异常情况确认:acknowledge=“auto”
其中自动确认是指,当消息一旦被Consumer接收到,则自动确认收到,并将相应 message 从RabbitMQ 的消息缓存中移除。但是在实际业务处理中,很可能消息接收到,业务处理出现异常,那么该消息就会丢失。如果设置了手动确认方式,则需要在业务处理成功后,调用channel.basicAck(),手动签收,如果出现异常,则调用channel.basicNack()方法,让其自动重新发送消息。
Consumer ACK机制:
-
设置手动签收。acknowledge=“manual”
-
让监听器类实现ChannelAwareMessageListener接口
-
如果消息成功处理,则调用channel的 basicAck()签收
-
如果消息处理失败,则调用channel的basicNack()拒绝签收,broker重新发送给consumer
配置文件:
spring:
rabbitmq:
host: 127.0.0.1
port: 49154
virtual-host: /
username: guest
password: guest
listener:
direct:
acknowledge-mode: manual
mq:
exchange_name: "springboot_item_topic_exchange"
queue_name: "springboot_item_queue"
@Component
public class AckListener implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
//1.接收消息
System.out.println(new String(message.getBody()));
//2.业务处理逻辑
//TODO
//假如出现异常
int i=4/0;
//3.手动签收
channel.basicAck(deliveryTag,true);
} catch (Exception e) {
//4.拒绝签收
//第三个参数requeue,重回队列,true为重新回到queue中,broker重新发送给消费端
channel.basicNack(deliveryTag,true,true);
//channel.basicReject(deliveryTag,true)
}
}
@Override
public void onMessage(Message message) {
ChannelAwareMessageListener.super.onMessage(message);
}
}
3.消费端限流
Consumer 限流机制:
-
确保ack机制为手动确认。
-
listener-container配置属性
perfetch = 1,表示消费端每次从mq拉去一条消息来消费,直到手动确认消费完毕后,才会继续 拉去下一条消息。
spring:
rabbitmq:
host: 127.0.0.1
port: 49154
virtual-host: /
username: guest
password: guest
publisher-confirms: true #开启确认模式
publisher-returns: true #开启回退模式
listener:
direct:
acknowledge-mode: manual #手动应答
prefetch: 1 #限制流,每次发送一条数据。
mq:
exchange_name: "springboot_item_topic_exchange"
queue_name: "springboot_item_queue"
@Component
public class QosListener implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
//1.获取消息
System.out.println(new String(message.getBody()));
//2.处理业务逻辑
//3.签收
channel.basicAck(message.getMessageProperties().getDeliveryTag(),true);
}
@Override
public void onMessage(Message message) {
ChannelAwareMessageListener.super.onMessage(message);
}
}
4.TTL
Time To Live,消息过期时间设置
4.1 队列统一过期
生产端对队列的声明:
/**
* 声明队列
* 过期时间 100000
*/
@Bean("itemTopicQueue")
public Queue topicQueue(){
return QueueBuilder.durable(queue_name).withArgument("x-message-ttl",100000).build();
}
4.2消息单独过期
@Test
public void testTimeOut(){
//消息处理对象,设置消息参数信息
MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
//设置过期时间
message.getMessageProperties().setExpiration("100000");
return message;
}
};
//发送消息
rabbitTemplate.convertAndSend("springboot_item_topic_exchange","item.insert","插入",messagePostProcessor);
}