RabbitMQ------其他知识点(幂等性、优先级队列、惰性队列)(九)

RabbitMQ------其他知识点()(九)

幂等性

用户对于统一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生副作用。同一次还款,通过多次点击不会生成多条还款记录,一个人的注册按钮,多次点击不会生成多条用户信息。

解决思路

MQ消费者的幂等性的解决一般使用全局ID,或者写一个唯一标识比如时间戳,或者UUID或者订单消费者MQ中的消息,也可以利用MQ的该id来判断,或者可按自己的规则生成一个全局唯一id,每次消费消息时用该id先判断该消息是否已消费过。

消费端的幂等性保障

业界主流的幂等性有两种操作:1.唯一ID+指纹码机制,利用数据库主键去重, 2.利用redis的原子性去实现。

唯一ID+指纹码机制

指纹码:基本上都是由业务规则拼接而成,但是一定要保证唯一性。然后利用查询语句进行判断这个id是否存在数据库中。
优势:实现简单,一个拼接加上查询判断是否重复。
劣势:高并发时,单个数据库有写入性能瓶颈,当然也可以采用分库分表提升性能。

Redsi原子性(建议使用)

利用Redis执行setnx命令(只有不存在时候才设置),具有天然幂等性,从而实现不重复消费

优先级队列

对于同样的消息,有优先级处理,优先级高的,优先处理。如果发现是一个大客户的小新,就给与比较高的优先级,否则采用默认优先级。
队列的先进先出。
消费者在获取优先级队列消息时,是先把消息进行排队,排完队再获取。
优先级队列的优先级是0-255,却大,越优先被消费。

页面配置

在管理页面中,点击Queues—》Add a new queue-----》Maxium priority
点击后,会在Arguments中,自动带入参数 x-max-pripority
可以在value,中输入0-255之间的数字,但是建议10,数字越大,排序时开销也越大。
在这里插入图片描述

代码配置

1.首先在队列的代码中添加优先级

parms.put("x-max-priority", 10)
channel.queueDeclare("hello",true,false,false,parms);

2.发消息时,设置消息的优先级。
优先级别在队列优先级的范围内。

new AMQP.BasicProperties().builder().priority(5).builder();

只有队列和消息同时设置优先级,才能够使用该功能
且 消费者需要等待消息已经发送到队列中才能够去消费,应为此时才有机会对消息进行排序。
【将需要排序的消息,全部,发送到队列中后,消费者再消费】

示例代码:
配置类中新增优先级队列

    //优先级队列
    public static final String PRIPORITY_QUEUE_NAME = "pripority_queue";
    //声明 优先级队列
    @Bean("priorityQueue")
    public Queue priporityQueue(){
        //创建队列的两种方式
        //QueueBuilder.durable(CONFIRM_QUEUE_NAME).build();
        HashMap<String, Object> arguments = new HashMap<>();
        arguments.put("x-max-priority",10);
        return  new Queue(PRIPORITY_QUEUE_NAME,true,false,false,arguments);
    }

生产者:

    //开始发消息
    @GetMapping("/sendExpirationMessage/{message}")
    public void sendPriMsg(@PathVariable String message){
        log.info("当前时间:{},发送一条消息给优先级队列:{},优先级为:{}ms",new Date().toString(),message);

        /**
         * 交换机
         * routingkey
         * message
         * Priority,可以设置存活时间
         */
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
                @Override
                public Message postProcessMessage(Message message) throws AmqpException {
                    message.getMessageProperties().setPriority(finalI);
                    return message;
                }
            };
            rabbitTemplate.convertAndSend("X","XC","优先级的队列:"+message,messagePostProcessor);
        }
        
    }

结论:可以实现优先级高的消息被优先消费。
但是也需要实现消息堆积
1.自己模拟的话,只能先启动生产者发消息,再启动消费者进行消费。
按这个思路生产上,应该是…
通过定时任务的方式开启消费者。

2.或者消费者一直启动,能否通过配置或者代码的方式,实现RabbitMQ对消息进行堆积操作?遗留问题

惰性队列

惰性队列会尽可能的将消息存入磁盘中,在消费者消费到相应的消息时,才会被加载到内存中。
使用场景:消费者下线了,宕机了或者由于维护而关闭了,导致长时间内不能消费消息时,造成堆积时,惰性队列就很有必要了。

两种模式

队列具有两种模式:default和lazy,默认的为default模式,lazy模式就是惰性队列的模式,可以通过调用channel.queueDeclare方法的时候再参数中设置。也可以通过Policy的方式设置。
两种方式都设置的话,Policy的方式具有更高的优先级。
如果通过声明的方式改变已有队列的模式的话,只能先删除队列,再重新声明一个新的。
声明方式设置:

HashMap<String, Object> arguments = new HashMap<>();
        arguments.put("x-queue-mode","lazy");
        return  new Queue(PRIPORITY_QUEUE_NAME,true,false,false,arguments);
或者
channel.queueDeclare("myqueue",false,false,false,arguments);

页面设置:
与页面设置优先级队列一样,选择Lazy mode,会自动将参数点出来。

结论:在发送1百万条消息时,每条消息大概占1KB的情况下,普通队列占用内存时1.2GB,而惰性队列仅仅占用1.5MB(因为只放在磁盘中,内存中仅存放索引)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值