跨 REST 微服务的事务? [英] Transactions across REST microservices?

查看:38
本文介绍了跨 REST 微服务的事务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有一个用户、钱包 REST 微服务和一个将事物粘合在一起的 API 网关.当 Bob 在我们的网站上注册时,我们的 API 网关需要通过 User 微服务创建一个用户,并通过 Wallet 微服务创建一个钱包.

Let's say we have a User, Wallet REST microservices and an API gateway that glues things together. When Bob registers on our website, our API gateway needs to create a user through the User microservice and a wallet through the Wallet microservice.

以下是一些可能出错的场景:

Now here are a few scenarios where things could go wrong:

  • 用户 Bob 创建失败:没关系,我们只是向 Bob 返回一条错误消息.我们正在使用 SQL 事务,所以没有人在系统中看到过 Bob.一切都很好:)

  • User Bob creation fails: that's OK, we just return an error message to the Bob. We're using SQL transactions so no one ever saw Bob in the system. Everything's good :)

用户 Bob 已创建,但在我们的钱包创建之前,我们的 API 网关硬崩溃.我们现在有一个没有钱包的用户(数据不一致).

User Bob is created but before our Wallet can be created, our API gateway hard crashes. We now have a User with no wallet (inconsistent data).

用户 Bob 已创建,当我们创建钱包时,HTTP 连接断开.钱包创建可能已经成功,也可能没有.

User Bob is created and as we are creating the Wallet, the HTTP connection drops. The wallet creation might have succeeded or it might have not.

有哪些解决方案可以防止这种数据不一致的发生?是否存在允许事务跨越多个 REST 请求的模式?我已经阅读了关于 两阶段提交的维基百科页面,这似乎涉及到这个问题,但我不是确定如何在实践中应用它.这个Atomic Distributed Transactions: a RESTful design 论文似乎也很有趣,虽然我还没有读过还没有.

What solutions are available to prevent this kind of data inconsistency from happening? Are there patterns that allow transactions to span multiple REST requests? I've read the Wikipedia page on Two-phase commit which seems to touch on this issue but I'm not sure how to apply it in practice. This Atomic Distributed Transactions: a RESTful design paper also seems interesting although I haven't read it yet.

