RabbitMQ(二) - RabbitMQ与消息发布确认与返回、消费确认

RabbitMQ消息确认

SpringBoot与RabbitMQ整合后,对RabbitClient的“确认”进行了封装、使用方式与RabbitMQ官网不一致;

消息发布确认

  • 生产者给交换机发送消息后、若是不管了,则会出现消息丢失;
    • 解决方案1: 交换机接受到消息、给生产者一个答复ack, 若生产者没有收到ack, 可能出现消息丢失,因此重新发送消息;
  • 解决方案1隐藏问题:若是交换机发送了ack, 出现网络延迟,则生产者没有收到ack, 就会出现消息重复发送问题, 进而衍生幂等性问题;
    • 隐藏问题解决方案1:在数据库中增加一张去重表,设置唯一索引; 生产者在消息内容中,翻入唯一ID,消费者消费时、先从数据库查询是否存在,存在则不处理该消息;
      • 适用于并发低、业务严谨的场景
    • 隐藏问题解决方案2:利用Redis的String的setnx,若key存在,则不处理、若key存在,则执行业务;
      • 适用于短时间处理大量消息,且 key不会重复;
        -这就是大名鼎鼎的幂等性问题,贼讨厌这些专有名词;

业务开发中的幂等性

  1. 前端保存数据时、点击多次保存按钮,插入多条数据;
    • 解决方案 :前端限制按钮点击、 数据库设置业务唯一索引;
  2. 消息推送中,可能出现多条内容一样的消息,又不可以重复处理 ,需要幂等性处理;
    上家公司中,后台给app客户端推送系统消息时、配置给所有用户推送消息, 其他服务给我的应用消息服务推送 RabbitMQ消息, 正常来说, 每次推送的消息, 设备ID和用户ID合起来唯一的,结果其他服务业务数据存在问题,有些旧数据没有清除, 导致相通的设备ID,用户ID, 一次给设备用户推送了十几条,安卓客户端当当当的响, 直接惊动了产品经理; 经过排查上,是上游数据有问题,代码又很老,其他服务负责人排查了好几天, 把问题数据清楚了, 结果后面又产生了问题数据;
    • 解决方案:由于会一次性处理几万条推送消息,因此对业务要求速度高,因此利用Redis的String的setNx, 以taskId + mobileDevId + userId + tenantId 组成了唯一key,若是存在,则不处理; key有限时间为60分钟, 就成功处理了该问题;
    • 吐槽:上游的业务问题,让下游服务做业务保证,属实离谱;

{
“taskId” :“xxxx”;
“mobileDevId” : “xxxx”;
“userId”:“xxx”;
“tenantId” : “xxx”;
“其他字段”: “…”
}

RabbitMQ发布确认与返回

SpringBoot发布确认与返回

配置:
第二个参数因为过时,所以要配置第三个参数为correlated,表示用来确认消息;

#生产者
spring.rabbitmq.publisher-returns=true
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-confirm-type=correlated

生产者:

  1. 通过RabbitTempldate#setConfirmCallback设置确认回调, 即交换器发送给ack给生产者,生产者调用ConfirmCallback回调, 若出现异常cause,则可重新推送;
    通过RabbitTempldate#setReturnCallback设置返回回调;
  2. 通过template#waitForConfirms(xxx)表示等待xxx毫秒后确认,超时返回false;
    • 若返回false, 则进行业务补救处理;
public class ConfirmProducer implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback{
   
    @Autowired
    private RabbitTemplate template;

    @Autowired
    private DirectExchange confirmExchange;

    AtomicInteger index = new AtomicInteger(0);

    AtomicInteger count = new AtomicInteger(0);

    private final String[] keys = {
   "sms", "mail"};

    @Scheduled(fixedDelay = 1000, initialDelay = 500)
    public void send() throws IOException {
   
        //短信
        String sms = "{userName: xxx; phone:xxx}";
        HashMap<String, Object> map = new HashMap<>();
        map.put("userName", "hanxin");
        map.put("phone", index
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值