阿里二面:要保证消息不丢失,又不重复,消息队列怎么选型?

大家好,我是君哥。

在使用消息队列时,有两个经常让我们烦恼的问题,消息丢失和消息重复。那我们在做技术选型时,有没有一个消息队列能解决消息丢失和消息重复这两个问题呢?

消息丢失

图片

如上图,从生产者发送消息,Broker 保存消息,消费者消费消息,每一个环节都有可能丢失消息。

发送丢失

生产者发送消息时,如果处理不当,很可能会造成消息丢失。

生产者发送消息,主流消息队列都支持同步发送和异步发送。如果使用同步发送,生产者发送消息后,会同步等待 Broker 返回的 ACK,收到 ACK 消息,就认为消息发送成功。如果长时间没有收到,则会认为消息发送失败,需要进行重试。

同步发送可以保证消息不丢失,但是会有性能问题,所以多数情况会选择异步发送。异步发送如何保证消息不丢失呢?主流消息队列(比如 Kafka 和 RocketMQ)实现方法基本类似,使用回调函数来实现。下面看一下 Kafka 的异步发送代码:

producer.send(record, new Callback() {public void onCompletion(RecordMetadata metadata, Exception exception) {if (exception != null) {logger.error("发送消息失败:", exception);}if (metadata != null) {logger.info("消息发送成功");}}
});

消息存储

生产者发送消息成功,也不能保证消息绝对不丢失。因为即使消息发送到 Broker,如果在消费者拉取到消息之前,Broker 宕机了,消息还没有落盘,也会导致消息丢失。

在存储阶段要保证消息不丢失,可以考虑几个方面:

同步刷盘

采用异步刷盘,如果在消息落盘之前 Broker 宕机了,就会造成消息丢失。而采用同步刷盘,等待消息落盘之后,再给 Sender 返回发送成功,可以从消息发送环节保证消息不丢失。

图片

在 RocketMQ 中,把 flushDiskType 参数配置为 SYNC_FLUSH 就可以开启同步刷盘。

Broker 集群

如果 Broker 集群中只有一个节点,即使消息落盘成功了,Broker 发送故障,在 Broker 恢复以前消费者也会拉取不到消息。而且如果 Broker 磁盘故障不可恢复,消息也会丢失。

采用 Broker 集群可以很好地解决这个问题。见下图:

图片

在 Broker 集群时,可以等待 2 个以上的节点同步消息完成后再给 Producer 返回成功。这样即使一个 Broker 挂了,也可以很容易找到替代的 Broker。

消息消费

消费者保证不丢失消息,需要消费完成后再给 Broker 返回 ACK。在主流的消息队列中,如果 Broker 收不到 ACK,都会给消费者再次发送这条消息。

有时候为了解决消息积压的问题,消费者拉取到消息后会直接返回 ACK,然后再异步执行消息处理逻辑。这样要保证消息不丢失,需要在返回 ACK 之前把消息保存到本地,比如持久化到数据库,后面可以取数据库保存的消息进行处理。

消息重复

消息重复一般有两个原因,一个是生产者发送消息后没有收到 ACK,然后进行重复发送,另一个原因是消费者消费完成后 Broker 没有收到 ACK,导致消息重复推送给消费者。

重复消息会对业务造成影响,比如电商场景中的重复支付、账务场景中的重复记账,对业务造成的影响都比较严重。

从目前主流的消息队列来看,并没有一个消息队列能解决消息重复消费的问题,只能在消费端做幂等处理。下面提供几个思路作为参考。

数据库唯一键约束

如果消息会落本地数据库,可以采用消息 ID 作为唯一键。如果消息不落数据库,可以将消息 ID 或者消息中其他唯一能标识消息的属性作为唯一键落业务数据表。

保存消费记录

我们也可以将消息 ID 保存 Redis,消费消息前判断消息 ID 是否已存在。

ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
Boolean result = valueOperations.setIfAbsent(messageId, messageId);
if (result) {//消费逻辑;
} else {logger.error("这条消息已经消费,跳过,消息ID:{}", messageId);
}

这里有一个注意点,如果消费失败了,需要删除 Redis 中保存的消息 ID。

总结

