欢迎来到Introzo百科
Introzo百科
当前位置:网站首页 > 技术 > 如何结合微服务和无服务器?使用新的事件驱动架构CQRS!

如何结合微服务和无服务器?使用新的事件驱动架构CQRS!

日期:2023-10-01 12:41

本文将介绍如何在微服务中实现 CQRS 模式,并深入探讨为什么 Serverless 非常适合此类系统。最后将介绍一个使用Spring Cloud Stream实现CQRS的参考应用程序。 本文将介绍如何在微服务中实现 CQRS 模式,并深入探讨为什么 Serverless 非常适合此类系统。 ***中将介绍一个使用Spring Cloud Stream实现CQRS的参考应用。 什么是事件驱动架构? 事件驱动架构优先考虑领域事件,但这种架构已逐渐被淘汰。 我们每天使用的一个例子是前端应用程序。在当今使用的网络浏览器中,事件是通过从用户表单捕获输入数据来处理的,并且连接到页面元素的事件将由显式映射的函数来处理,该函数在触发时将更改应用于用户界面中的状态。 最近,随着微服务的广泛流行,人们对如何在分布式后端系统中利用事件驱动技术产生了新的兴趣。 连续QRS 如今,事件驱动架构中最流行的实践之一称为 CQRS,它代表命令查询职责分离。 CQRS 是一种架构风格,允许您使用不同的模型来更新和读取域数据。 CQRS 的基本思想是,你用来更新和读取数据的模型很自然地彼此分离。上图描述了这个基本思想。 CQRS 在事件驱动架构中如此流行的原因是输入的领域事件在结构上与其所属的领域模型不同。以下面代表帐户的域模型对象为例。 示例 1. 账户集成 { "createdAt":1481351048967, "lastModified":1481351049385, "userId":1, "accountNumber":"123456", "defaultAccount": true, "status":"ACCOUNT_ACTIVE" } 当服务想要查询帐户时使用此模型。那么如果我们想将状态更新为 ACCOUNT_SUSPENDED 该怎么办?通常,简单地更新域对象的状态字段就足够了。现在,如果我们想使用域事件来更新状态怎么办?由于领域对象在结构上与事件不同,因此我们需要一个接受不同模型作为命令的 API。 以下代码片段是将帐户状态从 ACCOUNT_ACTIVE 转换为 ACCOUNT_SUSPENDED 的领域事件。示例 2. 帐户事件 { "createdAt":1481353397395, "lastModified":1481353397395, "type":"ACCOUNT_SUSPENDED", "accountNumber":"123456" } 为了处理这个领域事件并将更新应用到查询模型,我们必须有一个接受命令的 API。此命令将包含域事件的模型,并使用该模型来处理帐户查询模型的更新。 将命令模型与查询模型分离是对 CQRS 最简单的解释。我们今天看到的复杂性更多地与实现类型有关,尤其是在将模式应用于微服务时。 CQRS 和微服务 如果将CQRS与微服务结合起来,毫不夸张地说,情况会变得有点复杂。让我们看看使用 Spring Boot 实现 CQRS 的“简单”微服务是什么样子的。 上图是CQRS模式实现的简化图。图中,我们将一个微服务分为命令端、查询端和事件处理器。这三个部分可以相互独立部署。 命令终端 本示例中的命令端提供了一个 REST API,用于接受通过 HTTP 发送的请求。请求采用命令的形式,可以驱动微服务拥有的域数据的状态更改。简而言之,对域数据的任何写入都将作为命令从 API 请求中流出,处理导致数据库更改的操作。 命令触发操作,操作触发域事件。领域事件存储在事件存储中,事件存储是“将数据库与消息代理相结合的系统”。最适合入门的事件存储是 Eventuate,这是 Chris Richardson 创建的一个项目,旨在帮助实施 CQRS 和事件溯源。到微服务。 域事件存储为附加到日志中的按时间顺序排列的一系列事件。由于每个命令都会生成一个事件,因此我们能够根据收集的事件历史记录重建当前系统的整体状态。 事件处理程序 我们将探讨的下一个组件是事件处理程序。该 CQRS 组件采用 Worker 应用程序的形式,负责摄取域事件。事件处理程序是无状态的,监听来自事件存储的消息,对传入的事件消息采取操作。 事件处理程序可以通过许多有用的方式响应新的域事件。一个领域事件可以生成多个事件,这些事件可以发送到其他微服务。这就是大多数微服务开发人员被 CQRS 所吸引的原因,因为它允许从有界环境之外的应用程序发布和订阅域事件。 这种方法为我们提供了一种确保域数据引用完整性的机制。来自其他微服务的消息可用于处理域事件,使我们能够在分布式系统中维护与其他记录的域数据之间烦人的外键关系。 查询端 事件处理程序主要负责应用可以更改域集成状态的域事件。每个领域事件都可用于更新数据库记录,形成描述集成的增量物化视图。反过来,查询端将提供一个 REST API,允许 HTTP 客户端读取从处理的事件生成的物化视图。 查询端组件的限制是域数据是只读的。该系统中的所有状态更改都从命令端流出,然后形成可以在查询端读取的物化视图。 是分布式集成还是微服务? 如今,当大多数人想到单个微服务时,他们会想到独立的服务组件。在大多数情况下,微服务被构建为专注于做好一件事的应用程序。最重要的是,该服务可以独立于其他服务进行升级和部署。 现在,如果我们谈论传统的 CQRS 实现,将其称为微服务似乎不合适,因为组件彼此分离。那么我们要问:CQRS应用程序可以被视为微服务吗?或者换句话说,我们是否可以像一些开发人员所做的那样,开始将其称为分布式集成?对于这个问题,不同的人会有不同的答案。微服务主要是为了让小型独立团队能够持续交付功能,作为其他微服务的更大生态系统的一部分。 与大多数微服务部署相比,CQRS 部署非常复杂。对于微服务团队来说,能够持续向生产交付功能是目标。由于CQRS中分离的组件仍然可以独立部署,因此可以说每个部署单元仍然可以满足独立向生产交付功能的最终要求。微服务的一项功能应该始终需要且最多一个可部署单元。当交付一个功能需要同时协调部署多个独立组件时,就会出现所谓的分布式集成。 微服务和无服务器 无服务器,也称为 FaaS(函数即服务),允许您将代码部署为函数,而无需设置或管理应用程序服务器或容器。无服务器是一种新的架构风格,在构建和运行云原生应用程序方面越来越受欢迎。使用无服务器函数的一个显着优势是事件概念具有优先级。 许多人认为微服务和无服务器是不兼容的,并且具有完全不同的架构风格。但如果你回想一下前面提到的CQRS,你就会明白这个想法是错误的。让我们看一个场景。您认为这种场景下微服务的边界在哪里? 一种方法是将微服务的边界视为团队的边界。只要团队能够独立且持续地将特性部署为功能,微服务的边界就只是负责支持团队拥有的功能的功能子集。权衡 采用微服务和无服务器相结合的方法需要您仔细权衡几件事,所以让我们看看需要注意什么。 速度 对于微服务来说,速度是目标。我们可以通过关注以下两个问题来衡量速度。平均时间越短,团队交付功能的速度就越快。 : 开发人员更改一行代码并将其安全部署到生产环境的速度有多快? 新开发人员能够多快地跟上并安全地对代码库进行更改? 无服务器有一个学习曲线,但有助于提高微服务的速度。它通过将大量工作流管理从核心组件转移到可以独立升级和部署的小型可组合功能中来提高速度。这可以最大限度地减少开发人员了解各个功能如何工作以及如何安全地更改它们所需的时间。 无服务器功能也易于升级或部署,但可能会使整个系统的理解变得更加复杂。管理数百个无服务器功能作为一个整体听起来有点让人不知所措。 复杂 软件的复杂性是不可避免的,并且随着代码库的老化而不断增加。当复杂性增加时,或者当框架或语言变得过时时,单体应用程序就会变得笨重且难以更改。微服务器将这种复杂性分解为分布式系统,其中每个可部署单元都易于理解,并且易于由敏捷开发人员组成的小团队进行更改。 云原生 CQRS 参考应用程序 这是一个参考应用程序,它将云原生 CQRS 应用程序构建为事件驱动的微服务和无服务器功能的组合。

关灯