cqrs axon
在过去的一两年中,随着诸如DevOps和微服务之类的新方法一夜之间成为热门话题,软件体系结构的变化速度Swift加快。
在这篇文章中,我想给你介绍一个项目,我一直在努力,它组合两个支架的出过去几年的建筑进展: 微服务和命令和查询职责分离模式(或CQRS的简称)。
我们在这里讨论的微服务样本围绕一个虚构的“产品”主数据应用程序,类似于您在大多数零售或制造公司中发现的应用程序。 可以使用简单的RESTful API添加,存储,搜索和检索产品。
该应用程序的源代码是开放的,可以在Github上找到 。 如果下载了它,您将拥有一个演示如何实现“云原生” Java所需的若干功能的应用程序,其中包括:-
- 使用Java和Spring Boot的微服务 ;
- 使用Axon Framework v2 , MongoDB和RabbitMQ的命令和查询责任分离(CQRS)和事件源(ES);
- 使用Docker容器在任何地方构建,运输和运行;
- 使用Spring Cloud进行集中配置和服务注册;
- 加上使用Swagger和SpringFox的 API文档。
在第一部分中,我将使用预构建的Docker容器向您展示如何以最小的工作量获取示例代码。 无需编写任何代码,您可以简单地亲自尝试这些组件,然后在以后查看代码。 在以后的文章中,我将进行更详细的介绍,以便您逐步了解系统的构建方式。
如果您只想直接学习代码,可以在Github上找到所有内容,网址为https://github.com/benwilcock/microservice-sampler
这个怎么运作
该应用程序是使用CQRS架构模式构建的。 在CQRS命令中,诸如ADD之类的命令实际上与诸如VIEW(其中id = 1)之类的查询分开。 在此示例中,域的代码库从字面上被完全分为两个单独的组件– 命令端微服务和查询端微服务 。
像大多数其他12要素应用程序一样 ,这些微服务都负有单一责任。 拥有自己的数据存储; 并且可以彼此独立地部署和扩展。 这是CQRS和微服务的最直接的解释。 CQRS或微服务都不必以这种方式实现,但是出于演示的目的,我选择对读和写关注点进行非常清晰的分离。
逻辑架构看起来像这样:
使用Java的Spring Boot框架开发了命令端和查询端微服务。 命令和查询微服务之间的所有通信都是“事件驱动”的。 使用RabbitMQ消息传递在微服务组件之间传递事件。 消息传递提供了一种可扩展的方式,以松散耦合的方式在流程,微服务,传统系统和其他各方之间传递事件。
请注意,这两个服务如何与另一个共享它的数据库。 这很重要,因为它为每个服务提供了高度的自治性,这反过来又有助于单个服务独立于系统中的其他服务进行扩展。 有关CQRS体系结构的更多信息,请查看我的CQRS Microservices幻灯片共享 ,上面的幻灯片来自该幻灯片。
有关命令行微服务的更多信息
命令是“ 改变状态的动作 ”。 命令端微服务包含所有域逻辑和业务规则。 命令用于添加新产品或更改其状态。 在特定产品上执行这些命令会导致生成“事件”,这些事件由Axon框架保留在MongoDB中,并通过RabbitMQ消息传递到其他进程(尽可能多的进程)。
在事件源中,事件是系统状态的唯一记录。 系统使用它们来描述和重建按需的任何实体的当前状态(通过一次重放过去的事件,直到重新应用所有先前的事件)。 这听起来很慢,但是实际上因为事件很简单,所以它确实非常快,并且可以使用称为“快照”的汇总进一步进行调整。
在域驱动设计(DDD)中,实体通常被称为“聚合”或“根”。
有关查询端微服务的更多信息
查询侧微服务充当事件侦听器和视图。 它侦听命令端发出的“事件”,并将它们处理为最有意义的形状(例如表格视图)。
在此特定示例中,查询端仅构建并维护一个“物化视图”或“投影”,其中包含各个产品的最新状态(就其ID和其描述以及它们是否可销售而言)。 查询侧可以多次复制以实现可伸缩性,并且RabbitMQ队列中保存的消息可以使持久性,因此,如果出现故障,它们甚至可以代表查询侧临时存储消息。
命令端和查询端都具有REST API,可用于访问其功能。
有关更多信息,请参见Axon文档 ,该文档描述了Axon如何将CQRS和事件源带入Java应用程序,以及有关如何配置和使用它的许多详细信息。
运行演示
运行演示代码很容易,但是您首先需要在计算机上安装以下软件。 作为参考,我使用Ubuntu 16.04作为操作系统。
- Docker (我正在使用v1.8.2)
- Docker-compose(我正在使用v1.7.1)
如果同时拥有这两种方法,则可以按照以下概述的过程来运行演示。
如果您已经拥有MongoDB或RabbitMQ,请在继续操作之前关闭这些服务,以避免端口可用性冲突。
步骤1:获取Docker-compose配置文件
在一个新的空文件夹中,在终端上执行以下命令以下载此演示的最新docker-compose配置文件。
$ wget https://raw.githubusercontent.com/benwilcock/microservice-sampler/master/docker-compose.yml
尽量不要更改文件名-Docker默认会查找名为“ docker-compose.yml”的文件。 如果确实要更改名称,请在以下步骤中使用-f开关。
步骤2:启动微服务
因为我们使用的是docker-compose,所以现在启动微服务只是执行以下命令的一种情况。
$ docker-compose up
随着docker镜像的下载和运行,您将在终端窗口中看到大量的下载和日志记录输出。
总共有六个Docker镜像,分别是'mongodb','rabbitmq','config','discovery','product-cmd-side'和'product-qry-side'。
如果您想随时查看机器上正在运行哪些docker实例,请打开一个单独的终端并执行以下命令:
$ docker ps
实例启动并运行后(起初可能要花一些时间),您可以立即使用浏览器浏览一下。 您应该可以访问:
- 端口“ 15672”上的Rabbit管理控制台
- 端口“ 8761”上的Eureka Discovery Server控制台
- 端口“ 8888”上的配置服务器映射
- 9000端口上的Product Command Side Swagger API文档
- 查询端的空“产品”视图位于端口9001上
步骤3:使用产品
到目前为止,一切都很好。 现在我们要测试产品的添加。 在此手动系统测试中,我们将向命令行REST API发出“ add”命令。
当命令方处理完命令后,将引发“ ProductAdded”事件,该事件存储在MongoDB中,并通过RabbitMQ转发给查询方。 然后,查询端将处理此事件,并将产品记录添加到其物化视图(实际上是此简单演示的H2内存数据库)。 处理完事件后,我们可以使用查询端微服务来查找有关已添加的新产品的信息。 在执行这些任务时,应在docker-compose终端窗口中观察一些日志记录输出。
步骤3.1:添加新产品
为了执行此测试,我们首先需要打开第二个终端窗口,从中可以发出一些CURL命令,而无需停止我们在第一个窗口中运行的docker组成实例。
为了进行此测试,我们将MP3产品添加到产品目录中,名称为“ Everything is Awesome”。 为此,我们可以使用命令行REST API并向其发出POST请求,如下所示……
$ curl -X POST -v --header "Content-Type: application/json" --header "Accept: */*" "http://localhost:9000/products/add/1?name=Everything%20Is%20Awesome"
如果没有可用的“ CURL”,则可以使用浏览器来添加产品,方法是导航到命令端Swagger文档随附的简单Web表单。
您应该看到以下响应。
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 9000 (#0)
> POST /products/add/1?name=Everything%20Is%20Awesome HTTP/1.1
> Host: localhost:9000
> User-Agent: curl/7.47.0
> Content-Type: application/json```bash
> Accept: */*$ http://localhost:9000/products/1
< HTTP/1.1 201 Created
< Date: Thu, 02 Jun 2016 13:37:07 GMTThis
< X-Application-Context: product-command-side:9000
< Content-Length: 0
< Server: Jetty(9.2.16.v20160414)
响应代码应为<HTTP / 1.1 201 Created。”这意味着MP3产品“一切都很棒”已成功添加到命令端事件源存储库中。
步骤3.2:查询新产品
现在让我们检查一下是否可以查看刚刚添加的产品。 为此,我们在端口9001上使用查询侧API,并发出简单的“ GET”请求。
$ curl http://localhost:9001/products/1
您应该看到以下输出。 这表明查询侧微服务具有我们新添加的MP3产品的记录。 该产品被列为不可销售(可销售=假)。
{
name: "Everything Is Awesome",
saleable: false,
_links: {
self: {
href: "http://localhost:9001/products/1"
},
product: {
href: "http://localhost:9001/products/1"
}
}
}
而已! 如果愿意,请继续并重复测试以添加更多产品,只是要小心,不要在POST时尝试重用相同的产品ID,否则会看到错误。
如果您熟悉MongoDB,则可以检查数据库以查看创建的所有事件。 同样,如果您知道使用RabbitMQ管理控制台的方式,则可以看到消息在命令端和查询端微服务之间流动时的状态。
翻译自: https://www.javacodegeeks.com/2016/06/microservices-spring-boot-axon-cqrses-docker.html
cqrs axon
本文介绍了一个结合微服务和命令查询职责分离(CQRS)模式的项目,通过一个产品主数据应用程序示例,展示了如何使用Java、Spring Boot、Axon框架、MongoDB和RabbitMQ实现云原生Java应用。文章提供了Docker容器快速启动指南,以及如何添加和查询产品的详细步骤。


801

被折叠的 条评论
为什么被折叠?



