本篇和大家分享的是关于rabbit的生产和消费方的一些实用的操作;正如文章标题,主要内容如producer的confirm和consumer的ack,这两者使用的模式都是用来保证数据完整性,防止数据丢失。

  • producer的confirm模式
  • consumer的ack模式

producer的confirm模式

首先,有这样一种业务场景1:a系统在做活动前,需要给用户的手机发送一条活动内容短信希望用户来参加,因为用户量有点大,所以通过往短信mq中插入数据方式,让短信服务来消费mq发短信;

此时插入mq消息的服务为了保证给所有用户发消息,并且要在短时间内插入完成(因此用到了异步插入方式(快速)),我们就需要知道每次插入mq是否成功,如果不成功那我们可以收集失败的信息后补发(因此confirm模式排上了用场);如图设计:

在springboot中可以使用基于amqp封装的工厂类来开启confirm模式,然后通过RabbitTemplate模板来设置回调函数,如下代码:

  1. ///region producer生产 - confirm模式
  2.  
  3. public RabbitTemplate getRabbitTemplate(RabbitTemplate.ConfirmCallback confirmCallback) {
  4. return this.getRabbitTemplate(this.connectionFactory(), confirmCallback);
  5. }
  6.  
  7. public RabbitTemplate getRabbitTemplate(CachingConnectionFactory connectionFactory, RabbitTemplate.ConfirmCallback confirmCallback) {
  8. RabbitTemplate template = new RabbitTemplate(connectionFactory);
  9. //product开启confirm模式
  10. connectionFactory.setPublisherConfirms(true);
  11. //设置confirm回调处理
  12. template.setConfirmCallback(confirmCallback);
  13. return template;
  14. }
  15. ///endregion

这里通过RabbitTemplate.ConfirmCallback函数编程来传递我们自定义的回调方法,如下收集confirm返回的结果信息:

  1. RabbitUtil rabbitUtil = new RabbitUtil(this.getFirstNode().getLink());
  2. RabbitTemplate template = rabbitUtil.getRabbitTemplate((a, b, c) -> {
  3. System.out.println("firstNodeTpl - ConfirmCallback的Id:" + a.getId() + ";状态:" + b + ";信息:" + c);
  4. });

最后再通过RabbitTemplate实例的convertAndSend方法发送mq信息,我们能够在日志中看到如下记录的信息:

这里的状态true:表示send成功,false:表示send失败;通常false的时候信息c会有响应的错误提示,这里把网络断开,如下错误提示:

consumer的ack模式

再来,有这样一种场景2:短信服务去消费mq队列信息时,倘若服务调用的运营商发送短信接口异常了(短信运营商接口欠费),我们此时的短信是发送失败的,用户也收不到短信,但是在默认(默认开启ack)前提下mq消息已经被消费了rabbit中没有记录了(kafka例外);想要mq消息在业务逻辑异常时还存在,那么可以使用ack方式;

在springboot中可以使用基于amqp封装的工厂类关闭自动ack模式,改为手动ack方式;只有当业务代码流程走完后,最后通过代码设置ack标识,来通知rabbit消息可以丢弃了;如果设置了手动模式后,又没有提交ack标识,那么mq中的消息一直存在无法释放(每次consumer消费后,rabbit会把noack的消息重复放入队列中):

  1. ///region consumer监听 - 手动ack
  2. public SimpleRabbitListenerContainerFactory listenerContainerFactory() {
  3. return this.listenerContainerFactory(this.connectionFactory());
  4. }
  5.  
  6. public SimpleRabbitListenerContainerFactory listenerContainerFactory(ConnectionFactory connectionFactory) {
  7. SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
  8. factory.setConnectionFactory(connectionFactory);
  9. //代码手动ack
  10. factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
  11. //开启消费者数量
  12. factory.setConcurrentConsumers();
  13. //每次接受数据量,默认250
  14. factory.setPrefetchCount();
  15. return factory;
  16. }
  17. ///endregion

通过连接工厂设置手动ack方式,然后获取mq消息后,走完正常业务逻辑,最后再手动通知ack释放消息,如下:

  1. @RabbitListener(containerFactory = "firstNodeListener", queues = {"${shenniu.rabbits.firstNode.queue}"})
  2. private void firstNodeListener(String msg, Channel channel, Message message) {
  3. try {
  4. long deliverTag = message.getMessageProperties().getDeliveryTag();
  5. System.out.println("firstNodeListener - 消费消息 [" + deliverTag + "] - " + msg);
  6. channel.basicAck(deliverTag, true);
  7. } catch (Exception ex) {
  8. }
  9. }

这里ack主要根据mq消息的唯一编号(deliverTag)来通知;如果我们不设置ack确认,那么消息状态会是这样如下rabbit管理后台:

