编排microservices

编排微服务的标准模式是什么?

如果一个微服务只知道它自己的域,但是有一个数据流要求多个服务以某种方式交互,那么该怎么做呢?

假设我们有这样的东西:

  • 发票
  • 装运

为了便于讨论,让我们假设订单发出后,应该创建发票。

在某处,某人按下GUI中的一个按钮,“我做完了,让我们这样做!” 在一个经典的整体服务架构中,我会说要么有一个ESB处理这个,要么Shipment服务有发票服务的知识,只是调用它

但是,在这个勇敢的微服务新世界中,人们是如何处理这些问题的呢?

我知道这可能被认为是高度基于意见的。但它也有具体的一面,因为微服务不应该做上述事情。 所以必须有一个“根据定义它应该做什么”,这不是基于意见的

开枪。

87741 次浏览

所以你有两个服务:

  1. 发票微服务
  2. 货运微服务

在现实生活中,你会有一些保持有序状态的东西。我们称它为顺序服务。接下来是订单处理用例,它知道当订单从一种状态转换到另一种状态时该做什么。所有这些服务都包含一组特定的数据,现在您需要其他的东西来进行所有的协调。这可能是:

  • 了解所有服务和实现用例的简单GUI(“我完成了”调用发货服务)
  • 一个等待“I'm done”事件的业务流程引擎。这个引擎实现了用例和流程。
  • 一个编配微服务,比如说订单处理服务本身,它知道你的领域的流程/用例
  • 还有其他我没想过的吗

主要的一点是控制是外部的。这是因为所有应用程序组件都是独立的构建块,松散耦合。如果您的用例发生了变化,您必须在一个地方更改一个组件,即编制组件。如果您添加了不同的订单流,您可以轻松地添加另一个不干扰第一个编排器的编排器。微服务的思想不仅仅是关于可伸缩性和使用花哨的REST API,还包括一个清晰的结构,减少组件之间的依赖关系,以及在整个业务中共享的公共数据和功能的重用。

HTH,马克

试着把不同的方法聚合在一起。

域的事件

主要的方法似乎是使用域事件,其中每个服务发布关于已发生事件的事件,其他服务可以订阅这些事件。 这似乎与Martin Fowler在这里描述的聪明的端点,愚蠢的管道的概念密切相关:http://martinfowler.com/articles/microservices.html#SmartEndpointsAndDumbPipes

Domain events

代理

另一种常见的方法是将业务流包装在自己的服务中。 代理协调微服务之间的交互,如下图所示:

代理

其他组合模式

这个页面包含各种组合模式。

这本书建筑Microservices详细描述了@RogerAlsing在他的回答中提到的风格。

在43页的编配vs编舞中,这本书说:

