微服务分布式事务处理

news2025/2/26 1:09:24

当我们向微服务架构迁移时,如何处理好分布式事务是必须考虑的问题。这篇文章介绍了分布式事务处理的两种方案,可以结合实际采用合适的解决方案。原文:Handling Distributed Transactions in the Microservice world[1]

如今每个人(包括我)都在思考、构建微服务,分布式系统是微服务的核心原则和一切实现的上下文。

什么是分布式事务?

跨越网络上多个物理系统或计算机的事务被简单的称为分布式事务。在微服务世界中,事务被分割到多个服务中,需要按顺序调用这些服务以完成整个事务。

下面是一个单体电子商务系统使用事务的例子:

图1: 单体中的事务
图1: 单体中的事务

在上面的系统中,如果用户向平台发送Checkout请求,平台将创建一个本地数据库事务,该事务操作多个数据库表,以处理订单并从库存中保留商品。如果有任何步骤失败,事务(包括订单和保留的商品)可以回滚。这被称为ACID(原子性 Atomicity、一致性 Consistency、隔离性 Isolation、持久性 Durability),由数据库系统保证。

下面是电子商务系统分解为微服务的情况:

图2: 微服务中的事务
图2: 微服务中的事务

当我们解耦这个系统时,创建了微服务OrderMicroserviceInventoryMicroservice,各自有独立的数据库。当用户发起Checkout请求时,这两个微服务都将被调用从而将更改应用到各自的数据库中。因为事务是通过多个系统跨多个数据库的,所以现在这是一个分布式事务

微服务中的分布式事务有什么问题?

随着微服务体系架构的出现,事务可以跨越多个微服务,从而跨越数据库,因此我们现在无法利用数据库的ACID特性,从而面临以下关键问题:

如何保持事务的原子性?

原子性意味着事务要么完成所有步骤,要么没有完成任何步骤。在上面的例子中,如果InventoryMicroservice方法中的“保留商品”失败,如何回滚OrderMicroservice应用的“处理订单”?

如何处理并发请求?

如果某个微服务的对象被持久化到数据库中,同时有另一个请求读取相同的对象。服务应该返回旧数据还是新数据?在上面的例子中,一旦OrderMicroservice已经完成,那么InventoryMicroservice在执行更新的过程时,客户下单的请求中应该包括当前的订单吗?

如今,系统应该为失败而设计,其中主要的问题就是处理分布式事务。下面引用Pat Helland的话:

一般来说,应用程序开发人员不会简单的就能实现支持分布式事务的大型可伸缩应用系统。—— Pat Helland

可能的解决方案

在设计和构建基于微服务的应用时,上述两个问题非常关键。为了解决这些问题,下面列举几种方法:

  • 两阶段提交(Two-Phase Commit)
  • 最终一致性和补偿(Eventual Consistency and Compensation )/ SAGA
1. 两阶段提交

顾名思义,这种处理事务的方式有两个阶段,准备阶段和提交阶段,其中起到重要作用的是事务协调器(Transaction Coordinator),负责维护事务的生命周期。

工作方式:

在准备阶段,所有涉及到的微服务都准备提交,并通知协调器已经准备好完成事务。然后在提交阶段,事务协调器向所有微服务发出提交或回滚命令。

以电子商务系统为例:

图3: 在微服务上成功的两阶段提交
图3: 在微服务上成功的两阶段提交

在上面的示例中(图3),当用户发送Checkout请求时,TransactionCoordinator将发起一个带有所有上下文信息的全局事务。首先,向OrderMicroservice发送prepare命令创建订单。然后,向InventoryMicroservice发送prepare命令保留商品。当两个服务都可以执行更改时,它们将锁定对象,不再接受其他更改,并通知TransactionCoordinator。一旦TransactionCoordinator确认所有微服务都已准备好应用更改,就会通过请求事务commit来要求这些微服务持久化所作的更改,然后所有对象才能被解锁。

图4: 在微服务上失败的两阶段提交
图4: 在微服务上失败的两阶段提交

在失败的场景中(图4)——如果在任何时候有某个微服务没有做好准备,TransactionCoordinator将中止事务并发起回滚流程。图中由于某种原因,OrderMicroservice未能创建订单,但是InventoryMicroservice已经回复说它准备创建订单。TransactionCoordinator将请求InventoryMicroservice中止创建订单,并回滚所做的任何更改、解锁数据库对象。

优点

  • 该方法保证事务是原子的。交易结束时,要么所有微服务都成功,要么所有微服务都没有改变。
  • 其次,允许读写分离,在事务协调器提交更改之前,对象上的更改是不可见的。
  • 这种方法通过同步调用通知客户端成功或失败。

缺点

  • 没什么事情是完美的,两阶段提交与单个微服务的处理时间比起来慢很多,并且高度依赖于事务协调器,在高负载期间,事务协调器确实会降低系统的速度。
  • 另一个主要缺点是数据库行锁定,该锁可能成为性能瓶颈,并且可能出现两个事务相互锁定造成的 死锁
2. 最终一致性和补偿/SAGA

