当前位置: 首页 > news >正文

使用 MQ 解决分布式事务一致性问题

1、背景

​ 在互联网分布式场景中,原本一个系统被拆分成多个子系统,要想完成一次写入操作,需要同时协调多个系统,这就带来了分布式事务的问题(分布式事务是指:一次大的操作由多个小操作组成,这些小的操作分布在不同的服务器上,分布式事务需要保证这些小操作要么全部成功,要么全部失败)。那怎么设计才能实现系统之间的事务一致性呢?

2、分析

​ 这是一个很典型的分布式事务问题,解决方案也很多,有两阶段提交协议(Two-Phase Commit,2PC)、3PC 、TCC 和基于消息队列的实现方式。

​ 建议先介绍目前主流实现分布式系统事务一致性的方案(也就是基于 MQ 的可靠消息投递的机制)然后回答出可实现方案和关键知识点。另外,为了和面试官进一步交流,可以提出 2PC 或 TCC (这是一种交流方案)。因为 2PC 或 TCC 在工业界落地代价很大,不适合互联网场景,所以只有少部分的强一致性业务场景(如金融支付领域)会基于这两种方案实现。围绕它们的解决思路和方案弊端与面试官讨论,这会让你和面试官由不平等的“面试与被面试”变成平等且友好的“双方沟通”,是一种面试套路。

3、基于 MQ 的可靠消息投递方案

​ 基于 MQ 的可靠消息队列投递方案是目前互联网最为常用的方式之一,在应对高并发场景下的分布式事务问题时,这种方案通过放弃强一致性,而选择最终一致性,来提高系统的可用性。

​ 以下单系统为例子,现在分为订单系统、优惠劵系统,下单后首先订单系统创建订单,然后优惠劵系统扣除优惠劵。这里使用上 MQ 之后,将会变成:订单系统创建订单后,将扣除优惠劵的事件放入消息队列,最终优惠劵系统消费消息之后,执行后续扣除流程。注意开启消息持久化,即使 MQ 重启也不会丢失消息。

在这里插入图片描述

3.1、MQ 自动应答机制导致的消息丢失

​ 如果消息中间件(如 RabbitMQ)开启消息自动应答机制,当优惠券系统消费了消息,消息中间件就会删除这个持久化的消息。但是优惠劵系统消费过程中可能出现异常情况,假如这条信息已经删除而优惠劵系统执行过程中异常,那么就会丢失这条消息。所以一般是开启手动应答机制,在优惠劵扣除流程正确执行之后,再手动应答删除信息。

3.2、假如优惠劵系统执行的扣除流程失败,订单系统如何感知?

​ 假如优惠劵系统成功消费到消息,但扣除优惠劵的流程执行失败且重试也不能解决,比如优惠劵数量不足,那么订单系统如何感知这个结果呢? 订单系统可以提供一个回调接口,优惠劵系统执行失败的情况可以调用接口通知订单系统。但是这个前提是优惠劵系统消费了信息,而下面的情况回调接口的方式就不适用了。

3.3、高并发场景下的消息积压导致消息丢失

​ 消息队列中的消息是有超时时间的,但超过一定时间未被消费,这个消息就会被 MQ 重新放入队列,如果继续超时则会重复这个过程,但超过一定次数后,这个消息就会移入死信队列中。

​ 分布式部署环境基于网络进行通信,而在网络通信的过程中,上下游可能因为各种原因而导致消息丢失。比如优惠券系统由于流量过大而触发限流,不能保证事件消息能够被及时地消费,这个消息就会被消息队列不断地重试,最后可能由于超过了最大重试次数而被丢弃到死信队列中。实际上,我们需要人工干预处理移入死信队列的消息,所以在这种场景下,这条事件消息大概率会被丢弃(等待后续人工处理)。

我们可以使用双向 MQ + 订单系统持久化来解决这个问题。具体如下:

