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。

在这里插入图片描述

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

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

相关文章

虚拟机改IP地址

使用场景:当你从另一台电脑复制一个VMware虚拟机过来,就是遇到一个问题,虚拟的IP地址不一样(比如,一个是192.168.1.3,另一个是192.168.2.4,由于‘1’和‘2’不同,不是同一网段&#…

浅谈路由器转发数据包

当路由器转发数据包时,它会经历一系列步骤,包括接收数据包、路由表查询、以及转发数据包。以下是详细的步骤描述: 1. 接收数据包 以太网帧到达端口:当一个以太网帧到达路由器的某个网络接口(端口)时&#…

20240529瑞芯微官方Toybrick TB-RK3588开发板的Debian11下使用SCP拷贝文件

20240529瑞芯微官方Toybrick TB-RK3588开发板的Debian11下使用SCP拷贝文件 2024/5/29 20:48 1、ADB链接异常。 2、BT打开之后找不到设备? 不清楚:是我拿到的开发板的问题,还是Toybrick/Rockchip官方没有做好。 3、现在最新版本的WINSCP&…

154.找出出现至少三次的最长特殊字符串|(力扣)

代码解决 class Solution { public:int maximumLength(string s) {// 使用unordered_map来存储每个连续子串出现的次数unordered_map<string, int> mp;string key; // 存储当前的连续子串int ans -1; // 存储最终的答案&#xff0c;如果没有符合条件的子串&#xff0c…

高级数据结构-并查集

例题1&#xff1a; Alice和Bob玩了一个古老的游戏&#xff1a;首先画一个 &#x1d45b;&#x1d45b; 的点阵&#xff08;下图 n3 &#xff09;。 接着&#xff0c;他们两个轮流在相邻的点之间画上红边和蓝边&#xff1a; 直到围成一个封闭的圈&#xff08;面积不必为 1&#…

如何更改SSH服务器端口以减少蛮力攻击

本周有一个客户&#xff0c;购买Hostease的独立服务器&#xff0c;询问我们的在线客服&#xff0c;如何更改SSH服务器端口以减少蛮力攻击&#xff1f;我们为用户提供相关教程&#xff0c;用户很快解决了遇到的问题。在此&#xff0c;我们分享这个操作教程&#xff0c;希望可以对…

8086 汇编笔记(二):寄存器(内存访问)

一、内存中字的存储 字单元的概念&#xff1a;字单元&#xff0c;即存放一个字型数据(16 位)的内存单元&#xff0c;由两个地址连续的内存单元组成 由上一章学习可知&#xff1a;高地址内存单元中存放字型数据的高位字节&#xff0c;低地址内存单元中存放字型数据的低位字节 …

扎气球最高分-第13届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第74讲。 扎气球最高分&…

Spring框架温习

Spring Spring是一个全面的、企业应用开发一站式的解决方案&#xff0c;贯穿表现层、业务层、持久层。但是 Spring仍然可以和其他的框架无缝整合。 Spring 特点&#xff1a; 轻量级、控制反转、面向切面、容器、框架集合 Spring 核心组件&#xff1a; Spring 常用模块&…

【Redis】 关于 Redis 有序集合类型

文章目录 &#x1f343;前言&#x1f334;普通命令介绍&#x1f6a9;zadd&#x1f6a9;zcard&#x1f6a9;zcount&#x1f6a9;zrange&#x1f6a9;zrevrange&#x1f6a9;zrangebyscore&#x1f6a9;zpopmax&#x1f6a9;zpopmin&#x1f6a9;zrank&#x1f6a9;zrevrank&…

Shell脚本的分支语句,循环语句

分支语句 if 表达式 then 命令表 fi 如果表达式为真&#xff0c;则执行命令表中的命令&#xff0c;否则退出。执行fi后的语句。 给文件权限:chmod 0777 文件名 输出: ./文件名 grep 查找用户名&#xff0c;管道wc -l 统计字符 2.多路分支语句 记得给文件名权限喔&#x…

OSPF扩展知识2

FA-转发地址 正常 OSPF 区域收到的 5 类 LSA 不存在 FA 值&#xff1b; 产生 FA 的条件: 1、5类LSA ----假设 R2为 ASBR&#xff0c;90/0 口工作的 OSPF 中&#xff0c;g0/1 口工作在非 ospf 协议或不同 ospf 进程中&#xff1b;若 g0/1 也同时宣告在和 g0/0 相同的 OSPF 进程…

R语言入门 | 使用 ggplot2 进行数据可视化

1.0准备工作 先下好tidyverse包&#xff0c;并进行加载。 install.packages ( "tidyverse" ) library(tidyverse) R 包只需安装一次&#xff0c;但每次开始新会话时都要重新加载。 1.1 数据框 数据框是变量&#xff08;列&#xff09;和观测&#xff08;行&#x…

算法练习——字符串

一确定字符串是否包含唯一字符 1.1涉及知识点 c的输入输出语法 cin>>s; cout<<"NO"; 如何定义字符串 切记&#xff1a;在[]中必须加数字——字符串最大长度&#xff0c;不然编译不通过 char s[101]; 如何获取字符串长度 char s[101];cin>>s;i…

windows10远程桌面端口,修改Windows 10远程桌面端口的步骤

在Windows 10操作系统中&#xff0c;远程桌面功能为企业用户、技术支持人员以及个人用户提供了极大的便利&#xff0c;允许他们远程访问和管理另一台计算机的桌面环境。然而&#xff0c;默认的远程桌面端口&#xff08;通常为3389&#xff09;常常成为安全漏洞的潜在目标&#…

【图像处理与机器视觉】图像处理概述与像素

什么是数字图像处理 改善图像信息&#xff0c;便于作出解释 方便对图像传输&#xff0c;储存&#xff0c;方便机器理解 什么是数字图像 &#xff08;1&#xff09;模拟图像&#xff1a;连续二维函数 f&#xff08;x&#xff0c;y&#xff09;表示&#xff0c;其中 x&#xf…

操作系统真象还原:一些你可能正感到迷惑的问题

第0章-一些你可能正感到迷惑的问题 这是我看操作系统真象还原这本书的一些记录&#xff1a; 4 软件是如何访问硬件的 硬件在输入输出上大体分为串行和并行&#xff0c;相应的接口也就是串行接口和并行接口。串行硬件通过串行接口与 CPU 通信&#xff0c;反过来也是&#xff…

【uni-app】Pinia 持久化

小程序端 Pinia 持久化 说明&#xff1a;Pinia 用法与 Vue3 项目完全一致&#xff0c;uni-app 项目仅需解决持久化插件兼容性问题。 持久化存储插件 安装持久化存储插件&#xff1a; pinia-plugin-persistedstate pnpm i pinia-plugin-persistedstate插件默认使用 localStor…

MySQL——JDBC编程

目录 前言 一、JDBC概述 二、准备工作 1.下载MySQL的JDBC驱动包 2.把jar引入到项目中 三、JDBC编程 1.插入操作 2.查询操作 尾声 前言 本篇文章主要介绍如何利用Java代码进行操作数据库&#xff0c;在实际开发中&#xff0c;绝大多数对数据库的操作我们都是通过代码进行…

uni-app全局弹窗的实现方案

背景 为了解决uni-app 任意位置出现弹窗 解决方案 一、最初方案 受限于uni-app 调用组件需要每个页面都引入注册才可以使用&#xff0c;此方案繁琐&#xff0c;每个页面都要写侵入性比较强 二、改进方案 app端&#xff1a;新建一个页面进行跳转&#xff0c;可以实现伪弹窗…