rabbit - producer的confirm和consumer的ack模式的更多相关文章

  1. JAVA消息确认机制之ACK模式

    JMS API中约定了Client端可以使用四种ACK模式,在javax.jms.Session接口中: AUTO_ACKNOWLEDGE = 1    自动确认 CLIENT_ACKNOWLEDGE ...

  2. springboot集成rabbitmq并手动注册容器实现单个queue的ack模式

    原文:https://blog.csdn.net/qq_38439885/article/details/88982373 进入正题,本文会介绍两种实现rabbitmq的ack模式的方法,分别为: 一 ...

  3. kafka producer自定义partitioner和consumer多线程

    为了更好的实现负载均衡和消息的顺序性,Kafka Producer可以通过分发策略发送给指定的Partition.Kafka Java客户端有默认的Partitioner,平均的向目标topic的各个 ...

  4. springcloud服务提供producer and 服务调用consumer

    ---------------------------------producer------------------------------------------- 1.pom文件中,作为客户端的 ...

  5. RabbitMQ的transaction、confirm、ack三个概念的解释

    在使用RabbitMQ的过程中,肯定会遇到这样的几个概念:transaction.confirm.ack.本文介绍一下这几个概念,以及他们之间的关系. RabbitMQ是采用的AMQP协议,AMQP协 ...

  6. 在kafka/config/目录下面有3个配置文件参数说明(producer.properties。consumer.properties。server.properties)

    (1).producer.properties:生产端的配置文件 #指定kafka节点列表,用于获取metadata,不必全部指定 #需要kafka的服务器地址,来获取每一个topic的分片数等元数据 ...

  7. RocketMQ学习笔记(6)----RocketMQ的Client的使用 Producer/Consumer

    1.  添加依赖 pom.xml如下: <dependency> <groupId>org.apache.rocketmq</groupId> <artifa ...

  8. 如何创建Kafka客户端:Avro Producer和Consumer Client

    1.目标 - Kafka客户端 在本文的Kafka客户端中,我们将学习如何使用Kafka API 创建Apache Kafka客户端.有几种方法可以创建Kafka客户端,例如最多一次,至少一次,以及一 ...

  9. RabbitMQ 之消息确认机制(事务+Confirm)

    概述 在 Rabbitmq 中我们可以通过持久化来解决因为服务器异常而导致丢失的问题,除此之外我们还会遇到一个问题:生产者将消息发送出去之后,消息到底有没有正确到达 Rabbit 服务器呢?如果不错得 ...

随机推荐

  1. .gitignore文件我自己常用的配置

    我项目中一般不需要上传到git服务器上的有 .idea ------.idea目录 .mvn ------.mvn目录 .iml mvnw mvnw.cmd logs/ --- 我生成的日志文件目录 ...

  2. JAVA 基于TCP协议的一对一,一对多文件传输实现

    最近老师给我们上了多线程和TCP和UDP协议,其中一个要求就是我们用JAVA协议一个基于TCP和UDP这两种协议的一对一文件上传和一对多文件上传. 然后我就开始分析TCP和UDP这两个协议的特点,发现 ...

  3. 脱壳0-FSG壳-详细流程

    目录 @ 1 拿到当前加壳程序,用exeinfo/PeID 看一下信息 可以看出是很老的壳FSG. 分析: ​ Entry Point : 000000154,熟悉PE结构的知道,入口点(代码)揉进P ...

  4. 【转】解决eclipse连接不到genymotion的问题

    (1)很多朋友在使用genymotion开发安卓应用程序的时候,会遇见完全正确的安装但是在运行的时候仍然找不到,genymotion上的设备,在打开的devices上找不到如下图所示: (2)解决的方 ...

  5. 后端开发实践系列之二——领域驱动设计(DDD)编码实践

    Martin Fowler在<企业应用架构模式>一书中写道: I found this(business logic) a curious term because there are f ...

  6. Iterator-Java

    在Java中,Iterator的作用就是为了方便处理集合中的元素.例如获取和删除集合中的元素. 在JDK8,Iterator接口提供了如下方法: 迭代器Iterator最基本的两个方法是next()和 ...

  7. 百度网盘 人工智能书籍【Tensorflow和深度学习】

    链接:https://pan.baidu.com/s/1ejCvwn08ILI2fMhBEdXR8w 提取码:6pk9

  8. wscript.shell 使用

    <%@ Page Language="VB" validateRequest = "false" aspcompat = "true" ...

  9. Spring条件注解@Conditional

    @Conditional是Spring4新提供的注解,它的作用是根据某个条件创建特定的Bean,通过实现Condition接口,并重写matches接口来构造判断条件.总的来说,就是根据特定条件来控制 ...

  10. LR(1)语法分析器生成器(生成Action表和Goto表)java实现(二)

    本来这次想好好写一下博客的...结果耐心有限,又想着烂尾总比断更好些.于是还是把后续代码贴上.不过后续代码是继续贴在BNF容器里面的...可能会显得有些臃肿.但目前管不了那么多了.先贴上来吧hhh.说 ...