Oli*_*nde 172 architecture rest transactions microservices
假设我们有一个用户,Wallet REST微服务和一个将各种东西粘合在一起的API网关.当Bob在我们的网站上注册时,我们的API网关需要通过用户微服务和钱包通过钱包微服务创建用户.
现在这里有一些可能出错的场景:
用户Bob创建失败:没关系,我们只是向Bob返回错误消息.我们正在使用SQL事务,因此没有人在系统中看到过Bob.一切都很好:)
用户Bob已创建,但在创建我们的Wallet之前,我们的API网关很难崩溃.我们现在有一个没有钱包的用户(数据不一致).
用户Bob已创建,在我们创建电子钱包时,HTTP连接将断开.钱包创建可能已经成功,也可能没有.
有哪些解决方案可以防止这种数据不一致发生?是否存在允许事务跨越多个REST请求的模式?我已经阅读了关于两阶段提交的维基百科页面,它似乎触及了这个问题,但我不确定如何在实践中应用它.这个原子分布式事务:一个RESTful设计文章似乎也很有趣,虽然我还没有读过它.
或者,我知道REST可能不适合这个用例.也许正确的方法来处理这种情况完全放弃REST并使用不同的通信协议,如消息队列系统?或者我应该在我的应用程序代码中强制执行一致性(例如,通过让后台作业检测到不一致并修复它们,或者在我的用户模型上使用"创建","创建"值等具有"状态"属性)?
Pau*_*son 132
什么没有意义:
什么会让你头疼:
什么可能是最好的选择:
但是如果你需要同步响应呢?
use*_*437 58
这是我最近在一次采访中被问到的一个经典问题如何调用多个Web服务,并且仍然在任务中保留某种错误处理.今天,在高性能计算中,我们避免了两阶段提交.多年前我读了一篇关于交易的"星巴克模型"的文章:想想订购,支付,准备和接收你在星巴克订购的咖啡的过程......我过分简化了事情,但两阶段提交模式会建议在收到咖啡之前,整个过程将是所有相关步骤的单一包装交易.但是,使用这种模式,所有员工都会等待并停止工作,直到你拿到咖啡.你看到了这张照片吗?
相反,通过遵循"尽力而为"模型并补偿过程中的错误,"星巴克模型"更具生产力.首先,他们确保你支付!然后,有一些消息队列,您的订单附在杯子上.如果在这个过程中出现问题,就像你没有拿到咖啡,这不是你订购的等等,我们进入补偿过程,我们确保你得到你想要的或退款给你,这是最有效的模式提高生产力.
有时,星巴克浪费咖啡,但整个过程是有效的.在构建Web服务时还需要考虑其他一些技巧,例如以可以被调用任意次数的方式进行设计,并且仍然提供相同的最终结果.所以,我的建议是:
在定义您的Web服务时不要太精细(我不相信这些天发生的微服务炒作:过多的风险太大了);
异步提高了性能,因此更喜欢异步,尽可能通过电子邮件发送通知.
构建更多智能服务,使其可以"重新调用"任意次数,使用uid或taskid进行处理,按照订单自下而上直到最后,验证每个步骤中的业务规则;
使用消息队列(JMS或其他)并转移到错误处理处理器,通过应用相反的操作将操作应用于"回滚",顺便说一下,使用异步命令将需要某种队列来验证进程的当前状态,所以考虑一下;
最后,(因为它可能不经常发生),将其放入队列以手动处理错误.
让我们回过头来发布的初始问题.创建一个帐户并创建一个钱包,并确保一切都完成.
假设一个Web服务被调用来编排整个操作.
Web服务的伪代码如下所示:
呼叫帐户创建微服务,传递一些信息和一些独特的任务ID 1.1帐户创建微服务将首先检查该帐户是否已经创建.任务ID与帐户的记录相关联.微服务检测到该帐户不存在,因此它创建它并存储任务ID.注意:此服务可以调用2000次,它将始终执行相同的结果.该服务以"收据包含最少信息来回答,以便在需要时执行撤销操作".
致电钱包创建,为其提供帐户ID和任务ID.假设条件无效并且无法执行钱包创建.该调用返回错误但未创建任何内容.
协调器被告知错误.它知道它需要中止帐户创建,但它本身不会这样做.它将通过传递在步骤1结束时收到的"最小撤销收据"来要求钱包服务执行此操作.
帐户服务读取撤消收据并知道如何撤消操作; 撤销收据甚至可能包括有关另一个微服务的信息,它可能称自己为完成部分工作.在这种情况下,撤销收据可能包含帐户ID以及执行相反操作所需的一些额外信息.在我们的例子中,为简化起见,我们假设只是使用其帐户ID删除帐户.
现在,假设Web服务从未收到成功或失败(在这种情况下),即执行了帐户创建的撤消.它只会再次调用帐户的撤消服务.而且这项服务通常应该永远不会失败,因为它的目标是不再存在该帐户.因此它会检查它是否存在并且看不到任何可以撤消它的工作.因此它返回操作成功.
Web服务返回给用户无法创建帐户.
这是一个同步的例子.如果我们不希望系统完全恢复错误,我们可以以不同的方式管理它并将案例放入针对服务台的消息队列中."我看到这是在一个不够的公司中执行的可以向后端系统提供挂钩以纠正情况.服务台接收的消息包含已成功执行的操作,并且有足够的信息来解决问题,就像我们的撤销收据可以以完全自动化的方式使用.
我已经进行了搜索,并且微软网站对此方法有一个模式描述.它被称为补偿交易模式:
小智 28
所有分布式系统都存在事务一致性问题.这样做的最好方法就像你说的那样,进行两阶段提交.将钱包和用户创建为挂起状态.创建后,单独调用以激活用户.
最后一次调用应该是安全可重复的(如果您的连接断开).
这将需要最后一次调用知道两个表(以便它可以在单个JDBC事务中完成).
或者,您可能想要考虑为什么您如此担心没有钱包的用户.你相信这会导致问题吗?如果是这样,可能将这些作为单独的休息呼叫是一个坏主意.如果用户不应该没有钱包,那么您应该将钱包添加到用户(在原始POST调用中创建用户).
恕我直言,微服务架构的一个关键方面是交易仅限于个人微服务(单一责任原则).
在当前示例中,用户创建将是自己的事务.用户创建会将USER_CREATED事件推送到事件队列中.电子钱包服务将订阅USER_CREATED事件并创建电子钱包.
如果我的钱包只是与用户在同一个sql数据库中的另一堆记录,那么我可能会将用户和钱包创建代码放在同一个服务中,并使用普通的数据库事务工具处理它.
听起来你在询问当钱包创建代码要求你触摸另一个系统或系统时会发生什么?我想这一切都取决于创作过程的复杂程度和风险程度.
如果只是触摸另一个可靠的数据存储区(比如一个不能参与你的sql事务的数据存储区),那么根据整个系统参数,我可能愿意承担第二次写入不会发生的可能性极小的风险.我可能什么都不做,但提出异常并通过补偿事务或甚至一些特殊方法处理不一致的数据.正如我总是告诉我的开发人员:"如果在应用程序中发生这种事情,它就不会被忽视".
随着钱包创建的复杂性和风险的增加,您必须采取措施来改善所涉及的风险.假设某些步骤需要调用多个伙伴apis.
此时,您可能会引入消息队列以及部分构造的用户和/或钱包的概念.
确保您的实体最终构建正确的简单而有效的策略是让作业重试直到成功,但很大程度上取决于应用程序的用例.
我也会长时间地思考为什么我的配置过程中出现了一个容易出错的步骤.
| 归档时间: |
|
| 查看次数: |
62921 次 |
| 最近记录: |