rabbitmq(三):100%投递、幂等性、confirm和return、消费端限流、重回队列、TTL、死信队列

1.消息如何保证100%投递

同时做到下面四点可以保证消息可靠性的。
在这里插入图片描述
完善的消息进行补偿机制:当消息产生特殊情况进行处理,如:消息没有成功发出或者确认应答超时。

解决方案
(1)消息落库:将消息的投递、发送中、和已经收状态进行打标,将消息目前处于哪一种状态存储在数据库中。对没有投递成功的消息进行重试。
在这里插入图片描述
(2)消息延迟投递:相比第一种方案,减少了数据库的访问次数
在这里插入图片描述

2. 幂等性

比如一次、两次或者多次insert相同一行数据操作,对于DB结果都是相同的,这就是保证了幂等性。
(1)利用数据库去重:每个消息的处理操作在MQ的下游处理的时候,我们在MQ上游就已经设置好唯一的处理逻辑。(好比:我们以用户只能下一个订单,我们用id和商品id是唯一的,就保证了只可以下一次订单)

它的缺点是:数据库可能在并发下产生瓶颈。
在这里插入图片描述
(2)redis的setnx操作来设置订单唯一id,以后第二条订单过来就在redis这一层被过滤掉了。不会进行相关操作。
下面redis的需要问题:
在这里插入图片描述

3. confirm和return

confirm的机制:
在这里插入图片描述
confirm的过程:
在这里插入图片描述
return是去监听一些不可达的消息:如因为交换机不存在而导致的消息不可达。return发现有些消息不可达以后就可以在实现类中进行补偿。

代码:
consumer:

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;


@Component
@RabbitListener(queues = "hello")
public class Consumer {

    @RabbitHandler
    public void process(String hello,Channel channel, Message message) throws IOException {
        System.out.println("HelloReceiver收到  : " + hello +"收到时间"+new Date());
        try {
            //告诉服务器收到这条消息 已经被我消费了 可以在队列删掉 这样以后就不会再发了 否则消息服务器以为这条消息没处理掉 后续还会在发
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            System.out.println("receiver success");
        } catch (IOException e) {
            e.printStackTrace();
            //丢弃这条消息
            //channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
            System.out.println("receiver fail");
        }

    }
}

produce:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Date;


@RunWith(SpringRunner.class)
@SpringBootTest
public class Produce implements RabbitTemplate.ReturnCallback, RabbitTemplate.ConfirmCallback {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RabbitTemplate rabbitTemplate;

    // 发送消息
    @Test
    public void send(){
        String context = "你好现在是 " + new Date() +"";
        System.out.println("HelloSender发送内容 : " + context);
//        this.rabbitTemplate.setConfirmCallback(this);
        this.rabbitTemplate.setReturnCallback(this);

        // 消息的confirm
        this.rabbitTemplate.setConfirmCallback(this);
        this.rabbitTemplate.convertAndSend("hello", context);
    }

    // 消息监听
    @Override
    public void returnedMessage(Message message, int i, String s, String s1, String s2) {
        System.out.println("消息:"+message.getMessageProperties().getCorrelationId() +
                "错误码:"+i +
                "失败原因:"+s+
                "交换器:"+s1+
                "路由key:"+s2);
    }

    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            System.out.println("消息确认成功cause:"+cause);
        } else {
            //处理丢失的消息
            System.out.println("消息确认失败:"+correlationData.getId()+"#cause"+cause);
        }
    }
}

配置queue


import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitConfig {
    @Bean
    public Queue QueueA() {
        return new Queue("hello");
    }
}

测试confirm:
在这里插入图片描述

测试return:
在这里插入图片描述

4. 消费端限流

Qos限流:
(1)配置手动ACK:

# 开启手动ACK
spring.rabbitmq.listener.direct.acknowledge-mode=manual
spring.rabbitmq.listener.simple.acknowledge-mode=manual

(2)qos参数说明:代码仍然使用上面3中的代码,只是增加了一行qos的代码
在这里插入图片描述

5. 重回队列

定义:对没有处理的消息。重新投入broker(一般设置为false)

重回队列会回到队列的尾部。

ps:还是原来的代码,只是在接收数据失败的时候加了noack,第三个参数表示是否重回队列。

在这里插入图片描述

6. TTL

定义:Time To Live 表示消息的过期时间,可以是某个队列的过期时间(队列上的数据到达了时间就会过期),也可以是某个消息的过期时间。

为某个队列设置过期时间:
在这里插入图片描述

为某一条消息设置过期时间

rabbitTemplate.convertAndSend("direct.pay.exchange", "OrderPay", user,
                    message -> {
                        // 设置5秒过期
                        message.getMessageProperties().setExpiration("15000");
                        return message;
                    },
                    correlationData);

7. 死信队列

当某个消息没有消费者去消费就会变成死信队列。
在这里插入图片描述
死信队列中的消息都是无法被消费者接收到的消息,最后就放入到了死信队列中。
在这里插入图片描述

手动设置死信队列

在这里插入图片描述
死信队列会接受带有对应参数的队列。
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值