Go微服务: 分布式之通过可靠消息实现最终一致性

news2024/11/25 22:50:56

通过可靠消息实现最终一致性

  • 可靠消息,就是靠普消息,还是基于之前的这个案例
  • 比如这个订单服务,无论你是先发送消息,还是先新建订单,它其实都是发送的不可靠消息
  • 就是说如果这个消息,像mysql事务那样,只要订单服务不确认,下游就没办法消费
  • 如果你这个订单服务挂了,就可以取消这个消息,就不用做这个本地消息表了
  • 本地消息表,要有一个这个循环的这么一个查询,高并发的时候,你本地的数据库本身压力就大
  • 再弄这么一个查询,一直循环的查,它这个压力也不小,现在看一下基于事务消息,也称为可靠消息
  • 生产者就可以理解为这个订单服务,消费者就可以理解为积分服务,还有库存服务
  • 先看第一个,生产者先发一个半消息给消息队列,消息队列就回我这个半消息成功的信息
  • 这是一个半消息,然后拿到这个半消息成功的结果之后,我们往数据库里写一个Transaction事务
  • 我们就把本地事务执行了,执行之后,也就是到了第4步, 成功情况下就是确认这个半消息
  • 只要到第4步这个commit成功了,消费者就可以消费了,因为你的这个消息已经在这个消息队列中了
  • 这个解决方式是解决了只要我们能发出去的这个消息就是可靠的,只要能提交的消息,本地消息就一定是成功的
  • 因为你本地事务都已经执行成功了,先发半消息,消息队列回给我,回给我之后,我就能收到了,说明已经成功了
  • 然后这个时候你就开始干你本地的事儿,比如订单生产者自己开始建订单,建订单产品表,这都是你的事
  • 我本地能成功了之后,1,2,3步是为了能让消费者成功消费的准备工作
  • 这个思路就是说只要一提交,那我本地这边全部ok, 然后我这个消息队列, 肯定能保证我我的最终一致性
  • 如果在3之前出错,那不会做事务,那相当于准备工作没做好,那下游也不会做相应的这个事情
  • 同时,我们还要思考,有没有其他方面的情况会导致问题
    • 比如,更复杂的网络传输问题,别人的服务宕机了或有bug了
    • 因为微服务在开发的时候,每个小组可以时刻发布自己的服务,它不受控制
  • 如果上述分布式服务出问题了,消息队列也会有一个回查事务消息状态的机制
  • 我会问你这个生产者,哎,你这个状态是啥?然后生产者就会查询这个本地事务状态
  • 第5步和第6步,就是又一次为这个返回事务状态做commit和rollback,就是为下一步的工作做准备
  • 就是消息队列,不知道你这个消息要不要投递,也不能知道别人的状态是什么样的
  • 那消息队列就会问这个生产者,你这个消息事务是啥状态,在第6步得到查询的事务状态是commit
  • 那我消息队列就commit消息投递,一旦消息投递了,这个消费者就可以进行消费了
  • 假如说,返回的这个事务状态是rollback,消息队列就可以把消息扔了
  • 在这整个链路里,有成功的,让消费者消费消息;也有失败,让这个消息队列去丢弃消息
  • 还有中间状态,就是说我不确定这个事务是不是正确的?那询问还是有结果的,就是 commit 或 rollback
  • 其实我们说走到第5步,第6步,还有第7步的时候,他就可以再一次确认我们的消息是否要投递还是丢弃
  • 到这里,一直没有看到说有锁的存在,在高并发的情况下,消息队列就保证了我们最终的一致性
  • 就是说锁的存在,它一定是和高并发是这个对立的,我们尽量不要用锁的方式去考虑我们的并发

