【问题标题】:How to create a Transaction 'Wrapper' for multiple Services?如何为多个服务创建事务“包装器”?
【发布时间】:2016-12-02 10:11:57
【问题描述】:

目前,我正在做一个以微服务为主要概念的项目。

为了看得更清楚,我举个例子:

我得到了 Service A,它有自己的模型和控制器。

基本上,服务 A 只包含 数据库 A 的基本 CRUD 操作。

其次,我得到了Service B,与Service A 相同,但数据库不同(Database B)。

现在,我创建了 1 个服务来同时使用服务 A 和服务 B。目前我正在使用 TransactionScope 来“包装”事务,但它不起作用。

代码如下:

//This is the service to call Service A and Service B
using (TransactionScope ts = new TransactionScope())
{
     callServiceAMethod(); // works good
     callServiceBMethod(); // something happened, and failed

     //from here I don't know what should I do
     //What I'm expecting is : if one of the service i just called didn't work as expected, 
     //the transaction will be rolled back else will committed     
    }

任何帮助将不胜感激:)

【问题讨论】:

  • 我认为您需要为每个服务创建事务,存储在某种数组中,如果出现故障,只需遍历所有 ts 实例并回滚。
  • 好的,也就是说,我需要为每个服务创建模型,对吧?有没有其他方法,所以我不需要为每个服务创建模型?
  • 什么型号?对不起,真的不明白。您是否尝试将TransactionScopeOption.Required 添加到TransactionScope?您还需要使用嵌套事务,尽管不知道如何在服务调用其他服务方法的解决方案中实现它。请参阅Nested transactions- 19. requirement

标签: c# web-services wcf transactions microservices


【解决方案1】:

目前我正在使用 TransactionScope 来“包装”交易,但是 它没有工作

在事务范围内包装对物理外部资源的调用仅在非常精确配置(有些人会说人为)的条件下工作。

在您的示例中(假设服务和数据库位于彼此和调用者不同的物理主机上),您将从调用者主机到服务主机,跨越服务边界,到数据库主机,进入数据库,返回到服务主机,返回到服务边界,然后返回到调用者主机。

为了将分布式事务从客户端传播到数据库,调用链中每个步骤的每个中介都必须加入事务。

为了做到这一点:

  • 必须在每个参与的主机上正确启用和配置 MSDTC,
  • 必须使用支持 WS-AtomicTransaction 的绑定(如 wsHttpBinding)进行服务调用,并且
  • 必须专门构建服务以支持事务行为。

因此,除非所有这些都已完成,否则您连续进行两次服务调用这一事实在这种情况下没有任何区别。单个服务调用将无法将事务向下传播到数据库并再次返回。

即使您已经了解上述内容并已完成所有这些步骤以支持跨多个服务调用的分布式事务支持,我仍然不建议您这样做。交易成本高昂,并鼓励共享解决方案的环境依赖性。当您计划采用微服务风格的方法时尤其如此。

必须更简单的是让每个服务公开一个恢复或回滚操作,以便调用者可以采取适当的操作并将之前进行的任何调用回滚到失败的调用。这种方法称为compensation pattern

【讨论】:

  • 感谢您的回答,但不幸的是,该项目需要坚持微服务概念 :( 。即使我对微服务的第一个想法也是关于事务和繁荣,它现在正在发生在我身上,就在脸。是的,你是对的,即使在单一服务上,它也不起作用。有什么建议吗?
  • @Webster 我并不是说该项目不应该坚持使用微服务。只是强迫微服务参与总体事务行为是一种不正确的方法。我当然会尝试与制定这种方法的人交谈,以尝试引导他们寻求不依赖于事务一致性的解决方案,而是依赖于补偿性回滚。
【解决方案2】:

如果我的描述正确,上面的代码看起来像是在第三个服务或共享代码中?

在构建自治组件时,它们不应共享资源或代码,因为这会破坏松散耦合的基本思想......

(micro)Service A (component A) 应该只修改和拥有 DB A 中的数据 和 B 一样

一旦 A 完成了他的任务,它应该引发一个 B 订阅的事件,B 将处理该事件并完成他的工作。

如果其中任何一个失败,他们可以引发类似xOperationFailed(即CreatUserAccountFailed)的事件,订阅该事件的感兴趣组件将根据业务逻辑采取行动(回滚、暂停、发送电子邮件到用户或管理员采取纠正措施)。成功也是如此(他们可以引发成功事件)。

困难的部分是定义每个组件的边界(职责和数据)......

这有意义吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多