消息不丢失、不重复是消息队列的基本要求,但这个基本要求还是很难满足的。

消息丢失这个要求,主流消息队列通过消息重试和消息持久化的方式可以满足。

但消息重试也同时带来了消息重复的可能性,主流消息队列在解决重复消息的问题上并没有现成的方案,对不允许重复消费的场景,需要开发人员在消费端做幂等处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/415852.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序学习-17

attached最常用 推荐使用 lilfetimes 这种方法

【Linux】Linux进程间通信(四)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;Linux &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【Linux】…

基于嵌入式的智能智能通风系统

基于嵌入式的智能智能通风系统 功能说明 通过微信小程序控制窗户的开关状体以及倒计时开关和定时开关&#xff0c;小程序上实时显示当前温度湿度和光照强度。 功能展示 02智能通风系统 Mqtt服务器 http://www.yoyolife.fun/iot&#xff1a;Mqtt服务器&#xff0c;我是在这里注…

前端react入门day03-react获取dom与组件通信

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 受控表单绑定 React中获取DOM 组件通信 父传子 父传子-基础实现 父传子-props说明 父传子 - 特殊的…

J4 - ResNet与DenseNet结合

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 目录 环境模型设计模型效果展示总结与心得体会 环境 系统: Linux语言: Python3.8.10深度学习框架: Pytorch2.0.0cu118显卡&#xff1a;GT…

构建坚固网络,SD-WAN网络配置指南

在新兴的网络技术中&#xff0c;软件定义广域网&#xff08;SD-WAN&#xff09;作为关键角色脱颖而出&#xff0c;被广泛应用于构建高效可靠的企业网络。利用SD-WAN技术&#xff0c;企业能够更好地管理和优化其网络基础设施&#xff0c;实现更高效的连接和数据传输。本文将深入…

STM32标准库开发——串口发送/单字节接收

USART基本结构 串口发送信息 启动串口一的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);初始化对应串口一的时钟&#xff0c;引脚&#xff0c;将TX引脚设置为复用推挽输出。 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_In…

BigeMap在Unity3d中的应用,助力数字孪生

1. 首先需要用到3个软件&#xff0c;unity&#xff0c;gis office 和 bigemap离线服务器 Unity下载地址:点击前往下载页面(Unity需要 Unity 2021.3.2f1之后的版本) Gis office下载地址:点击前往下载页面 Bigemap离线服务器 下载地址: 点击前往下载页面 Unity用于数字孪生项…

比吸收率(SAR)

本文旨在介绍比吸收率&#xff08;Specific Absorption Rate&#xff09;的基本知识。搬运自https://www.antenna-theory.com。英语够用的朋友可以直接移步。感谢网站创始人Peter Joseph Bevelacqua教授的无私奉献。 ------------------我是分隔线------------------- 比吸收…

【征服redis6】Redis的内存淘汰详解

目录 1.redis的基本策略 2.Redis中的缓存淘汰策略 3.Redis内存不足的情况 4.几种淘汰策略的实现原理 5.项目实践与优化策略 5.1 配置案例 5.2 项目优化策略参考 数据库存储会将数据保存到磁盘中&#xff0c;而Redis的核心数据是在内存中的&#xff0c;而Redis本身主要用来…

【Java练习题汇总】《第一行代码JAVA》多线程篇,汇总Java练习题——线程及多线程概念、Thread 类及 Runnable 接口、线程状态、synchronized同步操作...

Java练习题 多线程篇 1️⃣ 多线程篇2️⃣ 答案 1️⃣ 多线程篇 一、填空题 Java 多线程可以依靠________ 、________ 和________ 三种方式实现。多个线程操作同一资源的时候需要注意________&#xff0c;依靠________ 关键字实现&#xff0c;实现手段是&#xff1a;_______…

「 网络安全常用术语解读 」杀链Kill Chain详解

1. 简介 早在2009年&#xff0c;Lockheed Martin公司就提出了杀链(Kill Chain)理论&#xff0c;现在也称之为攻击者杀链(Attacker Kill Chain)。杀链其实就是攻击者进行网络攻击时所采取的步骤。杀链模型包括7个步骤&#xff1a;1侦察 -> 2武器化 -> 3交付 -> 4利用 …