生活不易,且行且学习吧

 

        前几天有同事手上有个老项目,效率比较低,压测的时候压死了,领导准备用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正确收到消息并处理掉。

spring boot 自定义 ddl spring boot 自定义内存队列_消息发送

但此种方式无法适用高并发的情况,一次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秒消费一个

spring boot 自定义 ddl spring boot 自定义内存队列_数据_02

应用此方法,满足领导要求。。。。