或者,我知道 REST 可能不适合这个用例.也许处理这种情况的正确方法是完全放弃 REST 并使用不同的通信协议,如消息队列系统?或者我应该在我的应用程序代码中强制执行一致性(例如,通过后台作业检测不一致并修复它们,或者在我的用户模型上使用创建"、创建"值等的状态"属性)?

Alternatively, I know REST might just not be suited for this use case. Would perhaps the correct way to handle this situation to drop REST entirely and use a different communication protocol like a message queue system? Or should I enforce consistency in my application code (for example, by having a background job that detects inconsistencies and fixes them or by having a "state" attribute on my User model with "creating", "created" values, etc.)?

推荐答案

什么没有意义:

  • 与 REST 服务的分布式事务.根据定义,REST 服务是无状态的,因此它们不应成为跨越多个服务的事务边界的参与者.您的用户注册用例场景是有道理的,但是使用 REST 微服务来创建用户和钱包数据的设计并不好.
  • distributed transactions with REST services. REST services by definition are stateless, so they should not be participants in a transactional boundary that spans more than one service. Your user registration use case scenario makes sense, but the design with REST microservices to create User and Wallet data is not good.

什么会让你头疼:

  • 具有分布式事务的 EJB.这是在理论上有效但在实践中无效的事情之一.现在,我正在尝试为跨 JBoss EAP 6.3 实例的远程 EJB 进行分布式事务.数周以来,我们一直在与 RedHat 支持人员进行沟通,但仍未奏效.
  • 一般的两阶段提交解决方案.我认为 2PC 协议 是一个很棒的算法(很多年前我用 C 实现了它RPC).它需要全面的故障恢复机制,包括重试、状态存储库等.所有复杂性都隐藏在事务框架内(例如:JBoss Arjuna).但是,2PC 不是防故障的.有些情况下交易根本无法完成.然后您需要手动识别和修复数据库不一致.如果幸运的话,它可能在一百万次交易中发生一次,但根据您的平台和场景,它可能每 100 次交易中发生一次.
  • Sagas(补偿交易).有创建补偿操作的实现开销,以及最后激活补偿的协调机制.但补偿也不是失败证明.您最终可能仍会出现不一致的情况(= 令人头疼).
  • EJBs with distributed transactions. It's one of those things that work in theory but not in practice. Right now I'm trying to make a distributed transaction work for remote EJBs across JBoss EAP 6.3 instances. We've been talking to RedHat support for weeks, and it didn't work yet.
  • Two-phase commit solutions in general. I think the 2PC protocol is a great algorithm (many years ago I implemented it in C with RPC). It requires comprehensive fail recovery mechanisms, with retries, state repository, etc. All the complexity is hidden within the transaction framework (ex.: JBoss Arjuna). However, 2PC is not fail proof. There are situations the transaction simply can't complete. Then you need to identify and fix database inconsistencies manually. It may happen once in a million transactions if you're lucky, but it may happen once in every 100 transactions depending on your platform and scenario.
  • Sagas (Compensating transactions). There's the implementation overhead of creating the compensating operations, and the coordination mechanism to activate compensation at the end. But compensation is not fail proof either. You may still end up with inconsistencies (= some headache).

什么可能是最好的选择:

  • 最终一致性.类似 ACID 的分布式事务和补偿事务都不是故障证明,两者都可能导致不一致.最终的一致性通常比偶尔的不一致"要好.有不同的设计解决方案,例如:
    • 您可以使用异步通信创建更强大的解决方案.在您的场景中,当 Bob 注册时,API 网关可以向 NewUser 队列发送一条消息,并立即回复用户说您将收到一封确认帐户创建的电子邮件".队列消费者服务可以处理消息,在单个事务中执行数据库更改,并将电子邮件发送给 Bob 以通知帐户创建.
    • 用户微服务在同一个数据库中创建用户记录一个钱包记录.在这种情况下,用户微服务中的钱包存储是主钱包存储的副本,仅对钱包微服务可见.有一种基于触发器或定期启动的数据同步机制,以将数据更改(例如,新钱包)从副本发送到主服务器,反之亦然.
    • Eventual consistency. Neither ACID-like distributed transactions nor compensating transactions are fail proof, and both may lead to inconsistencies. Eventual consistency is often better than "occasional inconsistency". There are different design solutions, such as:
      • You may create a more robust solution using asynchronous communication. In your scenario, when Bob registers, the API gateway could send a message to a NewUser queue, and right-away reply to the user saying "You'll receive an email to confirm the account creation." A queue consumer service could process the message, perform the database changes in a single transaction, and send the email to Bob to notify the account creation.
      • The User microservice creates the user record and a wallet record in the same database. In this case, the wallet store in the User microservice is a replica of the master wallet store only visible to the Wallet microservice. There's a data synchronization mechanism that is trigger-based or kicks in periodically to send data changes (e.g., new wallets) from the replica to the master, and vice-versa.

      但是如果您需要同步响应怎么办?

      • 改造微服务.如果队列的解决方案由于服务使用者需要立即响应而不起作用,那么我宁愿将用户和钱包功能改造成配置在同一服务中(或至少在同一 VM 中以避免分布式事务)).是的,它离微服务更远了一步,更接近于单体应用,但会让你免于头痛.
      • Remodel the microservices. If the solution with the queue doesn't work because the service consumer needs a response right away, then I'd rather remodel the User and Wallet functionality to be collocated in the same service (or at least in the same VM to avoid distributed transactions). Yes, it's a step farther from microservices and closer to a monolith, but will save you from some headache.

      这篇关于跨 REST 微服务的事务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