最终一致性的最佳定义之一是microservices.io[2]描述的:每个服务在更新数据时发布一个事件。其他服务订阅事件,当接收到事件时,更新其数据。

在这种方法中,分布式事务由相关微服务上的异步本地事务来完成,微服务通过事件总线相互通信。

工作方式:

再以电子商务系统为例:

图5: 最终的一致性/SAGA,成功的场景
图5: 最终的一致性/SAGA,成功的场景

在上面的例子中(图5),客户端请求系统处理订单。在处理过程中,Choreographer发出一个Create Order事件,表示开始一个事务。OrderMicroservice监听到这个事件并创建一个订单,如果成功,发出一个Order Created事件。Choreographer侦听此事件,并通过发出Reserve items事件继续保留商品。InventoryMicroservice侦听此事件并保留商品,如果成功,发出Items Reserved事件。在这个例子中,这意味着事务的结束。

微服务之间所有基于事件的通信都是通过事件总线进行的,并由另一个系统编排以解决复杂性问题。

图6:最终的一致性/SAGA,失败场景
图6:最终的一致性/SAGA,失败场景

如果由于任何原因InventoryMicroservice未能保留商品(图6),它会发出Failed to Reserve Items事件。Choreographer侦听此事件,并通过发出Delete Order事件启动补偿事务OrderMicroservice侦听此事件并删除所创建的订单。

优点

这种方法的一大优点是每个微服务只关注自己的原子事务。如果某个服务花费了更长的时间,其他微服务不会被阻塞,这也意味着不需要数据库锁。由于其基于异步事件的解决方案,这种方法可以使系统在高负载下具有高度的可伸缩性。

缺点

该方法的主要缺点是没有读取隔离。这意味着在上面的示例中,客户端可以看到已创建的订单,但在下一秒中,由于补偿事务,订单会被删除。此外,当微服务的数量增加时,调试和维护就变得更加困难。

结论

首先尽量避免分布式事务,如果正在构建新应用,那么就从单体开始,如Martin Fowler在MonolithFirst[3]中所描述的那样:

更常见的方法是从单体开始,逐渐剥离边缘的微服务。这种方法可以在微服务体系架构的核心留下一个巨大的单体,大多数新的开发都发生在微服务中,而这个单体相对来说变化不大。— Martin Fowler

当一个事件需要在两个地方更新数据时,与两阶段提交相比,最终一致性/SAGA方案是处理分布式事务的更好的方式,主要原因是两阶段提交在分布式环境中不能伸缩。不过最终一致性方案引入了新问题,例如如何以原子方式更新数据库和发出事件,因此采用这种方案需要开发和测试团队改变思维方式。

References:
[1] Handling Distributed Transactions in the Microservice world: https://medium.com/swlh/handling-transactions-in-the-microservice-world-c77b275813e0
[2] Event Driven Architecture: https://microservices.io/patterns/data/event-driven-architecture.html
[3] MonolithFirst: https://martinfowler.com/bliki/MonolithFirst.html

你好,我是俞凡,在Motorola做过研发,现在在Mavenir做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。
微信公众号:DeepNoMind

- END -

本文由 mdnice 多平台发布

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

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

相关文章

图片投票小程序微信投票软件发起投票软件互动酷投票

现在来说,公司、企业、学校更多的想借助短视频推广自己。 通过微信投票小程序,网友们就可以通过手机拍视频上传视频参加活动,而短视频微信投票评选活动既可以给用户发挥的空间激发参与的热情,又可以让商家和企业实现推广的目的&am…

Linux指令 热键

热键 上一次我们说到了linux的基本指令,这次我们先说一下热键 TAB TAB键在linux中有什么作用呢?? 在Linux中,假设我们想要输入的指令忘记了,我们可以TAB两下,帮我们补全命令或者假如命令太多&#xff0…

openfeign源码解析

概括 Feign是Netflix开发的声明式、模板化的HTTP客户端,其灵感来自Retrofit、JAXRS-2.0以及WebSocket。 Feign可帮助我们更加便捷、优雅地调用HTTP API。 Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。Spring Cloud openfeign对Feign进行了 …

QT软件开发: 获取CPU序列号、硬盘序列号、主板序列号 (采用wmic命令)

[TOC](QT软件开发: 获取CPU序列号、硬盘序列号、主板序列号 (采用wmic命令)) [1] QT软件开发: 获取CPU序列号、硬盘序列号、主板序列号 (采用wmic命令) https://blog.51cto.com/xiaohaiwa/5380259 一、环境介绍 QT版本: 5.12.6 环境: win10 64位 编译器: MinGW 32 二、功…

陷入“营销迷城”的小仙炖,需要回归消费行业本质

消费行业往往受经济周期波动影响较小,因此被认为是一条长坡赛道。近年来,随着消费者收入水平提高,消费市场也出现了诸多以社交、休闲、健康等为目的的新消费形式,如饮料领域的元气森林、江小白,生鲜零售赛道的锅圈食汇…

Go gRPC etcd实现服务注册发现与负载均衡

一、前置 如果不了解go grpc 调用方式和实现细节,可以参考上一篇文章 golang grpc配置使用实战教程 涉及技术点 技术点版本描述golang1.19基础版本grpcv1.41.0gRPC golang包etcd server3.5.0注册中心etcd clientv3.5.8客户端服务发现和负载均衡 服务注册 服务…

