RabbitMQ-消息队列:优先级队列、惰性队列

20、优先级队列

在我们系统中有一个订单催付的场景,我们的客户在天猫下的订单,淘宝会及时将订单推送给我们,如果在用户设定的时间内未付款那么就会给用户推送一条短信提醒,很简单的一个功能对吧。

但是,天猫商家对我们来说,肯定是要分大客户和小客户的对吧,比如像苹果、小米这样大商家一年起码能给我们创造很大的利润,所以理应当然,他们的订单必须得到优先处理,而曾经我们的后端系统是使用 redis 来存放的定时轮询,大家都知道 redis 只能用 List 做一个简简单单的消息队列,并不能实现一个优先级的场景,所以订单量大了后采用 RabbitMQ 进行改造和优化,如果发现是大客户的订单给一个相对比较高的优先级, 否则就是默认优先级。

按照优先级在队列上排队,优先级越大,越往前

控制台上添加队列的优先级

代码中添加优先级

队列中代码添加优先级

java 复制代码
Map<String, Object> params = new HashMap();
params.put("x-max-priority", 10);
channel.queueDeclare("hello", true, false, false, params);

消息中代码添加优先级

java 复制代码
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().priority(10).build();

注意事项:

要让队列实现优先级需要做的事情有如下事情:1.队列需要设置为优先级队列2.消息需要设置消息的优先级3.消费者需要等待消息已经发送到队列中才去消费因为,这样才有机会对消息进行排序。

a.消息生产者

java 复制代码
public class PriorityProducer {
    private static final String QUEUE_NAME = "hello";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();

        //给消息赋予一个 priority 属性
        AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().priority(10).build();

        for (int i = 1; i < 11; i++) {
            String message = "info" + i;
            if (i == 5) {
                channel.basicPublish("", QUEUE_NAME, properties, message.getBytes());
            } else {
                channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
            }
            System.out.println("发送消息完成:" + message);
        }
    }

}

b.消息消费者

java 复制代码
public class PriorityConsumer {
    private final static String QUEUE_NAME = "hello";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();

        //设置队列的最大优先级 最大可以设置到 255 官网推荐 1-10 如果设置太高比较吃内存和 CPU
        Map<String, Object> params = new HashMap();
        params.put("x-max-priority", 10);
        channel.queueDeclare(QUEUE_NAME, true, false, false, params);

        //推送的消息如何进行消费的接口回调
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody());
            System.out.println(message);
        };
        //取消消费的一个回调接口 如在消费的时候队列被删除掉了
        CancelCallback cancelCallback = (consumerTag) -> {
            System.out.println("消息消费被中断");
        };

        channel.basicConsume(QUEUE_NAME, true, deliverCallback, cancelCallback);
    }

}

测试效果:

web界面上,注册的队列上有 pri:优先级的标志

优先级更高,优先接收消息

21、惰性队列

使用场景

RabbitMQ 从 3.6.0 版本开始引入了惰性队列的概念。惰性队列会尽可能的将消息存入磁盘中,而在消费者消费到相应的消息时才会被加载到内存中 ,它的一个重要的设计目标是能够支持更长的队列,即支持更多的消息存储当消费者由于各种各样的原因 (比如消费者下线、宕机亦或者是由于维护而关闭等) 而致使长时间内不能消费消息造成堆积时,惰性队列就很有必要了

默认情况下,当生产者将消息发送到 RabbitMQ 的时候,队列中的消息会尽可能的存储在内存之中, 这样可以更加快速的将消息发送给消费者。即使是持久化的消息,在被写入磁盘的同时也会在内存中驻留一份备份。当 RabbitMQ 需要释放内存的时候,会将内存中的消息换页至磁盘中,这个操作会耗费较长的时间,也会阻塞队列的操作,进而无法接收新的消息。虽然 RabbitMQ 的开发者们一直在升级相关的算法, 但是效果始终不太理想,尤其是在消息量特别大的时候。

两种模式

队列具备两种模式:defaultlazy默认的为 default 模式 ,在 3.6.0 之前的版本无需做任何变更。lazy 模式即为惰性队列的模式 ,可以通过调用 channel.queueDeclare 方法的时候在参数中设置,也可以通过 Policy 的方式设置,如果一个队列同时使用这两种方式设置的话,那么 Policy 的方式具备更高的优先级。 如果要通过声明的方式改变已有队列的模式的话,那么只能先删除队列,然后再重新声明一个新的。

在队列声明的时候可以通过 "x-queue-mode" 参数来设置队列的模式,取值为 "default" 和 "lazy"。下面示例中演示了一个惰性队列的声明细节:

java 复制代码
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-queue-mode", "lazy");
channel.queueDeclare("myqueue", false, false, false, args);

内存开销对比

在发送 1 百万条消息,每条消息大概占 1KB 的情况下,普通队列占用内存是 1.2GB,而惰性队列仅仅 占用 1.5MB。

RabbitMQ-消息队列:优先级队列、惰性队列 到此完结,笔者归纳、创作不易,大佬们给个3连再起飞吧

相关推荐
不吃香菜学java6 小时前
Redis的java客户端
java·开发语言·spring boot·redis·缓存
yaoyouzhong7 小时前
分布式与集群,二者区别是什么?
分布式
橙露8 小时前
SpringBoot 整合 MinIO:分布式文件存储上传下载
spring boot·分布式·后端
小眼哥8 小时前
SpringBoot整合Vue代码生成exe运行程序以及windows安装包
vue.js·windows·spring boot
Ulyanov10 小时前
Apache Kafka在雷达仿真数据流处理中的应用
分布式·python·kafka·apache·雷达电子战
shark222222211 小时前
能懂!基于Springboot的用户增删查改(三层设计模式)
spring boot·后端·设计模式
IGAn CTOU12 小时前
王炸级更新!Spring Boot 3.4 正式发布,新特性真香!
java·spring boot·后端
Ssan PRIN12 小时前
深度掌握 RabbitMQ 消息确认(ACK)机制,确保消息万无一失
分布式·rabbitmq
切糕师学AI13 小时前
深入理解 CAP 定理:分布式系统中的一致性、可用性与分区容错
分布式·cap
indexsunny14 小时前
互联网大厂Java面试实战:核心技术与微服务架构在电商场景中的应用
java·spring boot·redis·kafka·maven·spring security·microservices