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

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

producer的confirm模式

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

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

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

     ///region producer生产 - confirm模式

     public RabbitTemplate getRabbitTemplate(RabbitTemplate.ConfirmCallback confirmCallback) {
return this.getRabbitTemplate(this.connectionFactory(), confirmCallback);
} public RabbitTemplate getRabbitTemplate(CachingConnectionFactory connectionFactory, RabbitTemplate.ConfirmCallback confirmCallback) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
//product开启confirm模式
connectionFactory.setPublisherConfirms(true);
//设置confirm回调处理
template.setConfirmCallback(confirmCallback);
return template;
}
///endregion

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

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

最后再通过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的消息重复放入队列中):

     ///region consumer监听 - 手动ack
public SimpleRabbitListenerContainerFactory listenerContainerFactory() {
return this.listenerContainerFactory(this.connectionFactory());
} public SimpleRabbitListenerContainerFactory listenerContainerFactory(ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
//代码手动ack
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
//开启消费者数量
factory.setConcurrentConsumers();
//每次接受数据量,默认250
factory.setPrefetchCount();
return factory;
}
///endregion

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

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

这里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. python的socket模块

    sk.bind(address) s.bind(address) 将套接字绑定到地址.address地址的格式取决于地址族.在AF_INET下,以元组(host,port)的形式表示地址. sk.li ...

  2. LiteDB源码解析系列(3)索引原理详解

    在这一章,我们将了解LiteDB里面几个基本数据结构包括索引结构和数据块结构,我也会试着说明前辈数据之巅在博客中遇到的问题,最后对比mysql进一步深入了解LiteDB的索引原理. 1.LiteDB的 ...

  3. Java面向对象16种原则

    一   类的设计原则   1 依赖倒置原则-Dependency Inversion Principle (DIP) 2 里氏替换原则-Liskov Substitution Principle (L ...

  4. Hadoop自学系列集(二) ---- CentOS下安装JDK

    上篇我们讲述了如何使用VMware安装CentOS系统,接下来就看如何安装我们最为熟悉的jdk吧!安装前先看看系统上有没有安装过jdk,输入java -version,如果查询出了其他版本的jdk版本 ...

  5. @Validated和@Valid的区别?校验级联属性(内部类)

    每篇一句 NBA里有两大笑话:一是科比没天赋,二是詹姆斯没技术 相关阅读 [小家Java]深入了解数据校验:Java Bean Validation 2.0(JSR303.JSR349.JSR380) ...

  6. 对ThreadLocal的一些理解

    ThreadLocal也是在面试过程中经常被问到的,本文主要从以下三个方面来谈对ThreadLocal的一些理解: ThreadLocal用在什么地方 ThreadLocal一些细节 ThreadLo ...

  7. 今天代码中接触到了一个新的东西。js的上下自动滚动,无缝对接。

    js的上下自动滚动,无缝对接.为什么会用到这个东西呢?因为我在做公司的官网项目的修改的时候.有一个产品介绍的页面,会有很多的产品出现在,中间部分的列表里.但是又不能够使用分页.所以我就在想如果,列表数 ...

  8. vue通信、传值的多种方式(详细)

    转载自https://blog.csdn.net/qq_35430000/article/details/79291287

  9. 【游记】NOIP2019复赛

    声明 我的游记是一个完整的体系,如果没有阅读过往届文章,阅读可能会受到障碍. ~~~上一篇游记的传送门~~~ 前言 (编辑中)

  10. python basemap readshapefile二三事

    今天要用到basemap读取shp文件报错,查了很多资料,都没有解决. 先是: fig,ax = plt.subplots(figsize=(15,10)) from mpl_toolkits.bas ...