微服务分布式事务处理

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: 微服务分布式事务处理

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


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


什么是分布式事务?


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


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

image.png

图 1: 单体中的事务


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


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

image.png


图 2: 微服务中的事务


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


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


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


如何保持事务的原子性?


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


如何处理并发请求?


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


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


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


可能的解决方案


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


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


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


工作方式:


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


以电子商务系统为例:

image.png

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


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

image.png

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


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


优点


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


缺点


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


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


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


工作方式:


再以电子商务系统为例:

image.png

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


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


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


image.png

图 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

目录
相关文章
|
3月前
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2
|
3月前
|
负载均衡 Java 应用服务中间件
微服务分布式系统架构之zookeeper与dubbor-1
微服务分布式系统架构之zookeeper与dubbor-1
|
4月前
|
存储 消息中间件 Apache
比较微服务中的分布式事务模式
比较微服务中的分布式事务模式
76 2
|
20天前
|
存储 运维 数据可视化
如何为微服务实现分布式日志记录
如何为微服务实现分布式日志记录
35 1
|
2月前
|
消息中间件 存储 负载均衡
微服务与分布式系统设计看这篇就够了!
【10月更文挑战第12天】 在现代软件架构中,微服务和分布式系统设计已经成为构建可扩展、灵活和可靠应用程序的主流方法。本文将深入探讨微服务架构的核心概念、设计原则和挑战,并提供一些关于如何在分布式系统中实现微服务的实用指导。
77 2
|
2月前
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
|
4月前
|
监控 Go API
带你十天轻松搞定 Go 微服务之大结局(分布式事务)
带你十天轻松搞定 Go 微服务之大结局(分布式事务)
|
4月前
|
监控 Java 开发者
随着软件开发的发展,传统单体应用已难以适应现代业务需求,微服务架构因此兴起,成为构建可伸缩、分布式系统的主流
随着软件开发的发展,传统单体应用已难以适应现代业务需求,微服务架构因此兴起,成为构建可伸缩、分布式系统的主流。本文探讨Java微服务架构的设计原则与实践。核心思想是将应用拆分为独立服务单元,增强模块化与扩展性。Java开发者可利用Spring Boot等框架简化开发流程。设计时需遵循单一职责、自治性和面向接口编程的原则。以电商系统为例,将订单处理、商品管理和用户认证等拆分为独立服务,提高可维护性和容错能力。还需考虑服务间通信、数据一致性及监控等高级话题。掌握这些原则和工具,开发者能构建高效、可维护的微服务应用,更好地应对未来挑战。
90 1
|
4月前
|
Cloud Native 云计算 微服务
云原生时代:企业分布式应用架构的惊人蜕变,从SOA到微服务的大逃亡!
【8月更文挑战第8天】在云计算与容器技术推动下,企业分布式应用架构正经历从SOA到微服务再到云原生的深刻变革。SOA强调服务重用与组合,通过标准化接口实现服务解耦;微服务以细粒度划分服务,增强系统灵活性;云原生架构借助容器化与自动化技术简化部署与管理。每一步演进都为企业带来新的技术挑战与机遇。
133 6
|
4月前
|
Java 数据库连接 微服务
揭秘微服务架构下的数据魔方:Hibernate如何玩转分布式持久化,实现秒级响应的秘密武器?
【8月更文挑战第31天】微服务架构通过将系统拆分成独立服务,提升了可维护性和扩展性,但也带来了数据一致性和事务管理等挑战。Hibernate 作为强大的 ORM 工具,在微服务中发挥关键作用,通过二级缓存和分布式事务支持,简化了对象关系映射,并提供了有效的持久化策略。其二级缓存机制减少数据库访问,提升性能;支持 JTA 保证跨服务事务一致性;乐观锁机制解决并发数据冲突。合理配置 Hibernate 可助力构建高效稳定的分布式系统。
76 0
下一篇
DataWorks