积分和库存业务场景的对比

  • 再回过头来看一下这个模型,如果你的生产者是订单,而消费者是库存的话
  • 如果库存不足,消费者是库存服务,库存不足,虽然成功的发送了到这个RocketMQ里
  • 但是库存没有办法成功消费这条消息,这个和其他业务形态上是不一样的
  • 比如订单服务,可以说是送积分,从技术角度来说,积分是没有上限的
  • 还有一种形态,就是我们说发短信,你成功的购买了某某产品等等
  • 这种业务形态, 你的生产者只要把消息放到了消息队列, 消息队列一定是可以保障的
  • 就是说你消息队列是集群吧,你在不挂的情况下,是一定能送达到消费者应用队列里的
  • 比如说, 积分服务,短信服务,你这边已经是commit了
  • 无论你是在第4步commit的,还是说第7步commit的下游是一定能消费到的
  • 但是库存服务不一样,如果库存不足了,你这边又没办法返回
  • 左边是库存服务和订单服务,右边是消息队列
  • 从正向来说,如果服务的提供方发送消息到这个消息队列,也就是生产者发送消息到消息队列
  • 只要消息队列集群不挂,那么我们的消费者是一定能收到这个消息的
  • 就是实现最终的一致性对于积分服务,短信服务的使用都是没有问题的
  • 因为积分理论上是无上限的,我们的短信是一定能发上去的,只要你短信账户里,有足够的余额
  • 但是当库存为零的时候,你的这个消息队列仍然收到了我们发送成功的消息
  • 但下游库存服务是没有办法消费成功的,我们不可能凭空多出来这么多库存
  • 让你去消费,因为没有那么多库存,我们又不能把这个消息队列成功投递库存不足的消息
  • 再返回给这个生产者,这个是不可能的,所以,我们能不能先发送一个归还库存的半消息
  • 这个半消息, 对于库存服务来说, 它是见不到的,我们发完半消息之后
  • 去调用扣减库存的Srv服务,这就是一个Grpc的这么一个调用,先看这个返回失败的情况
  • 如果调用库存失败了,这个时候返回一个rollback,因为一开始就是调用的是归还
  • 那你这个时候就调用rollback,如果我们库存执行失败了,那说明我们库存这个数据是没有变的
  • 既然你库存调用是失败,订单就不会创建, 因为我本地这个数据库就不会变
  • 那么我们两边的这个数据都没变,这个业务也是可以接受的
  • 就是说没有造成数据不一致,那你就不要给我发这个消息来告诉我,你要去归还库存了
  • 那我们直接rollback这个消息,然后这个消息队列, 就可以把这个归还库存的消息给它扔掉了
  • 扔掉之后,看左边这一边就没问题了,数据都没变
  • 你执行失败了,我这边又没执行,或者说,这两边的数据都保持一致,这就是OK的
  • 好,我们再看下一张执行成功的图,看我们订单服务发送一个半消息
  • 然后调用了Grpc扣减那个库存,然后它成功了
  • 成功之后, 我们就会执行这个本地 mysql 事务服务, 其实它可能成功,也可能失败
  • 因为我们如果在微服务里, 由于网络原因或宕机,Bug,停电等各种问题
  • 它都可能导致一个服务的运行失败
  • 如果我们先说这个执行本地mysql事务成功,在第4步成功,执行rollback
  • 还是从数据的角度来看,库存扣减成功,订单执行成功,我们本地也执行成功
  • 那就是说我们两边数据都改变了,这个业务上也是可以接受的
  • 订单生成成功了,库存也扣减了,那就相当于交易成功
  • 那你就不要给我发送这个归还库存的半消息了,所以是 rollback这个半消息
  • 然后,我们把这个消息就扔掉了
  • 那我们再看看,如果第4步执行失败了,就是说我们有任何情况
  • 订单服务有bug,断电或者其他场景,执行失败,那就执行一个commit
  • 因为订单执行失败了,相当于订单数据没有变,那你的库存现在是变了
  • 因为之前第三步已经执行成功了,那这个时候就要告诉库存,说给我扣减了,因为我执行失败了
  • 失败以后,提交一个commit之后,然后,这个库存服务就可以监听到这个消息队列里
  • 因为它 commit 了嘛,这个消息就能看到了,订阅了这个消息之后,就能去归还库存了
  • 如果你这个订单服务,还有一些其他问题,怎么办?其实这个消息队列还提供一种机制
  • 就是回查这个消息,比如说我现在不确定你这个是要提交还是rollback
  • 这个回查机制,就查这个订单的服务,那你还去你这个本地事务的数据库库里去捞数据
  • 你捞对了,就rollback,捞错了,还是commit, 你commit之后
  • 我还是能调用到这个库存服务,然后你再给我归还
  • 这张图就是看到了为了保持这个数据的一致性,我们这边整个业务流程的保证就是这样了
  • 再看上面这张图,还有问题,是在原来的基础上增加了第8条发送延迟消息和监听延迟消息。
  • 就是说我这个库存有一百个,我这个用户买完以后,就是不支付
  • 如果他一周不支付或者一个月不支付,你的库存永远不释放,别人永远买不了
  • 那不就把这个商城的库存给锁死了
  • 当我库存执行成功,这个本地的事务也执行成功的时候,我就把它发送一条延迟消息。
  • 假如我们规定半个小时,时间一到,这个延迟消息就会投递
  • 然后,我们就会根据这个消息去看,这个订单是 支付成功了,还是支付失败了
  • 如果是未支付或者是支付失败都可以,如果你执行失败了,那我就归还库存
  • 因为对商城来说,如果没收到钱,那我就归还库存,半个小时之后,仍然其他的用户就可以买
  • 这样就完美的解决了库存,订单和这个订单下单成功后不支付的这么一个场景
  • 这里的核心重点是:在一开始发送了一个归还库存的半消息
  • 执行commit和rollback的情况是反着来的

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

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

