问题

今天遇到一个问题,发送MQ消息的时候需要保证不会重复发送,注意不是可靠到达(可靠到达可以通过消息确认机制和回调接口保证),这里保证的是不会生产多条一样的消息。

方法

综合讨论下来决定使用Redis缓存来解决,因为相比于将记录插入数据库Redis更为高效和便捷。

检验是否已经发送

在发送消息之前根据相关信息组合成keyRedis中查找,找到后检测值是否为存在并且是否为设定的值,若存在且与设定的值一样,则返回false,说明该消息已经发送过了。

    public boolean isSend(String messageType, Long bizId, int hashCode) {
// 根据消息类型、业务id和哈希值组合成key
String key = this.genKey(messageType, bizId, hashCode);
Long value = super.get(key); if (value != null && value.equals(DEFAULT_VALUE)) {
return false;
} return true;
} /**get方法*/
public V get(K key) {
if (key == null) {
return null;
} else {
try {
// 在key前添加前缀和名字,并将原来的key进行json序列化
String realKey = this.genRealKey(key);
String content = (String)this.redisTemplate.opsForValue().get(realKey);
// 若get到的值不为null则进行json反序列化
return content == null ? null : this.valueSerializer.deserialize(content);
} catch (Exception e) {
CACHE.error("", key.toString(), "", "0", e);
return null;
}
}
}

以上就是检验消息是否重复的方法,需要注意的是JSON序列化,因为Redis默认使用的是JDK序列化,这种序列化后的内容不仅多而且不易于阅读,因此将其改为Json序列化。

发送后添加缓存

在发送消息的时候会先在Redisput一个以相关信息组合为keyvalue为默认值的记录,过期时间为5min

    public void sendMessage(String messageType, Long bizId, int hashCode) {
super.put(genKey(messageType, bizId, hashCode), DEFAULT_VALUE);
} /**put方法*/
public void put(K key, V value) {
try {
if (key != null && null != value) {
// 进行json序列化
String content = this.valueSerializer.serialize(value);
this.redisTemplate.opsForValue().set(this.genRealKey(key), content, this.expires, this.timeUnit);
}
} catch (Throwable e) {
e.printStackTrace();
}
}

发送消息方法

最后的发送消息方法大致代码如下:

    public void sendMQMessage(Long bizId, String messageTemplateCode, String msg, int msgHashCode, String exchange, String routingKey) {
//加入缓存
boolean send = true;
//String messageType = MessageTypeUtil.getMessageType(messageTemplateCode);
if (bizId != null) {
// 检测是否已经发送
send = sendMessageCache.isSend(messageTemplateCode, bizId, msgHashCode);
} //发送mq消息
if (send) {
if (bizId != null) {
// 加入缓存
sendMessageCache.sendMessage(messageTemplateCode, bizId, msgHashCode);
}
// 发送消息
messageSender.send(exchange, routingKey, msg);
}
}