​ 订单系统在投递消息前,先本次持久化一条投递记录,状态为未消费,随后投递消息。优惠劵系统消费了消息之后,将确认信息投递到 MQ,订单系统消费之后,将订单消息变更为已消费。这样即使因为高并发的情况导致 订单系统 -> 优惠劵系统的 消息丢失,订单系统也还是可以通过定时任务扫描的方式,将未完成的消息重新投递来进行消息补偿。这是基于消息队列实现分布式事务的关键,是一种双向消息确认的机制。

在这里插入图片描述

3.4、消息重复消费会有问题吗?

​ 理论上不会。优惠劵系统一般会存储订单 id + 优惠劵 id 的处理记录。订单 id 和 优惠劵 id 是唯一的,它们的组合也就同样是唯一的,即使有重复的消息,优惠劵系统也能正确处理。

3.5、双向确认 OR 单向确认?

​ 上面使用 双向 MQ + 订单系统投递记录持久化已经可以解决消息丢失问题,可以注意到这个过程,优惠劵系统消费消息后 ACK 确认了一次,可以理解为单向确认。

​ 然后我们可以发现:优惠劵系统向订单系统 ACK 的消息是否也需要持久化,订单系统接收到确认信息后也发送一次确认信息,类似 TCP 三次握手一样?

本人认为在大部分情况是不需要的:

  1. 单向过程已经足够处理上诉消息丢失的情况了:假如优惠劵系统向订单系统 ACK 的消息出现异常,那么订单系统定时扫描消息投递状态后,会重试投递消息,优惠劵系统会继续 ACK。所以依靠双向 MQ + 单向确认 已经可以解决问题。
  2. 优惠劵系统 ACK 的消息天然比订单系统的扣减信息的 QPS小:上诉引入双向 MQ 是因为优惠劵系统消费的 QPS 比订单系统投递的 QPS 小,而优惠劵系统 ACK 的 QPS 小于等于优惠劵系统消费订单信息的 QPS,除非订单系统的处理能力远小于优惠劵系统消费订单信息的 QPS,否则很少会出现消息堆积的情况,所以我认为双向确认机制性价比比较低。
http://www.dtcms.com/a/474953.html

相关文章:

  • 中国石化工程建设公司网站保山市建设厅官方网站
  • 电子商务网站建设需要哪些步骤聚成网站建设
  • 前端开发指南,前端开发需要学什么
  • 一个网站设计的费用搭建影视网站违法
  • 深入解析 YOLO v2
  • 网站建设开票计量单位网站建设宣传素材
  • wordpress插件怎么使用兰州搜索引擎优化
  • Mysql初阶第七讲:Mysql复合查询
  • 代码随想录 101.对称二叉树
  • 深圳网站建设哪家比较专业大学城网站开发公司
  • 制作静态链接库并使用
  • 西方设计网站vs2010网站开发与发布
  • 网站维护工作的基本内容施工企业质量管理体系认证几年
  • 网站建设教程pdf下载企业官网网页设计
  • 重启MySQL,为何重启后MySQL数据“回滚”了?
  • 非洲购物网站排名文创产品设计包括哪些方面
  • Linux 文件内容查看与编辑
  • 2022 CSP-J复赛题
  • 【cubeide】IIC通信
  • python学习之访问模式和文件定位操作
  • CTF攻防世界WEB精选基础入门:simple_php
  • CodexField 热度登顶:内容资产化赛道的加速信号
  • 00_k8s容器编排系统
  • 广西柳州网站制作公司厦门做网站排名
  • 算法学习 02
  • 广西建设监理协会官网站珠海响应式网站建设推广公司
  • 机器学习实践项目(一)- Rossman商店销售预测 - 特征工程
  • 网站首页轮播图片wordpress不支持中文
  • Blender经典像素风模拟插件 Drips Psx Efx – Playstation 1 Effects V1.4
  • 网站 备案 固话福州网站设计软件公司