MQ第②讲~保证消息可靠性

2024-05-30 02:12
文章标签 消息 保证 可靠性 mq

本文主要是介绍MQ第②讲~保证消息可靠性,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

上一讲我们讲了MQ实际工作中常见的应用场景,这一节讲一下消息的可靠性,如果对MQ掌握程度比较高的铁子,可以不用看,节省您宝贵的时间。

消息的大致链路

消息从投递到消费需要考虑如下几个问题

  • 生产者的消息是否成功投递到消息队列?
  • 消息队列的消息会不会丢失?(MQ宕机的情况
  • 消费者能否一定能消费到消息?
  • 消息异常重试,是否考虑幂等性?
  • 消息执行的结果异常,有没有补偿的方案?

以上这几点是使用MQ队列必须考虑的情况,尤其是商业项目,你要做好周密的方案,因为你的消息对于公司来说其实都是数据资产,比如广告行业的pv信息,广告一般计费都是按照pv计价的,消息丢失那就是严重的生产事故。

举例说明

业务场景

电商场景中,用户下单消费成功后,给用户增加对应的奖励积分,因为消费扣款是主业务,送积分其实并不是主流程业务,所以可以通过MQ进行异步处理。下面会介绍4种消息投递的方式,看看这个业务中消息投递的一个过程,我们一起对比一下他们可能存在的问题以及最终比较好的可取的方案。

方案① 在业务事务中投递消息

方案1大致步骤

可能出现异常的情况:

情况(1)

步骤③出现异常,消息投递失败,因为开始了事务,这样会导致订单生成失败,就直接影响到业务主流程;

情况(2)

步骤④发生异常,其他步骤成功:商品下单失败,消息投递成功,给用户增加了积分;因为电商的积分一般是可以兑换东西的,所以间接性地也是造成了损失,虽然不是致命的,还是不可取。

方案② 先进行主业务事务的提交,再进行消息投递

方案2大致步骤

这个顺序的话,如果步骤④发生异常,其他步骤成功:导致商品下单成功,投递消息失败,用户未增加积分,这给用户会造成不好的体验感,这种方式也不可取。

方案③ 事务消息(分两阶段投递)

(1)新建一张消息记录表(order_message_record)

假设这张表有以下几个字段id, order_no,status(默认值是0,表示消息待投递),content

(2) 流程如下

方案3大致步骤

(3)方案说明

这种方式借助了数据库的事务,业务和消息记录作为了一个原子操作,业务成功之后,消息记录必定是存在的。

(4)可能出现的异常情况

若步骤④执行成功,步骤⑤失败了,会导致业务执行成功,而消息投递失败,这样用户购物完,说好的送积分却没送,体验感就不好了,此时我们需要有个job对待发送的消息进行补偿投递。

(5)消息补偿措施

这个job负责从order_message_record表中查询出状态为0记录,重新投递。

对于投递失败的,采用衰减的方式进行重试,比如第1次失败了,则10秒后,继续重试,若还是失败,则再过20秒,再次重试,需要设置一个最大重试次数,最终还是投递失败,则需要告警+人工干预。

这种方案可靠性会相对高一些,成本其实就是消耗一些服务器的资源。还算可以接受。

方案④ 独立拆分消息服务

单独拆分一个消息服务,对于商业项目而言,需要用到MQ的场景一般会比较多。单独新建一个消息服务,负责消息的落库、将消息发送投递到mq,注意这里新增的一个消息服务可以是一个SpringBoot应用。

  • (1) 新建一个消息日志表

假设表名叫order_message_log

  • (2)新建一个消息表

假设表名叫做order_message_record,有如下几个字段

id:主键,消息id
msg_log_id:业务方order_message_log表的id
body:消息体
msg_log_url:业务方order_message_log记录回查的接口
status:状态,0:待投递,1:投递成功,2:投递失败
fail_msg:投递失败原因
  • (3)大致流程

方案4大致步骤

  • (4)可能出现的问题

若步骤⑥失败,消息服务order_message_record表中的这条消息,将处于待发送状态,但是业务库订单已经生成了,以及order_message_log表也是有记录的,对于这种情况,消息服务需新增一个job,对于order_message_record表中记录为0的消息,拿到order_message_record表中的msg_log_id去回查msg_log_url这个接口,去查一下业务库中的t_msg_log 表是否有记录,有记录说明业务是执行成功的,此时消息服务补发消息到MQ就可以了;对于回查不到的,有可能业务方本地事务还未提交,不能认定为业务方本地事务执行失败了,建议隔一段时间之后,再清理下这种消息。

如何确保消息到达MQ后,在MQ这边不会丢失?

  • 有些MQ为了性能,收到消息后,会将消息放在内存中,并没有立即持久化到磁盘,此时MQ挂了,消息会丢失。

  • 若要确保MQ收到消息后,消息不会丢失,则收到投递过来的消息后,立即持久化,这个操作基本上所有的MQ都是支持的,使用的时候配置一下就可以了。

    说明: 这个其实是运维干的事情,但是自己搞事情的话,那就得自己干了,其实也是基础知识,一般是安装MQ的时候进行配置一下即可

  • 为了防止MQ单节点故障,MQ还需要做主备,这样才可以最大限度的确保消息不会丢失。

消费者如何确保消息一定会被消费?

消息消费的大致流程

消费者消费消息,涉及到网络通信,网络通信存在不可靠的因素,可能会失败,导致消息没有被接收或者消费者消费之后没有进行确认,就会出现该消息再次消费的情况,所以需要做幂等处理,这种方式可以确保消息必然会被成功消费一次,并且就算被多次消费,结果也要是一致的。

写在最后

以上就是关于消息可靠性知识点的讲解,面试的时候,其实理解这一些也差不多了,实际业务万变不离其中,也没有说本文就是最优解,只要是能做到消息的可靠性保证就行,当然性能、数据存储这些都是成本的一部分,所以多思考一些情况总是好的,尤其是你自己搞事情的时候,缜密的思维可以让你省不少钱,我们团队的财经号"韭盾",因为每天要处理非常多的数据,保证为我们的用户每天可以收到最新的数据,MQ这一块真的很关键。对钱感兴趣的铁子可以微信搜索“韭盾”公众号,好了,今天的内容就先分享到这里了,咱们下期再见,这个专栏会继续更新。See you later。

在这里插入图片描述

这篇关于MQ第②讲~保证消息可靠性的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1015290

相关文章

ActiveMQ—消息特性(延迟和定时消息投递)

ActiveMQ消息特性:延迟和定时消息投递(Delay and Schedule Message Delivery) 转自:http://blog.csdn.net/kimmking/article/details/8443872 有时候我们不希望消息马上被broker投递出去,而是想要消息60秒以后发给消费者,或者我们想让消息没隔一定时间投递一次,一共投递指定的次数。。。 类似

如何保证android程序进程不到万不得已的情况下,不会被结束

最近,做一个调用系统自带相机的那么一个功能,遇到的坑,在此记录一下。 设备:红米note4 问题起因 因为自定义的相机,很难满足客户的所有需要,比如:自拍杆的支持,优化方面等等。这些方面自定义的相机都不比系统自带的好,因为有些系统都是商家定制的,难免会出现一个奇葩的问题。比如:你在这款手机上运行,无任何问题,然而你换一款手机后,问题就出现了。 比如:小米的红米系列,你启用系统自带拍照功能后

Java消息队列:RabbitMQ与Kafka的集成与应用

Java消息队列:RabbitMQ与Kafka的集成与应用 大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿! 在现代的分布式系统中,消息队列是实现系统间通信、解耦和提高可扩展性的重要组件。RabbitMQ和Kafka是两个广泛使用的消息队列系统,它们各有特点和优势。本文将介绍如何在Java应用中集成RabbitMQ和Kafka,并展示它们的应用场景。 消息队

Kafka 分布式消息系统详细介绍

Kafka 分布式消息系统 一、Kafka 概述1.1 Kafka 定义1.2 Kafka 设计目标1.3 Kafka 特点 二、Kafka 架构设计2.1 基本架构2.2 Topic 和 Partition2.3 消费者和消费者组2.4 Replica 副本 三、Kafka 分布式集群搭建3.1 下载解压3.1.1 上传解压 3.2 修改 Kafka 配置文件3.2.1 修改zookeep

Android 友盟消息推送集成遇到的问题

友盟消息推送遇到的问题 集成友盟消息推送,步骤根据提供的技术文档接入便可。可是当你集成到项目中去的时候,可能并不是一帆风顺就搞定,因为你项目里面是可能集成了其他的sdk(比如支付宝,微信,七鱼等等三方的sdk)。那么这个时候,再加上友盟的消息推送sdk集成可能就会出现问题。 问题清单 友盟消息推送sdk和支付宝sdk冲突问题 后台配置了消息推送,也显示发送成功,但是手机没有收到消息通知

消息队列的理解和应用场景

知乎上的一个通俗理解的优秀答案 by 祁达方 小红是小明的姐姐。 小红希望小明多读书,常寻找好书给小明看,之前的方式是这样:小红问小明什么时候有空,把书给小明送去,并亲眼监督小明读完书才走。久而久之,两人都觉得麻烦。 后来的方式改成了:小红对小明说「我放到书架上的书你都要看」,然后小红每次发现不错的书都放到书架上,小明则看到书架上有书就拿下来看。 书架就是一个消息队列,小红是生产者,小明是

基于 RocketMQ 的云原生 MQTT 消息引擎设计

作者:沁君 概述 随着智能家居、工业互联网和车联网的迅猛发展,面向 IoT(物联网)设备类的消息通讯需求正在经历前所未有的增长。在这样的背景下,高效和可靠的消息传输标准成为了枢纽。MQTT 协议作为新一代物联网场景中得到广泛认可的协议,正逐渐成为行业标准。 本次我们将介绍搭建在 RocketMQ 基础上实现的 MQTT 核心设计,本文重点分析 RocketMQ 如何适应这些变化,通过优化存储

消息队列创建以及使用示例

消息队列是消息的链接表,存放在内核中并由消息队列标示符标识。 1. 创建或打开一个队列 int msgget(key_t key, int flag); key: 键 由ftok()生成 key_t ftok(const char* path, int id); flag: IPC_CREAT 或 IPC_EXCL  2. 发送消息 int msgsn

WebSocket+Spring boot 构建一个完整消息服务

1、添加依赖 compile project(":faas-spring-boot-starter-data-websocket") 2、定义WebSocketHandler Socket 服务入口(Header接收 jwt-token 同应用登录的Token(直接解决鉴权问题),然后定义请求的自定义参数,方便后续消息推送、支持群发、私发、模糊匹配) @Component@WebSock

Kafka【十三】消费者消费消息的偏移量

偏移量offset是消费者消费数据的一个非常重要的属性。默认情况下,消费者如果不指定消费主题数据的偏移量,那么消费者启动消费时,无论当前主题之前存储了多少历史数据,消费者只能从连接成功后当前主题最新的数据偏移位置读取,而无法读取之前的任何数据。如果想要获取之前的数据,就需要设定配置参数或指定数据偏移量。 【1】起始偏移量 在消费者的配置中,我们可以增加偏移量相关参数auto.offset.re