以下文章来源于Java旅途 ,作者Java旅途

Java旅途

坚持原创,坚持分享

一 重复消息

为什么会出现消息重复?消息重复的原因有两个:1.生产时消息重复,2.消费时消息重复。

1.1 生产时消息重复

由于生产者发送消息给MQ,在MQ确认的时候出现了网络波动,生产者没有收到确认,实际上MQ已经接收到了消息。这时候生产者就会重新发送一遍这条消息。

生产者中如果消息未被确认,或确认失败,我们可以使用定时任务+(redis/db)来进行消息重试。

@Component@Slf4Jpublic class SendMessage {    @Autowired    private MessageService messageService;    @Autowired    private RabbitTemplate rabbitTemplate;    // 最大投递次数    private static final int MAX_TRY_COUNT = 3;    /**     * 每30s拉取投递失败的消息, 重新投递     */    @Scheduled(cron = "0/30 * * * * ?")    public void resend() {        log.info("开始执行定时任务(重新投递消息)");        List msgLogs = messageService.selectTimeoutMsg();        msgLogs.forEach(msgLog -> {            String msgId = msgLog.getMsgId();            if (msgLog.getTryCount() >= MAX_TRY_COUNT) {                messageService.updateStatus(msgId, Constant.MsgLogStatus.DELIVER_FAIL);                log.info("超过最大重试次数, 消息投递失败, msgId: {}", msgId);            } else {                messageService.updateTryCount(msgId, msgLog.getNextTryTime());// 投递次数+1                CorrelationData correlationData = new CorrelationData(msgId);                rabbitTemplate.convertAndSend(msgLog.getExchange(), msgLog.getRoutingKey(), MessageHelper.objToMsg(msgLog.getMsg()), correlationData);// 重新投递                log.info("第 " + (msgLog.getTryCount() + 1) + " 次重新投递消息");            }        });        log.info("定时任务执行结束(重新投递消息)");    }}

1.2消费时消息重复

消费者消费成功后,再给MQ确认的时候出现了网络波动,MQ没有接收到确认,为了保证消息被消费,MQ就会继续给消费者投递之前的消息。这时候消费者就接收到了两条一样的消息。

修改消费者,模拟异常

@RabbitListener(queuesToDeclare = @Queue(value = "javatrip", durable = "true"))public void receive(String message, @Headers Map headers, Channel channel) throws Exception{    System.out.println("重试"+System.currentTimeMillis());    System.out.println(message);    int i = 1 / 0;}

配置yml重试策略

spring:  rabbitmq:    listener:      simple:        retry:          enabled: true # 开启消费者进行重试          max-attempts: 5 # 最大重试次数          initial-interval: 3000 # 重试时间间隔

由于重复消息是由于网络原因造成的,因此不可避免重复消息。但是我们需要保证消息的幂等性

二 如何保证消息幂等性

让每个消息携带一个全局的唯一ID,即可保证消息的幂等性,具体消费过程为:

  1. 消费者获取到消息后先根据id去查询redis/db是否存在该消息。
  2. 如果不存在,则正常消费,消费完毕后写入redis/db。
  3. 如果存在,则证明消息被消费过,直接丢弃。

生产者

@PostMapping("/send")public void sendMessage(){    JSONObject jsonObject = new JSONObject();    jsonObject.put("message","Java旅途");    String json = jsonObject.toJSONString();    Message message = MessageBuilder.withBody(json.getBytes()).setContentType(MessageProperties.CONTENT_TYPE_JSON).setContentEncoding("UTF-8").setMessageId(UUID.randomUUID()+"").build();    amqpTemplate.convertAndSend("javatrip",message);}

消费者

@Component@RabbitListener(queuesToDeclare = @Queue(value = "javatrip", durable = "true"))public class Consumer {    @RabbitHandler    public void receiveMessage(Message message) throws Exception {        Jedis jedis = new Jedis("localhost", 6379);        String messageId = message.getMessageProperties().getMessageId();        String msg = new String(message.getBody(),"UTF-8");        System.out.println("接收到的消息为:"+msg+"==消息id为:"+messageId);        String messageIdRedis = jedis.get("messageId");        if(messageId == messageIdRedis){            return;        }        JSONObject jsonObject = JSONObject.parseObject(msg);        String email = jsonObject.getString("message");        jedis.set("messageId",messageId);    }}

如果需要存入db的话,可以直接将这个ID设为消息的主键,下次如果获取到重复消息进行消费时,由于数据库主键的唯一性,则会直接抛出异常。

rabbitmq 集群保证顺序消费_随笔《RabbitMQ》如何保证消息不被重复消费相关推荐

  1. RabbitMQ——RabbitMQ集群原理

    摘要 主要围绕运维层面展开论述,主要包括集群搭建.日志查看.故障恢复.集群迁移.集群监控这几个方面. RabbitMQ集群搭建 如果RabbitMQ 服务器遇到内存崩溃.机器掉电或者主板故障等情况,该 ...

  2. RabbitMQ集群原理介绍

    文章目录 一.RabbitMQ默认集群原理 1. RabbitMQ集群元数据的同步 2. 为何RabbitMQ集群仅采用元数据同步的方式 3. RabbitMQ集群发送/订阅消息的基本原理 4. 客户 ...

  3. rabbitmq集群部署及配置

    rabbitmq集群部署及配置 文章目录 rabbitmq集群部署及配置 前言 一.原理介绍 二.部署方案 1.环境介绍 2.部署过程 小结 前言 消息中间件rabbitmq,一般以集群方式部署,主要 ...

  4. 部署RabbitMQ集群

    RabbitMQ集群实操手册 实战案例--部署RabbitMQ集群 案例目标 了解RabbitMQ服务的安装与配置. 了解RabbitMQ集群的配置架构. 了解RabbitMQ集群的使用. 案例分析 ...

  5. hbase1.1.1 连接集群_除了HAProxy,RabbitMQ集群还可以这样用

    全网最简单的安装手册 // 安装erlang wget https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm. ...

  6. RabbitMQ集群搭建(七)

    先来介绍一下RabbitMQ集群 RabbitMQ集群有两种模式,一种是普通模式,即默认的集群模式,另外一种为镜像模式,可以把队列做成镜像队列 我们在学习两种模式之前,先来了解下一些关于RabbitM ...

  7. Rabbitmq集群高可用测试

    Rabbitmq集群高可用 RabbitMQ是用erlang开发的,集群非常方便,因为erlang天生就是一门分布式语言,但其本身并不支持负载均衡. Rabbit模式大概分为以下三种:单一模式.普通模 ...

  8. Rabbitmq集群,镜像队列和分布式原理

    前言 基于前两次的分享会,结合rabbitmq相关知识,做一个小结.说明一致性的设计思想,在此说明相关的基础理论. CAP定理: 在计算机科学里,CAP定理又被称作布鲁尔定理(Brewer theor ...

  9. 自己的笔记本上设置RabbitMQ集群

    RabbitMQ 是用 erlang 开发的,集群非常方便,因为 erlang 天生就是一门分布式语言,但其本身并不支持负载均衡.Rabbit 模式大概分为以下三种:单一模式.普通模式和镜像模式. 单 ...

  10. RabbitMQ集群部署

    一般来说,RabbitMQ部署分布式集群架构有如下三种: 1.Cluster 2.Federation 3.Shovel 其中最常用的就是cluster模式(集群),它可以动态增加节点或减少,但只支持 ...

最新文章

  1. python学习手册翻译很差吗-为什么要翻译?值得坚持下去么?
  2. 32位微型计算机原理...,32位微型计算机原理·接口技术及其应用
  3. 危险!!!也许你的web网站或服务正在悄无声息地被SQL注入
  4. 使用Grab的实验平台进行混沌实验编排
  5. Ubuntu18.0.1 安装 anaconda conda cudnn pytorch-gpu
  6. 你的消息队列如何保证消息不丢失,且只被消费一次,这篇就教会你
  7. C#设计模式之8-组合模式
  8. 韩企全球首造72层3D NAND芯片 下半年或量产
  9. “腾讯持股比例提升”系误读!美团对外定增后腾讯持股比例降低
  10. html span设置外边距,行内元素内外边距探究:为何span设置上下margin和padding不起效...
  11. Excel解析的几种实现方式
  12. 雪花算法生成主键id
  13. 如何ajax上传图片,ajax上传图片文件
  14. win10 干净卸载anaconda
  15. js创建节点删除节点实例
  16. VCSA6.7移除添加vSAN磁盘组
  17. android判断两个图片相同,android中比较两张图片的相似度
  18. nn.Conv1d 理解
  19. java红包正态分布_红包分配算法
  20. maven 系列 02 - packing 类型

热门文章

  1. java rest httpclient_Httpclient与RestTemplate的比较(比httpClient更优雅的Restful URL访问)...
  2. go sqlite mysql_Go语言中使用SQLite数据库
  3. 玩转 SpringBoot 2 快速整合 Filter 注解版
  4. 手机通讯录备份代码实现二
  5. androidStudio导入库文件
  6. 基于JAVA+SpringMVC+Mybatis+MYSQL的体育器材管理系统
  7. linux mint 设置分辨率,Vmware中装Linux Mint 15 添加 1600x900分辨率
  8. 【JAVA面试】java面试题整理(4)
  9. 一些关于并行计算的科研思路
  10. OpenStack 云计算基础知识