生活不易,且行且学习吧
前几天有同事手上有个老项目,效率比较低,压测的时候压死了,领导准备用mq分下流,但是这个项目接收到请求后又进行了二次转发,没法具体确定一条消息是否真正执行完成,能想到的是定时5S执行一条,这样能保证消息不丢失,还不会死掉。于是发现了mq的延时队列,在此记录下。
方式A,整体过期时间。
1,创建队列A,作为死信转发队列
/**
* 注册队列A,死信转发队列,不处理消息,死信自动转发到B
* @return
*/
@Bean
public Queue TestMqQueryA(){
Map<String, Object> map = new HashMap<>();
map.put("x-message-ttl", 10000);//设置10s过期时间
//x-dead-letter-exchange参数是设置该队列的死信交换器(DLX),此处设置为B的Exchange
map.put("x-dead-letter-exchange", MqContains.TestMqExchangeInB);
//x-dead-letter-routing-key参数是给这个DLX指定路由键,此处设置为B的RoutingKey
map.put("x-dead-letter-routing-key", MqContains.TestInBRouting);
return new Queue(MqContains.TestMqQueryInA,true,false,false,map);
}
2,controller进行数据写入队列A
@RequestMapping(value="/sendMsgInA", method = RequestMethod.POST)
@ApiOperation(value="发送mq消息到A", notes="发送mq消息到A")
@ResponseBody
public String sendMsgInA(@RequestBody Map params) {
String id = UUID.randomUUID().toString().replace("-","");
String msgBody = "发送一条死信测试消息A,数据01,将在10秒后到达B";
Map msgMap = new HashMap();
msgMap.put("msgId",id);
msgMap.put("msgBody",msgBody);
//将消息携带绑定键值:TestInARouting 发送到交换机TestMqExchangeInA
rabbitTemplate.convertAndSend(MqContains.TestMqExchangeInA,MqContains.TestInARouting,msgMap);
logger.info("mqA消息发送成功");
return "发送成功";
}
3,编写死信队列B的监听
@RabbitListener(queues = MqContains.TestMqQueryInB)
@RabbitHandler
public void process(Map testMessage) {
logger.info("DirectReceiver消费者收到消息 : " + testMessage.toString());
}
4,测试,10秒后B正确收到消息并处理掉。
但此种方式无法适用高并发的情况,一次2000条数据进入A,会同时在10秒后全部进入队列B中,B会一次性消费2000条,依旧不适用。
方式B,单条消息过期时间。
1,配置死信转发队列A,取消过期时间
/**
* 注册队列A,死信转发队列,不处理消息,死信自动转发到B
* @return
*/
@Bean
public Queue TestMqQueryA(){
Map<String, Object> map = new HashMap<>();
// map.put("x-message-ttl", 10000);//设置10s过期时间
//x-dead-letter-exchange参数是设置该队列的死信交换器(DLX),此处设置为B的Exchange
map.put("x-dead-letter-exchange", MqContains.TestMqExchangeInB);
//x-dead-letter-routing-key参数是给这个DLX指定路由键,此处设置为B的RoutingKey
map.put("x-dead-letter-routing-key", MqContains.TestInBRouting);
return new Queue(MqContains.TestMqQueryInA,true,false,false,map);
}
2,写入数据A的方法调整,增加每条消息的过期时间
@RequestMapping(value="/sendMsgInA", method = RequestMethod.POST)
@ApiOperation(value="发送mq消息到A", notes="发送mq消息到A")
@ResponseBody
public String sendMsgInA(@RequestBody Map params) {
String id = UUID.randomUUID().toString().replace("-","");
for(int i=1;i<11;i++) {
String msgBody = "发送一条死信测试消息A"+i+",数据0"+i+",将在"+(10*i)+"秒后到达B";
int finalI = i;
MessagePostProcessor processor = message -> {
MessageProperties messageProperties = message.getMessageProperties();
//设置编码格式
messageProperties.setContentEncoding("UTF-8");
//设置过期时间10*1000
messageProperties.setExpiration(String.valueOf(10000* finalI));
return message;
};
Map msgMap = new HashMap();
msgMap.put("msgId", "id:0"+i);
msgMap.put("msgBody", msgBody);
//将消息携带绑定键值:TestInARouting 发送到交换机TestMqExchangeInA
rabbitTemplate.convertAndSend(MqContains.TestMqExchangeInA,MqContains.TestInARouting,msgMap,processor);
logger.info("mqA"+i+"消息发送成功");
}
return "发送成功";
}
3,查看日志,依次10秒消费一个
应用此方法,满足领导要求。。。。