生产端的可靠性投递
定义
- 保障消息的成功发出
- 保障MQ节点的成功接收
- 发送端收到MQ节点(Broker)确认应答
- 完善的消息进行补偿机制
BAT互联网大厂解决方案
- 消息落库,对消息状态进行打标
- 消息的延迟投递,做二次确认,回调检查
消息落库
Callback
- callback:统一服务
幂等性
定义
消费端的幂等性
- 消费端实现幂等性,就意味着,我们的消息永远不会消费多次,即使我们收到了多条一样的消息
- 业界主流操作
- 唯一ID+指纹码 机制,利用数据库主键去重
- 利用Redis的原子性去实现
ID+指纹码
redis
P16
SpringBoot中
1. 参考
2. 小代码
@PostMapping(value = "/test/receiveMq")
public void receiveMq(){
Channel channel = connection.createChannel(false);
GetResponse response = null;
String s;
try{
response = channel.basicGet(RabbitMqEnum.TEST.getQueue(), false);
s = new String(response.getBody(), StandardCharsets.UTF_8);
// throw new IOException("就试试");
channel.basicAck(response.getEnvelope().getDeliveryTag(),false);
}catch(IOException e){
try{
if(response!=null){
channel.basicNack(response.getEnvelope().getDeliveryTag(),false,true);
}
}catch(Exception exception){
exception.printStackTrace();
}
e.printStackTrace();
return;
}
log.info("打印:[{}]",response);
log.info("打印:[{}]",s);
}
死信队列
1.参考
死信队列配合channel.basicNack(Long,false,flase)
2. 最重要配置
// 该队列即死信队列
public Queue successKillDeadQueue(){
HashMap<String, Object> argsMap = Maps.newHashMap();
//固定写法,这里设置消息死后发送到的交换机和路由key
argsMap.put("x-dead-letter-exchange",environment.getProperty("mq.kill.item.success.kill.dead.exchange"));
argsMap.put("x-dead-letter-routing-key",environment.getProperty("mq.kill.item.success.kill.dead.routing.key"));
//设置TTL
// argsMap.put("x-message-ttl",10000);
return new Queue(environment.getProperty("mq.kill.item.success.kill.dead.queue"),true,false,false,argsMap);
}
3. 场景举例
用户未支付: 用户下单后,可将订单放至私信队列中,设置TTL,当超时过后,将进入由另一个队列并消费,此时判断用户是否有下单记录,若有则无事发生,若没有则做相应逻辑