cqrs axon_具有Spring Boot,Axon CQRS / ES和Docker的微服务

本文介绍了一个结合微服务和命令查询职责分离(CQRS)模式的项目,通过一个产品主数据应用程序示例,展示了如何使用Java、Spring Boot、Axon框架、MongoDB和RabbitMQ实现云原生Java应用。文章提供了Docker容器快速启动指南,以及如何添加和查询产品的详细步骤。

cqrs axon

在过去的一两年中,随着诸如DevOps和微服务之类的新方法一夜之间成为热门话题,软件体系结构的变化速度Swift加快。

在这篇文章中,我想给你介绍一个项目,我一直在努力,它组合两个支架的出过去几年的建筑进展: 微服务命令和查询职责分离模式(或CQRS的简称)。

我们在这里讨论的微服务样本围绕一个虚构的“产品”主数据应用程序,类似于您在大多数零售或制造公司中发现的应用程序。 可以使用简单的RESTful API添加,存储,搜索和检索产品。

该应用程序的源代码是开放的,可以在Github上找到 。 如果下载了它,您将拥有一个演示如何实现“云原生” Java所需的若干功能的应用程序,其中包括:-

在第一部分中,我将使用预构建的Docker容器向您展示如何以最小的工作量获取示例代码。 无需编写任何代码,您可以简单地亲自尝试这些组件,然后在以后查看代码。 在以后的文章中,我将进行更详细的介绍,以便您逐步了解系统的构建方式。

如果您只想直接学习代码,可以在Github上找到所有内容,网址为https://github.com/benwilcock/microservice-sampler

这个怎么运作

该应用程序是使用CQRS架构模式构建的。 在CQRS命令中,诸如ADD之类的命令实际上与诸如VIEW(其中id = 1)之类的查询分开。 在此示例中,域的代码库从字面上被完全分为两个单独的组件– 命令端微服务查询端微服务

像大多数其他12要素应用程序一样 ,这些微服务都负有单一责任。 拥有自己的数据存储; 并且可以彼此独立地部署和扩展。 这是CQRS和微服务的最直接的解释。 CQRS或微服务都不必以这种方式实现,但是出于演示的目的,我选择对读和写关注点进行非常清晰的分离。

逻辑架构看起来像这样:

cqrs-architecture-01

使用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

实例启动并运行后(起初可能要花一些时间),您可以立即使用浏览器浏览一下。 您应该可以访问:

  1. 端口“ 15672”上的Rabbit管理控制台
  2. 端口“ 8761”上的Eureka Discovery Server控制台
  3. 端口“ 8888”上的配置服务器映射
  4. 9000端口上的Product Command Side Swagger API文档
  5. 查询端的空“产品”视图位于端口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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值