使用Redis防止重复发送RabbitMQ消息的更多相关文章

  1. RabbitMQ,RocketMQ,Kafka 事务性,消息丢失和消息重复发送的处理策略

    消息队列常见问题处理 分布式事务 什么是分布式事务 常见的分布式事务解决方案 基于 MQ 实现的分布式事务 本地消息表-最终一致性 MQ事务-最终一致性 RocketMQ中如何处理事务 Kafka中如 ...

  2. rabbitmq 重复ACK导致消息丢失

    rabbitmq 重复确认导致消息丢失 背景 rabbitmq 在应用场景中,大多采用工作队列 work-queue的模式. 在一个常见的工作队列模式中,消费者 worker 将不断的轮询从队列中拉取 ...

  3. RabbitMQ系列(四)RabbitMQ事务和Confirm发送方消息确认——深入解读

    RabbitMQ事务和Confirm发送方消息确认--深入解读 RabbitMQ系列文章 RabbitMQ在Ubuntu上的环境搭建 深入了解RabbitMQ工作原理及简单使用 RabbitMQ交换器 ...

  4. RabbitMQ事务和Confirm发送方消息确认

    RabbitMQ事务和Confirm发送方消息确认——深入解读 RabbitMQ系列文章 RabbitMQ在Ubuntu上的环境搭建 深入了解RabbitMQ工作原理及简单使用 RabbitMQ交换器 ...

  5. 在服务端处理同步发送小消息的性能上Kafka>RocketMQ>RabbitMQ

    在发送小消息的场景中,三个消息中间件的表现区分明显: Kafka的吞吐量高达17.3w/s,远超其他两个产品.这主要取决于它的队列模式保证了写磁盘的过程是线性IO.此时broker磁盘IO已达瓶颈. ...

  6. RabbitMQ如何保证发送端消息的可靠投递

    消息发布者向RabbitMQ进行消息投递时默认情况下是不返回发布者该条消息在broker中的状态的,也就是说发布者不知道这条消息是否真的抵达RabbitMQ的broker之上,也因此会发生消息丢失的情 ...

  7. RabbitMQ消息确认(发送确认,接收确认)

    前面几篇记录了收发消息的demo,今天记录下关于 消息确认方面的 问题. 下面是几个问题: 1.为什么要进行消息确认? 2.rabbitmq消息确认 机制是什么样的? 3.发送方如何确认消息发送成功? ...

  8. 【转载】java实现rabbitmq消息的发送接受

    原文地址:http://blog.csdn.net/sdyy321/article/details/9241445 本文不介绍amqp和rabbitmq相关知识,请自行网上查阅 本文是基于spring ...

  9. Rabbitmq消息队列(二) Hello World! 模拟简单发送接收

    1.简介 RabbitMQ是消息代理:它接受和转发消息.你可以把它当作一个邮局:当你把你要邮寄的邮件放在信箱里时,你可以肯定Postman先生最终会把邮件送到你的收件人那里.在这个比喻中,Rabbit ...

  10. 小程序:前端防止用户重复提交&即时消息(IM)重复发送问题解决

    背景: 最近参与开发的小程序,涉及到即时消息(IM)发送的功能: 聊天界面如下,通过键盘上的[发送]按钮,触发消息发送功能 问题发现: 功能开发完毕,进入测试流程:测试工程师反馈说: 在Android ...

随机推荐

  1. php日志分割

    为了方便查看php错误日志信息,将php的日志按照时间进行分割,器脚本如下 phpPid='/usr/local/webserver/php-5.3.27/var/run/php-fpm.pid' p ...

  2. FFmpeg转码音视频时间戳设置分析

    音频时间戳设置 以下代码基于FFmpeg n5.1.2进行分析 以下文档中有关音频的具体时间戳数据来自以下转码命令: ./ffmpeg_g -rw_timeout 5000000 -i 'rtmp:/ ...

  3. Linux系统搭建性能测试监控体系

    一.安装Grafana 1.Grafana介绍(默认端口3000): Grafana是一个开源的监控和可视化工具,用于显示和跟踪各种指标,数据和日志,支持多种源,包括influxDB.promethe ...

  4. 什么是静态方法?@staticmethod装饰器怎么用?

    填坑(@staticmethod装饰器----静态方法声明) > 在学习的时候看到很多人都在用@Staticmethod这个装饰器来修饰类方法,这就让我好奇了这个独特的装饰器到底是个啥?咋就受到 ...

  5. JUC.Condition学习笔记

    目录 Condition的概念 大体实现流程 I.初始化状态 II.await()*作 III.signal()*作 3个主要方法 Condition的数据结构 线程何时阻塞和释放 await()方法 ...

  6. element table 合并同类项并输出后台返回数据

    table的样式如下 后台返回的数据格式是按照横着来的,因为表头是经过处理的,而且是作为独立出来的数据返给前端的,所以当我们进行数据填充的时候需要用到后台返回的完整的数据,要想一一对应的话,我们需要进 ...

  7. Yii2之model

    记录model常用方法 between: $model->andFilterWhere(['between','apply_time',$startTime,$endTime])

  8. 简述GoLang优势与生态

    开门见山,一睹golang的风采 性能优势 部署运维成本低 编码格式统一:测试简单 1. 性能优势 Go 语言被称为是:"21世纪的C语言",虽然这个帽子戴的有点高,不妨这里给大家 ...

  9. [Cnblogs.Architecture][v20.5.1] 使用 AddLongToJsonConverter() 将 long 序列化为 string

    场景 浏览器的 JSON 反序列化无法完整将 long 类型转换为 number,最后一位会被四舍五入. 因此需要将 long 类型转为 string 发送到前端. 适用版本 v20.5.1 使用方法 ...

  10. uniapp h5 和 小程序互相传值

    小程序端 <template> <div> <web-view :webview-styles="webviewStyles" :src=" ...