当前位置: 首页 > 科技观察

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

时间:2023-03-14 23:34:51 科技观察

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