相关文章

Nvidia Jetson/Orin/算能 +FPGA+AI大算力边缘计算盒子:潍柴雷沃智慧农业无人驾驶

潍柴雷沃智慧农业科技股份有限公司,是潍柴集团重要的战略业务单元,旗下收获机械、拖拉机等业务连续多年保持行业领先,是国内少数可以为现代农业提供全程机械化整体解决方案的品牌之一。潍柴集团完成对潍柴雷沃智慧农业战略重组后,…

牛客NC32 求平方根【简单 二分 Java/Go/C++】

题目 题目链接: https://www.nowcoder.com/practice/09fbfb16140b40499951f55113f2166c 思路 Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可*** para…

rv1126-rv1109-openssh-密码秘钥等功能修改

1.openssh是允许外部登录的工具 2.真的是很复杂的设备 3.移植分布,怎么得到我们想要的openssh 去网上自己寻找安装包下载; 4.怎么预制进arm主板,把编译出来的openssh放进去 其中除了ssh_config和sshd_config;其他都是秘钥,公钥和私钥; root账户走的秘钥的修改,不改是默认的r…

【学习笔记】解决 VMware Workstation 17 Player 和主机之间无法复制粘贴的问题

【学习笔记】解决 VMware Workstation 17 Player 和主机之间无法复制粘贴的问题 使用VMware Workstation 17 Player,再上面安装 Ubuntu ,安装完之后,需要和主机之间进行复制粘贴。 首先安装了VMware Tools。 在打开的页面下把 VMwareTools…

今年618,京东和爱奇艺为大屏品质“把关”

今年618电视大战,还是打响了。 根据京东618数据显示,618开门红阶段热卖TOP10电视均为75英寸以上的大屏,拥有超高画质的MiniLED电视成交量同比增长5倍。可以看到,大屏电视逐步成为消费主流,尤其是拥有出色视听体验的高…

【Emgu CV教程】10.14、ConnectedComponents()函数计算连通区域

文章目录 一、概念1.什么叫图像的连通区域2.提取连通区域的函数 二、简单应用1.原始素材2.代码3.运行结果4.连通区域上色 一、概念 1.什么叫图像的连通区域 图像的连通域是指图像中具有相同像素值并且位置相邻的像素组成的区域,连通域分析是指在图像中寻找出彼此互…

韩顺平0基础学java——第19天

p396-406 final关键字 1.final修饰的为“常量”,需要给初始值。1可以直接定义时赋值,2在构造器中,3在代码块中。 注意静态代码块只能访问静态变量。 2.如果final修饰的关键字是静态的,那就不能在构造器中赋值,只能…

2024年最新Microsoft Edge关闭自动更新的方法分享

这里写自定义目录标题 打开【服务】 打开【服务】 windows中搜索服务,如下图: 打开服务界面,找到“Microsoft Edge Update Service (edgeupdate)” 及 “Microsoft Edge Update Service (edgeupdatem)” 两个服务,设置为禁用

C++ | Leetcode C++题解之第132题分割回文串II

题目&#xff1a; 题解&#xff1a; class Solution { public:int minCut(string s) {int n s.size();vector<vector<int>> g(n, vector<int>(n, true));for (int i n - 1; i > 0; --i) {for (int j i 1; j < n; j) {g[i][j] (s[i] s[j]) &…

