微服务分布式事件处理

火影  论坛元老 | 2024-9-29 14:13:57 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1019|帖子 1019|积分 3057

<blockquote class="multiquote-1" style="border: none; display: block; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; color: #6a737d; padding-top: 10px; padding-bottom: 10px; padding-left: 20px; padding-right: 10px; margin-bottom: 20px; margin-top: 20px; border-left: 3px solid rgba(0, 0, 0, 0.65); border-right: 1px solid rgba(0, 0, 0, 0.65); background: rgb(249, 249, 249);">   当我们向微服务架构迁移时,如那边理好分布式事件是必须思量的问题。这篇文章先容了分布式事件处理的两种方案,可以团坚固际采用合适的办理方案。原文:Handling Distributed Transactions in the Microservice world[1]
    如今每个人(包括我)都在思考、构建微服务,分布式体系是微服务的核心原则和一切实现的上下文。
  什么是分布式事件?

  凌驾网络上多个物理体系或盘算机的事件被简单的称为分布式事件。在微服务世界中,事件被分割到多个服务中,必要按顺序调用这些服务以完成整个事件。
  下面是一个单体电子商务体系利用事件的例子:
     
       图1: 单体中的事件       在上面的体系中,假如用户向平台发送Checkout请求,平台将创建一个当地数据库事件,该事件操作多个数据库表,以处理订单并从库存中保留商品。假如有任何步骤失败,事件(包括订单和保留的商品)可以回滚。这被称为ACID(原子性 Atomicity、同等性 Consistency、隔离性 Isolation、长期性 Durability),由数据库体系保证。
  下面是电子商务体系分解为微服务的情况:
     
       图2: 微服务中的事件       当我们解耦这个体系时,创建了微服务OrderMicroservice和InventoryMicroservice,各自有独立的数据库。当用户发起Checkout请求时,这两个微服务都将被调用从而将更改应用到各自的数据库中。因为事件是通过多个体系跨多个数据库的,以是如今这是一个分布式事件
  微服务中的分布式事件有什么问题?

  随着微服务体系架构的出现,事件可以凌驾多个微服务,从而凌驾数据库,因此我们如今无法利用数据库的ACID特性,从而面对以下关键问题:
  怎样保持事件的原子性?

  原子性意味着事件要么完成全部步骤,要么没有完成任何步骤。在上面的例子中,假如InventoryMicroservice方法中的“保留商品”失败,怎样回滚OrderMicroservice应用的“处理订单”?
  如那边理并发请求?

  假如某个微服务的对象被长期化到数据库中,同时有另一个请求读取相同的对象。服务应该返回旧数据照旧新数据?在上面的例子中,一旦OrderMicroservice已经完成,那么InventoryMicroservice在执行更新的过程时,客户下单的请求中应该包括当前的订单吗?
  如今,体系应该为失败而设计,其中重要的问题就是处理分布式事件。下面引用Pat Helland的话:
  <blockquote class="multiquote-2" style="border: none; box-shadow: 1px 1px 10px rgba(0,0,0,0.2); padding: 20px; margin-bottom: 20px; margin-top: 20px;">   <blockquote style="border: none;">    一般来说,应用步伐开辟职员不会简单的就能实现支持分布式事件的大型可伸缩应用体系。—— Pat Helland
       大概的办理方案

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

  •          两阶段提交(Two-Phase Commit)
  •          终极同等性和赔偿(Eventual Consistency and Compensation )/ SAGA
  1. 两阶段提交

  顾名思义,这种处理事件的方式有两个阶段,准备阶段和提交阶段,其中起到重要作用的是事件协调器(Transaction Coordinator),负责维护事件的生命周期。
  工作方式:
  在准备阶段,全部涉及到的微服务都准备提交,并通知协调器已经准备好完成事件。然后在提交阶段,事件协调器向全部微服务发出提交或回滚命令。
  以电子商务体系为例:
     
       图3: 在微服务上成功的两阶段提交       在上面的示例中(图3),当用户发送Checkout请求时,TransactionCoordinator将发起一个带有全部上下文信息的全局事件。首先,向OrderMicroservice发送prepare命令创建订单。然后,向InventoryMicroservice发送prepare命令保留商品。当两个服务都可以执行更改时,它们将锁定对象,不再接受其他更改,并通知TransactionCoordinator。一旦TransactionCoordinator确认全部微服务都已准备好应用更改,就会通过请求事件commit来要求这些微服务长期化所作的更改,然后全部对象才能被解锁。
     
       图4: 在微服务上失败的两阶段提交       在失败的场景中(图4)——假如在任何时候有某个微服务没有做好准备,TransactionCoordinator将中断事件并发起回滚流程。图中由于某种原因,OrderMicroservice未能创建订单,但是InventoryMicroservice已经复兴说它准备创建订单。TransactionCoordinator将请求InventoryMicroservice中断创建订单,并回滚所做的任何更改、解锁数据库对象。
  长处
  

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

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

  终极同等性的最佳界说之一是microservices.io[2]描述的:每个服务在更新数据时发布一个事件。其他服务订阅事件,当接收到事件时,更新其数据。
  在这种方法中,分布式事件由干系微服务上的异步当地事件来完成,微服务通过事件总线相互通信。
  工作方式:
  再以电子商务体系为例:
     
       图5: 终极的同等性/SAGA,成功的场景       在上面的例子中(图5),客户端请求体系处理订单。在处理过程中,Choreographer发出一个Create Order事件,表示开始一个事件。OrderMicroservice监听到这个事件并创建一个订单,假如成功,发出一个Order Created事件。Choreographer侦听此事件,并通过发出Reserve items事件继续保留商品。InventoryMicroservice侦听此事件并保留商品,假如成功,发出Items Reserved事件。在这个例子中,这意味着事件的竣事。
  微服务之间全部基于事件的通信都是通过事件总线进行的,并由另一个体系编排以办理复杂性问题。
     
       图6:终极的同等性/SAGA,失败场景       假如由于任何原因InventoryMicroservice未能保留商品(图6),它会发出Failed to Reserve Items事件。Choreographer侦听此事件,并通过发出Delete Order事件启动赔偿事件。OrderMicroservice侦听此事件并删除所创建的订单。
  长处
  这种方法的一大长处是每个微服务只关注本身的原子事件。假如某个服务花费了更长的时间,其他微服务不会被阻塞,这也意味着不必要数据库锁。由于其基于异步事件的办理方案,这种方法可以使体系在高负载下具有高度的可伸缩性。
  缺点
  该方法的重要缺点是没有读取隔离。这意味着在上面的示例中,客户端可以看到已创建的订单,但在下一秒中,由于赔偿事件,订单会被删除。此外,当微服务的数量增长时,调试和维护就变得更加困难。
  结论

  首先只管制止分布式事件,假如正在构建新应用,那么就从单体开始,如Martin Fowler在MonolithFirst[3]中所描述的那样:
  <blockquote class="multiquote-2" style="border: none; box-shadow: 1px 1px 10px rgba(0,0,0,0.2); padding: 20px; margin-bottom: 20px; margin-top: 20px;">   <blockquote style="border: none;">    更常见的方法是从单体开始,渐渐剥离边缘的微服务。这种方法可以在微服务体系架构的核心留下一个巨大的单体,大多数新的开辟都发生在微服务中,而这个单体相对来说变化不大。— Martin Fowler
       当一个事件必要在两个地方更新数据时,与两阶段提交相比,终极同等性/SAGA方案是处理分布式事件的更好的方式,重要原因是两阶段提交在分布式情况中不能伸缩。不过终极同等性方案引入了新问题,例如怎样以原子方式更新数据库和发出事件,因此采用这种方案必要开辟和测试团队改变头脑方式。
  <blockquote class="multiquote-1" style="border: none; display: block; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; color: #6a737d; padding-top: 10px; padding-bottom: 10px; padding-left: 20px; padding-right: 10px; margin-bottom: 20px; margin-top: 20px; border-left: 3px solid rgba(0, 0, 0, 0.65); border-right: 1px solid rgba(0, 0, 0, 0.65); background: rgb(249, 249, 249);">   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

    <blockquote class="multiquote-1" style="border: none; display: block; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; color: #6a737d; padding-top: 10px; padding-bottom: 10px; padding-left: 20px; padding-right: 10px; margin-bottom: 20px; margin-top: 20px; border-left: 3px solid rgba(0, 0, 0, 0.65); border-right: 1px solid rgba(0, 0, 0, 0.65); background: rgb(249, 249, 249);">   你好,我是俞凡,在Motorola做过研发,如今在Mavenir做技能工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技能始终保持着浓厚的爱好,平时喜欢阅读、思考,信赖持续学习、终身成长,欢迎一起交换学习。
微信公众号:DeepNoMind

    - END -  本文由 mdnice 多平台发布

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

火影

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表