Spring Cloud Stream 知识点

发布-订阅模式

在Spring Cloud Stream中的消息通信方式遵循了发布-订阅模式,当一条消息被投递到消息中间件之后,它会通过共享的Topic主题进行广播,消息消费者在订阅的主题中收到它并触发自身的业务逻辑处理。这里所提到的Topic主题是Spring Cloud Stream中的一个抽象概念,用来代表发布共享消息给消费者的地方。在不同的消息中间件中,Topic可能对应着不同的概念,比如:在RabbitMQ中的它对应了Exchange、而在Kakfa中则对应了Kafka中的Topic。

通过RabbitMQ的 Channel 发布消息给我们编写的应用程序消费,而实际上Spring Cloud Stream应用启动的时候,在RabbitMQ的Exchange中也创建了一个名为input的Exchange交换器,由于Binder的隔离作用,应用程序并无法感知它的存在,应用程序只知道自己指向Binder的输入或是输出通道。为了直观的感受发布-订阅模式中,消息是如何被分发到多个订阅者的,我们可以使用快速入门的例子,通过命令行的方式启动两个不同端口的进程。此时,我们在RabbitMQ控制页面的Channels标签页中看到如下图所示的两个消息通道,它们分别绑定了启动的两个应用程序。

我们启动的两个应用程序分别是“订阅者-1”和“订阅者-2”,他们都建立了一条输入通道绑定到同一个Topic(RabbitMQ的Exchange)上。当该Topic中有消息发布进来后,连接到该Topic上的所有订阅者可以收到该消息并根据自身的需求进行消费操作。

相对于点对点队列实现的消息通信来说,Spring Cloud Stream采用的发布-订阅模式可以有效的降低消息生产者与消费者之间的耦合,当我们需要对同一类消息增加一种处理方式时,只需要增加一个应用程序并将输入通道绑定到既有的Topic中就可以实现功能的扩展,而不需要改变原来已经实现的任何内容。

消费组

虽然Spring Cloud Stream通过发布-订阅模式将消息生产者与消费者做了很好的解耦,基于相同主题的消费者可以轻松的进行扩展,但是这些扩展都是针对不同的应用实例而言的,在现实的微服务架构中,我们每一个微服务应用为了实现高可用和负载均衡,实际上都会部署多个实例。很多情况下,消息生产者发送消息给某个具体微服务时,只希望被消费一次,按照上面我们启动两个应用的例子,虽然它们同属一个应用,但是这个消息出现了被重复消费两次的情况。为了解决这个问题,在Spring Cloud Stream中提供了消费组的概念。

如果在同一个主题上的应用需要启动多个实例的时候,我们可以通过spring.cloud.stream.bindings.input.group属性为应用指定一个组名,这样这个应用的多个实例在接收到消息的时候,只会有一个成员真正的收到消息并进行处理。

默认情况下,当我们没有为应用指定消费组的时候,Spring Cloud Stream会为其分配一个独立的匿名消费组。所以,如果同一主题下所有的应用都没有指定消费组的时候,当有消息被发布之后,所有的应用都会对其进行消费,因为它们各自都属于一个独立的组中。大部分情况下,我们在创建Spring Cloud Stream应用的时候,建议最好为其指定一个消费组,以防止对消息的重复处理,除非该行为需要这样做(比如:刷新所有实例的配置等)。

消息分区

通过引入消费组的概念,我们已经能够在多实例的情况下,保障每个消息只被组内一个实例进行消费。通过上面对消费组参数设置后的实验,我们可以观察到,消费组并无法控制消息具体被哪个实例消费。也就是说,对于同一条消息,它多次到达之后可能是由不同的实例进行消费的。但是对于一些业务场景,就需要对于一些具有相同特征的消息每次都可以被同一个消费实例处理,比如:一些用于监控服务,为了统计某段时间内消息生产者发送的报告内容,监控服务需要在自身内容聚合这些数据,那么消息生产者可以为消息增加一个固有的特征ID来进行分区,使得拥有这些ID的消息每次都能被发送到一个特定的实例上实现累计统计的效果,否则这些数据就会分散到各个不同的节点导致监控结果不一致的情况。而分区概念的引入就是为了解决这样的问题:当生产者将消息数据发送给多个消费者实例时,保证拥有共同特征的消息数据始终是由同一个消费者实例接收和处理。

Spring Cloud Stream为分区提供了通用的抽象实现,用来在消息中间件的上层实现分区处理,所以它对于消息中间件自身是否实现了消息分区并不关心,这使得Spring Cloud Stream为不具备分区功能的消息中间件也增加了分区功能扩展。

以上出处:http://blog.didispace.com/spring-cloud-starter-dalston-7-2/

  • 将输入通道 input 的目标设置为 raw-sensor-data 主题
    将spring.cloud.stream.bindings.input.destination设置成raw-sensor-data,程序会从命名为raw-sensor-data的kafka主题中读取数据,或者从一个绑定到raw-sensor-data的rabbitmq交换机的队列中读取数据
spring.cloud.stream.bindings.input.destination=raw-sensor-data

spring.cloud.stream.bindings..destination=:绑定中间件的destination (e.g., the RabbitMQ exchange or Kafka topic)。如果channel绑定的是消费者,那么可以绑定多个destination,用逗号分隔。如果不设置则channel名称会替代这个值。

posted on 2019-09-30 16:42  cag2050  阅读(228)  评论(0编辑  收藏  举报

导航