当我们开始建模越来越复杂的逻辑时,我们必须处理 管理业务流程的问题横跨 单个服务的边界。有了微服务,我们就成功了 这个极限比平时快。[…当谈到实际上 实现这个流程,我们可以使用两种风格的体系结构 跟进。对于编曲,我们依靠中央大脑来指导和 驱动过程,就像管弦乐队的指挥一样。与 编排,我们通知系统的每个部分它的工作,并让它 解决细节问题,就像舞者找到自己的路一样

.在芭蕾舞中对周围的人做出反应

这本书接着解释了这两种风格。编排风格更多地对应于编制/任务服务的SOA思想,而编排风格对应于Martin Fowler的文章中提到的哑管道和智能端点

编排风格

在这种风格下,上面的书提到:

让我们考虑一下编排解决方案是什么样的 这个流。这里,可能最简单的方法就是 我们的客户服务就像中央大脑一样。关于创造,它会说话 到忠诚积分银行、电子邮件服务和邮政服务[…] 通过一系列的请求/响应调用。的 客户服务本身可以跟踪客户在其中的位置 的过程。它可以检查客户的帐户是否已设置 起床,或者发送邮件,或者投递邮件。我们可以 流程图[…]并将其直接建模成代码。我们甚至可以用 为我们实现这一点的工具,可能使用适当的 规则引擎。商业工具就是为了这个目的而存在的 业务流程建模软件。假设我们使用同步 请求/响应,我们甚至可以知道每个阶段是否工作[…] 这种编排方法的缺点是客户 服务可能成为一个过于集中的管理机构。它可以 成为网络中间的枢纽,成为逻辑的中心点 开始生活。我已经看到这种方法导致了少量的 智能的“上帝”服务告诉贫血的基于crud的服务该做什么

注意:我认为当作者提到工具时,他指的是类似BPM的东西(例如活动Apache ODE)。事实上,工作流程模式网站有一组很棒的模式来做这种编排,它还提供了不同供应商工具的评估细节,帮助以这种方式实现它。我不认为作者暗示需要使用这些工具之一来实现这种风格的集成,尽管如此,其他轻量级编排框架也可以使用,例如Spring IntegrationApache骆驼Mule ESB

然而,其他的书我读过关于微服务的主题,一般来说,我在网上找到的大多数文章似乎都是反对这种方法的编排,而不是建议使用下一个。

编排风格

编舞风格下,作者说:

使用编排的方法,我们可以只拥有客户 服务以异步方式发出一个事件,即Customer 创建。电子邮件服务、邮政服务和忠诚积分银行 然后订阅这些事件并做出相应的反应[…] 这种方法明显更加去耦。如果一些 其他服务需要达到客户的创建,它只是 需要订阅事件并在需要时完成其工作。的 缺点是我们在其中看到的业务流程的显式视图 [工作流]现在只是隐式地反映在我们的系统中[…] 这意味着需要额外的工作来确保您可以进行监控 并跟踪正确的事情发生了。例如,你愿意 知道忠诚度积分银行是否存在漏洞,或者出于某种原因没有 建立正确的账户?我喜欢的一种处理方法是 是要建立一个明确匹配的监控系统 在[工作流]中的业务流程,然后跟踪每个流程 服务作为独立的实体,让您看到奇怪 异常映射到更显式的流程流。(流程图) […并不是驱动力,只是一个镜头 我们可以看到系统是如何运行的。总的来说,我发现 那些更倾向于编排方法的系统 松散耦合,更灵活,更适应变化。你做 需要做额外的工作来监视和跟踪整个系统的进程 然而,边界。都是精心策划的 实现非常脆弱,具有更高的更改成本。 考虑到这一点,我强烈倾向于设计舞蹈 在系统中,每个服务都足够智能,能够了解自己在其中的角色

注意:直到今天,我仍然不确定编舞是否只是事件驱动架构 (EDA)的另一个名称,但如果EDA只是一种方式来做它,其他的方式是什么?(参见你所说的“事件驱动”是什么意思?事件驱动体系结构的意义)。而且,CQRS和EventSourcing之类的东西似乎与这种架构风格有很多共鸣,对吧?

现在,在这之后是乐趣。微服务这本书并没有假设微服务将使用REST实现。事实上,在本书的下一节中,他们将继续考虑RPC和基于soa的解决方案,最后是REST。这里很重要的一点是,微服务并不意味着REST。

那么,HATEOAS怎么样? (超媒体作为应用状态的引擎)

现在,如果我们想要遵循RESTful方法,就不能忽视HATEOAS,否则Roy Fielding会很高兴地在他的博客中说,我们的解决方案不是真正的REST。参见他在REST API必须是超文本驱动的上的博客文章:

我对调用任何基于http的人的数量感到沮丧 接口一个REST API。需要做什么来制作REST 架构风格明确,超文本是一种概念 约束?换句话说,如果应用程序的引擎状态(和 因此API)不是由超文本驱动的,那么它就不可能是 RESTful的,不能是REST API。时期。有什么坏了的手册吗 某个需要修理的地方?< / p >

因此,如您所见,Fielding认为如果没有HATEOAS,就不能真正构建RESTful应用程序。对于Fielding来说,HATEOAS是编排服务的最佳方式。我只是在学习这一切,但对我来说,HATEOAS并没有清楚地定义谁或什么是真正遵循链接背后的驱动力。在UI中可能是用户,但在计算机对计算机交互中,我认为这需要由更高级别的服务来完成。

根据HATEOAS, API使用者真正需要知道的唯一链接是发起与服务器通信的链接(例如POST /order)。从这一点开始,REST将执行流,因为在此端点的响应中,返回的资源将包含到下一个可能状态的链接。然后API使用者决定遵循哪个链接并将应用程序移动到下一个状态。

尽管这听起来很酷,客户端仍然需要知道链接是否必须post、PUTed、GETed、PATCHed等等。客户端仍然需要决定传递什么有效负载。客户端仍然需要知道如果失败了该做什么(重试、补偿、取消等等)。

我对这一切都很陌生,但对我来说,从hateoa的角度来看,这个客户机或API使用者是一个高级服务。如果我们从人的角度来考虑,你可以想象一个网页上的最终用户,决定遵循哪些链接,但是网页的程序员仍然必须决定使用什么方法来调用链接,以及传递什么有效负载。所以,在我看来,在计算机对计算机的交互中,计算机扮演了最终用户的角色。这就是我们所说的编排服务。

我认为我们可以将HATEOAS用于编配或编排。

API网关模式

Chris Richardson提出了另一个有趣的模式,他也提出了他所谓的API网关模式

在单片架构中,应用程序的客户端,例如web 浏览器和本机应用程序通过加载发出HTTP请求 应用程序的N个相同实例中的一个。但是在 微服务架构,整体已经被一个 服务的集合。因此,我们需要回答一个关键问题 客户端与什么交互?< / p > 应用程序客户端,例如本机移动应用程序,可以使 对单个服务的RESTful HTTP请求[…][背诵文选表面上 这似乎很有吸引力。然而,很可能会有一个 个人api之间的粒度明显不匹配 客户需要的服务和数据。例如,显示一个 Web页面可能需要调用大量的服务。 比如亚马逊, 描述了如何一些 页面需要调用100多个服务。甚至提出了那么多要求 通过高速互联网连接,更不用说低带宽了, 时延较高的移动网络,将会非常低效而导致

一个更好的方法是让客户做少量的 请求每个页面,也许只有一个,通过Internet到一个

.前端服务器即API网关 API网关位于应用程序的客户端和接口之间 microservices。它提供了为客户量身定制的api。的 API网关为移动客户端提供了一个粗粒度的API 为使用高性能的桌面客户端提供细粒度的API 网络。在本例中,桌面客户端发出多个请求 检索关于产品的信息,而移动客户端

API网关通过向some发出请求来处理传入的请求 高性能局域网上的微服务数量。Netflix, 的例子, 描述 每个请求如何扇形到平均六个后端服务。在这个 例如,来自桌面客户机的细粒度请求是简单的 代理到相应的服务,而每个粗粒度 的结果进行聚合,从而处理来自移动客户机的请求

.调用多个服务 API网关不仅优化客户端之间的通信 和应用程序,但它也封装的细节 microservices。这使得微服务能够在没有 影响客户。例如,两个微服务可能是 合并。另一个微服务可能被划分为两个或多个 服务。只有API网关需要更新来反映这些 的变化。

.客户端不受影响 现在我们已经了解了API网关如何在 应用程序及其客户机,现在让我们看看如何实现 微服务之间的通信

这听起来与上面提到的编曲风格非常相似,只是意图略有不同,在这种情况下,它似乎都是关于性能和简化交互。

那么,微服务的编排与非“微”的旧SOA服务的编排有什么不同呢?一点也不多。

微服务通常使用http (REST)或消息/事件进行通信。业务流程通常与业务流程平台相关联,这些平台允许您在服务之间创建脚本化的交互,以使工作流自动化。在旧的SOA时代,这些平台使用WS-BPEL。今天的工具不使用BPEL。现代编配产品的例子:Netflix Conductor, Camunda, Zeebe, Azure Logic Apps, Baker。

请记住,编排是一种复合模式,它提供多种功能来创建复杂的服务组合。微服务通常被视为不应该参与复杂组合的服务,而是更自治的服务。

我可以看到在编排工作流中调用微服务来做一些简单的处理,但我没有看到微服务是编排服务,它通常使用补偿事务和状态存储库(脱水)等机制。

如果状态需要管理,那么使用CQRS的事件源是理想的通信方式。除此之外,异步消息传递系统(AMQP)可以用于微服务之间的通信。

从你的问题可以看出,ES和CQRS应该是正确的组合。如果使用java,可以看看Axon框架。或者使用Kafka或RabbitMQ构建自定义解决方案。

关于这个话题,我写过几篇文章:

也许这些帖子也能有所帮助:

API网关模式——粗粒度API vs细粒度API

https://www.linkedin.com/pulse/api-gateway-pattern-ronen-hamias/ https://www.linkedin.com/pulse/successfulapi-ronen-hamias/ < / p >

粗粒度服务API与细粒度服务API

根据定义,粗粒度服务操作的范围比细粒度服务更广,尽管这两个术语是相对的。粗粒度增加了设计复杂性,但可以减少完成任务所需的调用数量。在微服务架构中,粗粒度的服务可能驻留在API网关层,并编排几个微服务来完成特定的业务操作。粗粒度API需要仔细设计,因为涉及多个管理不同专业领域的微服务,可能会在单个API中混合关注点,并破坏上面描述的规则。粗粒度api可能会为业务功能提供新的粒度级别,否则就不存在这种级别。例如,雇佣员工可能涉及到两个微服务调用HR系统创建员工ID,另一个调用LDAP系统创建用户帐户。或者客户端可能执行了两个细粒度的API调用来实现相同的任务。粗粒度API表示业务用例创建用户帐户,细粒度API表示此类任务所涉及的功能。此外,更细粒度的API可能涉及不同的技术和通信协议,而粗粒度的API将它们抽象为统一的流。在设计系统时,要同时考虑这两方面,因为没有解决所有问题的黄金方法,每一种方法都需要权衡。粗粒度特别适合作为在其他业务上下文中使用的服务,例如其他应用程序、业务线,甚至是跨企业边界的其他组织(典型的B2B场景)。

原来问题的答案是SAGA模式。

你可以使用spring 状态机模型来实现业务流程。

步骤

  1. 将以下依赖项添加到您的项目中(如果您使用Maven)

     <dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-core</artifactId>
    <version>2.2.0.RELEASE</version>
    </dependency>
    
  2. 定义状态和事件,例如状态1,状态2和事件1和事件2

State Machine

  1. buildMachine ()方法中提供状态机实现。

    configureStates
    configureTransitions
    
  2. 将事件发送到状态机

完整的代码请参考文档页