【JavaSE】多态(多态实现的条件 重写 向上转移和向下转型 向上转型 向下转型 多态的优缺点 避免在构造方法种调用重写的方法)

文章目录 多态多态实现的条件重写向上转移和向下转型向上转型向下转型 多态的优缺点避免在构造方法种调用重写的方法 多态 一种事物,多种形态。 多态的概念:去完成某个行为,当不同对象去完成时会产生出不同的状态。 多态实现的条件 1.必须…

路径规划算法:基于被囊群优化的路径规划算法- 附代码

路径规划算法:基于被囊群优化的路径规划算法- 附代码 文章目录 路径规划算法:基于被囊群优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要:本文主要介绍利用智能优化算法…

python 读写csv文件方法

csv是一种结构化文件,可以将文本转化成矩阵的形式,方便程序读取和处理。下面来介绍一下使用 python读写 csv文件的方法: 1.首先需要使用 pip安装 python包,然后将 csv文件解压到一个文件夹下 2.使用 pip安装 python包,…

(2)设置飞机进行调优

文章目录 前言 2.1 电池设置 2.2 电机设置 2.3 PID控制器初始设置 前言 以下参数应根据你的飞机的规格正确设置。每一个都会影响调优过程的质量。 2.1 电池设置 确保你的 VTOL 电机的推力曲线尽可能的线性是非常重要的。一个线性的推力曲线意味着电机产生的实际推力的变化…

uniapp学习日记之request自定义请求头

uniapp学习日记之request自定义请求头 在学习uniapp的过程中,由于笔者是从Vue项目转来学习uniapp,在使用uni.request时,发现在浏览器调试时,无法在请求头header中添加token字段,愤而弃之,便开始使用axios组…

python条件循环

python条件循环 Python中的条件循环,可以用来解决很多问题,比如计算一组数据中的最大值,或者从列表中获取一个元素。这里就以条件循环为例来介绍下吧。 Python的条件循环可以分为两种,一种是直接使用 for循环来计算最大值&#xf…

Nvidia技术路线和卷积神经网络介绍

1.Nvidia技术路线概述 2.卷积神经网络介绍 软硬件平台 目的:用卷积神经网络(CNNs)将车前部摄像头捕捉到的原始像素图映射为汽车的方向操控命令。 训练:这套端到端学习系统使用了NVIDIA DevBox, 用Torch 7进行训练。 操作:一台 NVIDIA DRIVE PX 自动驾驶汽车计算…

Mathtype修改硕士论文格式

Mathtype修改硕士论文格式 1将word格式的公式变为mathtype格式1选中公式2点击mathtype中的转换公式 2修改mathtype格式的公式文字版式 1将word格式的公式变为mathtype格式 1选中公式 如果不选公式默认全文所有公式或者指定的公式。 2点击mathtype中的转换公式 选择要转换的…

QML画布绘制(Canvas Paint)

目录 一 QML介绍 二 QML的使用场合 三 实例演示 一 QML介绍 QML是Qt Quick的缩写,它是一种新型的、面向对象的、跨平台的脚本语言,可以用来描述用户界面或应用程序的交互逻辑。QML可以在Qt应用程序中使用,也可以在其他JavaScript应用程序中…

freertos-简介(一)

FreeRTOS 裸机 不带任何操作系统 只能先打完游戏回复信息 实时性差,程序轮流执行delay空等待,CPU不执行其他代码结构臃肿,实现功能都在while循环 RTOS 实时操作系统 会执行打游戏一个时间片再回复信息一个时间片交替执行 在宏观下人类不…

全网最详细部署配置中科大chatgpt学术优化环境

目录 前期准备工作修改config_private.py文件创建私钥配置代理网络的地址 前期准备工作 项目地址: https://github.com/binary-husky/gpt_academic 使用git下载到本地 git clone https://github.com/binary-husky/gpt_academic.git使用conda创建虚拟环境chatgpt-academic …

Grafana系列-统一展示-8-ElasticSearch日志快速搜索仪表板

系列文章 Grafana 系列文章 概述 我们是基于这篇文章: Grafana 系列文章(十二):如何使用 Loki 创建一个用于搜索日志的 Grafana 仪表板, 创建一个类似的, 但是基于 ElasticSearch 的日志快速搜索仪表板. 最终完整效果如下: 📝…

近世代数 笔记与题型连载 第十二章(同态与同构)

文章目录 基本概念同构的概念和性质同态与同构凯莱定理自同态和自同构同态核 相关题型1.证明两个代数系统是同态的2.判断同态的类型(满同态、单一同态和同构)3.对于指定的有限群,找出其对应同构的置换群4.证明某个映射是同构映射5.求指定的同…

【Chrome】最简单方法更改用户文件存储目录User Data

不知不觉C盘下面GoogleChrome已经4.5G了,删除只是一时为快,要想痛快那还是乔迁其他盘符为妙 希望大家的C盘不要过于委屈!!! 关键注意点:网上的其他教程有个很大的错误(误导,就是使用…