消息驱动式微服务:Spring Cloud Stream & RabbitMQ
1. 概述
在本文中,我们将向您介绍Spring Cloud Stream,这是一个用于构建消息驱动的微服务应用程序的框架,这些应用程序由一个常见的消息传递代理(如RabbitMQ、Apache Kafka等)连接。
Spring Cloud Stream构建在现有Spring框架(如Spring Messaging和Spring Integration)之上。尽管这些框架经过了实战测试,工作得非常好,但是实现与使用的message broker紧密耦合。此外,有时对某些用例进行扩展是困难的。
Spring Cloud Stream背后的想法是一个非常典型的Spring Boot概念——抽象地讲,让Spring根据配置和依赖关系管理在运行时找出实现自动注入。这意味着您可以通过更改依赖项和配置文件来更改message broker。可以在这里找到目前已经支持的各种消息代理。
本文将使用RabbitMQ作为message broker。在此之前,让我们了解一下broker(代理)的一些基本概念,以及为什么要在面向微服务的体系架构中需要它。
2. 微服务中的消息
在微服务体系架构中,我们有许多相互通信以完成请求的小型应用程序—它们的主要优点之一是改进了的可伸缩性。一个请求从多个下游微服务传递到完成是很常见的。例如,假设我们有一个Service-A内部调用Service-B和Service-C来完成一个请求:
[外链图片转存失败(img-jzvHHRXw-1562549429195)(https://user-gold-cdn.xitu.io/2019/7/7/16bccd47c4051b28?w=511&h=347&f=png&s=11713)]
是的,还会有其他组件,比如Spring Cloud Eureka、Spring Cloud Zuul等等,但我们还是专注关心这类架构的特有问题。
假设由于某种原因Service-B需要更多的时间来响应。也许它正在执行I/O操作或长时间的DB事务,或者进一步调用其它导致Service-B变得更慢的服务,这些都使其无法更具效率。
现在,我们可以启动更多的Service-B实例来解决这个问题,这样很好,但是Service-A实际上是响应很快的,它需要等待Service-B的响应来进一步处理。这将导致Service-A无法接收更多的请求,这意味着我们还必须启动Service-A的多个实例。
另一种方法解决类似情况的是使用事件驱动的微服务体系架构。这基本上意味着Service-A不直接通过HTTP调用Service-B或Service-C,而是将请求或事件发布给message broker(消息代理)。Service-B和Service-C将成为message broker(消息代理)上此事件的订阅者。
与依赖HTTP调用的传统微服务体系架构相比,这有许多优点:
- 提高可伸缩性和可靠性——现在我们知道哪些服务是整个应用程序中的真正瓶颈。
- 鼓励松散耦合——
Service-A不需要了解Service-B和Service-C。它只需要连接到message broker并发布事件。事件如何进一步编排取决于代理设置。通过这种方式,Service-A可以独立地运行,这是微服务的核心概念之一。 - 与遗留系统交互——通常我们不能将所有东西都移动到一个新的技术堆栈中。我们仍然必须使用遗留系统,虽然速度很慢,但是很可靠。
3. RabbitMQ
高级消息队列协议(AMQP)是RabbitMQ用于消息传递的协议。虽然RabbitMQ支持其他一些协议,但是AMQP由于兼容性和它提供的大量特性而更受欢迎。
3.1 RabbitMQ架构设计
因此发布者将消息发布到RabbitMQ中称为Exchange(交换器)。Exchange(交换器)接收消息并将其路由到一个或多个Queues(队列)。路由算法依赖于Exchange(交换器)类型和routing(路由)key/header(与消息一起传递)。将Exchange(交换器)连接到Queues(队列)的这些规则称为bindings(绑定)。
绑定可以有4种类型:
- Direct: 它根据
routing key(路由键)将Exchange(交换器)类型直接路由到特定的Queues(队列)。 - Fanout:它将消息路由到绑定
Exchange(交换器)中的所有Queues(队列)。 - Topic:它根据完全匹配或部分据
routing key(路由键)匹配将消息路由到(0、1或更多)的Queues(队列)。 - Headers:它类似于
Topic(主题)交换类型,但是它是基routing header(路由头)而不是routing key(路由键)来路由的。
通过Exchange(交换器)和Queues(队列)发布和消费消息的整个过程是通过一个Channel(通道)完成的。
有关路由的详细信息,请访问此链接。
3.2 RabbitMQ 设置
3.2.1 安装
我们可以从这里下载并安装基于我们的操作系统的二进制文件。
然而,在本文中,我们将使用cloudamqp.com提供的免费云安装。只需注册服务并登录即可。
在主仪表板上单击创建新实例:
然后给你的实例起个名字,然后进入下一步:
然后选择一个可用区:
最后,查看实例信息,点击右下角的创建实例:
就是这样。现在在云中运行了一个RabbitMQ实例。有关实例的更多信息,请转到您的仪表板并单击新创建的实例:
我们可以看到我们可以访问RabbitMQ实例的主机,比如从我们的项目连接所需的用户名和密码:
我们将在Spring应用程序中使用AMQP URL连接到这个实例,所以请在某个地方记下它。
您还可以通过单击左上角的RabbitMQ manager来查看管理器控制台。这将采用它来管理的您的RabbitMQ实例。
Project 配置
现在我们的设置已经准备好了,让我们创建我们的服务:
- cloud-stream-producer-rabbitmq: 作为一个发布者,将消息推送到
RabbitMQ - cloud-stream-consumer-rabbitmq: 消费者消费消息
使用Spring Initializr创建一个脚手架项目。这将是我们的producer项目,我们将使用REST端点发布消息。
选择您喜欢的Spring Boot版本,添加Web和Cloud Stream依赖项,生成Maven项目:
注意:
请注意cloud-stream依赖项。这也需要像RabbitMQ、Kafka等绑定器依赖项才能工作。
由于我们将使用RabbitMQ,添加以下Maven依赖项:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
或者,我们也可以将两者结合起来使用spring-cloud-starter-stream-rabbit:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
使用同样的方法,创建消费者项目,但仅使用spring-cloud-starter-stream-rabbit依赖项。
4. 创建生产者
如前所述,将消息从发布者传递到队列的整个过程是通过通道完成的。因此,让我们创建一个HelloBinding接口,其中包含我们的消息机制greetingChannel:
interface HelloBinding {
@Output("greetingChannel")
MessageChannel greeting();
}
因为这将发布消息,所以我们使用@Output注解。方法名可以是我们想要的任意名称,当然,我们可以在一个接口中有多个Channel(通道)。
现在,让我们创建一个REST,它将消息推送到这个Channel(通道)
@RestController
public class ProducerController {
private MessageChannel greet;
public ProducerController(HelloBinding binding) {
greet = binding.greeting();
}
@GetMapping("/greet/{name}")
public void publish(@PathVariable String name) {
String greeting = "Hello, " + name + "!";
Message<String> msg = MessageBuilder.withPayload(greeting)
.build();
this.greet.send(msg);
}
}
上面,我们创建了一个ProducerController类,它有一个MessageChannel类型的属性 greet。这是通过我们前面声明的方法在构造函数中初始化的。
注意: 我们可以用简洁的方式做同样的事情,但是我们使用不同的名称来让您更清楚地了解事物是如何连接的。
然后,我们有一个简单的REST接口,它接收PathVariable的name,并使用MessageBuilder创建一个String类型的消息。最后,我们使用MessageChannel上的.send()方法来发布消息。
现在,我们将在的主类中添加@EnableBinding注解,传入HelloBinding告诉Spring加载。
@EnableBinding(HelloBinding.class)
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
最后,我们必须告诉Spring如何连接到RabbitMQ(通过前面的AMQP URL),并将greetingChannel连接到一可用的消费者。
这两个都是在application.properties中定义的:
spring.rabbitmq.addresses=<amqp url>
spring.cloud.stream.bindings.greetingChannel.destination = greetings
server.port=8080
5. 创建消费者
现在,我们需要监听之前创建的通道greetingChannel。让我们为它创建一个绑定:
public interface HelloBinding {
String GREETING = "greetingChannel";
@Input(GREETING)
SubscribableChannel greeting();
}
与生产者绑定的两个非常明显区别。因为我们正在消费消息,所以我们使用SubscribableChannel和@Input注解连接到greetingChannel,消息数据将被推送这里。
现在,让我们创建处理数据的方法:
@EnableBinding(HelloBinding.class)
public class HelloListener {
@StreamListener(target = HelloBinding.GREETING)
public void processHelloChannelGreeting(String msg) {
System.out.println(msg);
}
}
在这里,我们创建了一个HelloListener类,在processHelloChannelGreeting方法上添加@StreamListener注解。这个方法需要一个字符串作为参数,我们刚刚在控制台打印了这个参数。我们还在类添加@EnableBinding启用了HelloBinding。
同样,我们在这里使用@EnableBinding,而不是主类,以便告诉我们如何使用。
看看我们的主类,我们没有任何修改:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
在application.properties配置文件中,我们需要定义与生产者一样的属性,除了修改端口之外
spring.rabbitmq.addresses=<amqp url>
spring.cloud.stream.bindings.greetingChannel.destination=greetings
server.port=9090
6. 全部测试
让我们同时启动生产者和消费者服务。首先,让我们通过点击端点http://localhost:8080/greet/john来生产消息。
在消费者日志中看到消息内容:
我们使用以下命令启动另一个消费者服务实例(在另一个端口(9091)上):
$ mvn spring-boot:run -Dserver.port=9091
现在,当我们点击生产者REST端点生产消息时,我们看到两个消费者都收到了消息:
这可能是我们在一些用例中想要的。但是,如果我们只想让一个消费者消费一条消息呢?为此,我们需要在application.properties中创建一个消费者组。消费者的配置文件:
spring.cloud.stream.bindings.greetingChannel.group = greetings-group
现在,再次在不同的端口上运行消费者的2个实例,并通过生产者生产消息再次查看:
这一切也可以在RabbitMQ管理器控制台看到:
7. 结论
在本文中,我们解释了消息传递的主要概念、它在微服务中的角色以及如何使用Spring Cloud Stream实现它。我们使用RabbitMQ作为消息代理,但是我们也可以使用其他流行的代理,比如Kafka,只需更改配置和依赖项。
与往常一样,本文使用的示例代码可以在GitHub获得完整的源代码。
消息驱动式微服务:Spring Cloud Stream & RabbitMQ的更多相关文章
- SpringCloud---消息驱动的微服务---Spring Cloud Stream
1.概述 1.1 Spring Cloud Stream:用来 为微服务应用 构建 消息驱动能力的框架: 可基于SpringBoot来创建独立.可用于生产的Spring应用程序: 使用Sp ...
- Spring Cloud Alibaba学习笔记(12) - 使用Spring Cloud Stream 构建消息驱动微服务
什么是Spring Cloud Stream 一个用于构建消息驱动的微服务的框架 应用程序通过 inputs 或者 outputs 来与 Spring Cloud Stream 中binder 交互, ...
- 使用 Spring Cloud Stream 构建消息驱动微服务
相关源码: spring cloud demo 微服务的目的: 松耦合 事件驱动的优势:高度解耦 Spring Cloud Stream 的几个概念 Spring Cloud Stream is a ...
- Spring Cloud集成RabbitMQ的使用
同步 or 异步 前言:我们现在有一个用微服务架构模式开发的系统,系统里有一个商品服务和订单服务,且它们都是同步通信的. 目前我们商品服务和订单服务之间的通信方式是同步的,当业务扩大之后,如果还继续使 ...
- Spring Cloud 系列之 Spring Cloud Stream
Spring Cloud Stream 是消息中间件组件,它集成了 kafka 和 rabbitmq .本篇文章以 Rabbit MQ 为消息中间件系统为基础,介绍 Spring Cloud Stre ...
- Spring Cloud Stream 知识点
发布-订阅模式 在Spring Cloud Stream中的消息通信方式遵循了发布-订阅模式,当一条消息被投递到消息中间件之后,它会通过共享的Topic主题进行广播,消息消费者在订阅的主题中收到它并触 ...
- 第十章 消息驱动的微服务: Spring Cloud Stream
Spring Cloud Stream 是一个用来为微服务应用构建消息驱动能力的框架. 它可以基于Spring Boot 来创建独立的. 可用于生产的 Spring 应用程序. 它通过使用 Sprin ...
- 「 从0到1学习微服务SpringCloud 」08 构建消息驱动微服务的框架 Spring Cloud Stream
系列文章(更新ing): 「 从0到1学习微服务SpringCloud 」01 一起来学呀! 「 从0到1学习微服务SpringCloud 」02 Eureka服务注册与发现 「 从0到1学习微服务S ...
- 消息驱动微服务:Spring Cloud Stream
最近在学习Spring Cloud的知识,现将消息驱动微服务:Spring Cloud Stream 的相关知识笔记整理如下.[采用 oneNote格式排版]
随机推荐
- HDU5187 zhx's contest(计数问题)
主题链接: http://acm.hdu.edu.cn/showproblem.php?pid=5187 题意: 从1~n,有多少种排列 使得 a1~ai 满足单调递增或者单调递减. ai~an 满足 ...
- python短信轰炸机版本smsbomb----------部分(post)
用一些用手机号注冊且须要发送验证码的站点的漏洞.能够向不论什么人的手机号发送短信,当然短信内容,我们无法控制.所以主要工作还是寻找这种站点.然后利用Fiddler或者HttpWatch分析请求.使用p ...
- AngularJS 多级下拉框
<div ng-app="MultiDropDownApp" ng-controller="MultiDropDownControl as vm"> ...
- Delphi中的线程类 - TThread详解
Delphi中的线程类 - TThread详解 2011年06月27日 星期一 20:28 Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本 ...
- python 编码转换 专题
主要介绍了python的编码机制,unicode, utf-8, utf-16, GBK, GB2312,ISO-8859-1 等编码之间的转换. 常见的编码转换分为以下几种情况: 自动识别 字符串编 ...
- Image Captioning代码复现
Image caption generation: https://github.com/eladhoffer/captionGen Simple encoder-decoder image capt ...
- Windows10 【系统周期表】【系统下载表】【大型软件表】
系统周期表 商用名称 商用英文名 代号 版本 系统版本 上市日期 服务周期 备注 Windows 10 无 Threshold 1 1507 10.0.10240.17443 2015.07.29 2 ...
- 零元学Expression Blend 4 - Chapter 3 熟悉操作第一步(制作一个猴子脸)
原文:零元学Expression Blend 4 - Chapter 3 熟悉操作第一步(制作一个猴子脸) 本篇内容会教你如何使用笔刷.钢笔.渐层以及透明度的调整,还有如何转化图层和路径,最重要的是要 ...
- Android零基础入门第45节:GridView简单使用
原文:Android零基础入门第45节:GridView简单使用 前面一共用了8期来学习ListView列表的相关操作,其实学习的ListView的知识完全适用于AdapterView的其他子类,如G ...
- Android自定义View入门(一)
最近在写一个关于音乐播放的应用,写到播放界面UI时,就想自己实现的一个播放界面.那么如何实现自定义View呢?通过查看他人博客和Android官方开发文档,初步了解了一些浅显的内容.在此记录,已供需要 ...