人工智能--教育领域的运用

文章目录 &#x1f40b;引言 &#x1f40b;个性化学习 &#x1f988;体现&#xff1a; &#x1f988;技术解析&#xff1a; &#x1f40b;智能辅导与虚拟助手 &#x1f988;体现&#xff1a; &#x1f988;技术解析&#xff1a; &#x1f40b;自动评分与评估 &#x1f…

【嵌入式】波特率9600,发送8个字节需要多少时间,如何计算?

问题&#xff1a; 波特率9600&#xff0c;发送 01 03 00 00 00 04 44 09 (8字节) 需要多少时间&#xff0c;如何计算&#xff1f; 在计算发送数据的时间时&#xff0c;首先要考虑波特率以及每个字符的数据格式。对于波特率9600和标准的UART数据格式&#xff08;1个起始位&…

Jenkins+Rancher2.7部署构建

在Jenkins中使用rancher插件时需要去查找工作负载地址 在Rancher2.7没有查看Api按钮了需要自己去查找 1.进入https://192.168.x.xx:6443/v3/projects/ 2.输入在rancher中要查找的的项目名称并点击deployment连接进入下一个页面 3.找到自己的deployment随便点一个进去 4.浏览…

【安装笔记-20240608-Linux-免费空间之三维主机免费空间】

安装笔记-系列文章目录 安装笔记-20240608-Linux-免费空间之三维主机免费空间 文章目录 安装笔记-系列文章目录安装笔记-20240608-Linux-免费空间之三维主机免费空间 前言一、软件介绍名称&#xff1a;三维主机免费空间主页官方介绍 二、安装步骤测试版本&#xff1a;openwrt-…

Day53 动态规划part12

LC309买卖股票的最佳时机含冷冻期 与LC122类似&#xff0c;都是可无限次购买股票&#xff0c;只不过引入了冷冻期的概念dp[i][0] 第i天持有股票收益&#xff1b;dp[i][1] 第i天不持有股票收益;情况一&#xff1a;第i天是冷静期&#xff0c;不能以dp[i-1][1]购买股票,所以以dp[…

10-指针进阶——char型,多级指针,void指针,const指针

10-指针进阶——char型&#xff0c;多级指针&#xff0c;void指针&#xff0c;const指针 文章目录 10-指针进阶——char型&#xff0c;多级指针&#xff0c;void指针&#xff0c;const指针一、char 型指针1.1 示例 二、多级指针2.1 示例 三、 指针的万能拆解方法3.1 示例 四、v…

并查集进阶版

过关代码如下 #define _CRT_SECURE_NO_WARNINGS #include<bits/stdc.h> #include<unordered_set> using namespace std;int n, m; vector<int> edg[400005]; int a[400005], be[400005]; // a的作用就是存放要摧毁 int k; int fa[400005]; int daan[400005]…

Qt OPC UA初体验

介绍 OPC UA全称Open Platform Unified Architecture&#xff0c;开放平台统一架构&#xff0c;是工业自动化领域通用的数据交换协议&#xff0c;它有两套主要的通信机制&#xff1a;1.客户端-服务器通信&#xff1b;2.发布订阅。Qt对OPC UA通信标准也提供了支持&#xff0c;目…

分享一个 .NET Core Console 项目使用依赖注入的详细例子

前言 依赖注入&#xff08;Dependency Injection&#xff0c;简称DI&#xff09;是一种软件设计模式&#xff0c;主要用于管理和组织一个软件系统中不同模块之间的依赖关系。 在依赖注入中&#xff0c;依赖项&#xff08;也称为组件或服务&#xff09;不是在代码内部创建或查…

移动端投屏到大屏幕的操作详解

如果你懒得折腾电脑、电视或其他大屏设备上的影视软件安装及配置&#xff0c;可以选择直接在手机端上将影片投屏到电脑、电视或其他大屏设备上&#xff0c;这里给大家分享三种手机投屏的方法。 系统自带的投屏功能 不管是安卓、鸿蒙还是苹果操作系统&#xff0c;都自带了无线…

HTML静态网页成品作业(HTML+CSS)—— 24节气立夏介绍网页(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…