Spring Cloud Stream:基于事件(消息)驱动的微服务框架

概念和作用

Spring Cloud Stream是Spring Integration和Spring Boot的整合,用于开发数据集成的微服务

具备Spring Integration和Spring Boot的特征,其中突出卖点如下:

1:专注性:应用现代微服务架构模式,包括通过消息传递组合,独立构建,测试,迭代和部署以数据为中心的应用程序,而不需要其他业务应用程序的繁琐配置。
2:实时性和异步性:将以业务同步处理为职责的程序与以异步处理事件为中心的思维区分开。 事件可以表示及时产生的数据,消费者应用程序可以在不知道其来源或生产者身份的情况下对数据进行异步处理。

Stream App 应用架构

Spring Cloud Stream:基于事件(消息)驱动的微服务框架_第1张图片

app需要使用binder链接外部的消息中间件middleware。stream对binder进行抽象后,可利用不同的binder实现来整合不同的消息中间件,常见的有kafka和rabbitMQ。

在stream中,定义了三个通道channel,输出通道(outputs)Source、输入通道(inputs)Sink、输入输出通道(转发作用)Processor。用户也可以自定以通道,在接口中对方法使用@Sink和@Source注解即可。

app core:开发者可利用stream特性,对消息进行接收、处理和转发,和具体的消息中间件无关,主要得益与其抽象的channel。还可以利用配置文件,进行分区和分组等配置

快速开始

源码地址

启动项目结构如下:
Spring Cloud Stream:基于事件(消息)驱动的微服务框架_第2张图片

  • 启动项目前的准备
  1. 熟悉kafka和zookeeper集成的消息中间件
  2. 熟悉spring boot的项目结构、配置文件、注解使用
  3. 将zookeeper和kafka启动成功。(百度kafka和zookeeper集成)
  • 配置文件的修改
    Spring Cloud Stream:基于事件(消息)驱动的微服务框架_第3张图片
    spring.cloud.stream.kafka.binder.brokers=localhost:9092
    spring.cloud.stream.kafka.binder.zk-nodes=localhost:2181
    

需要将三个消费者和一个生产者的配置文件中的以上参数修改为本机启动的zookeepe端口和kafka端口

  • 生产者和消费者的启动配置

    /**启动配置,只需修改启动参数数组里的启动端口和启动文件中间关键词,就可同时启动多个不同的客户端
    */
    public static void main(String[] args) {
    	String[] args2 = new String[]{"--server.port=8802","--spring.profiles.active=ain2"};
    	SpringApplication.run(Sink2Application.class, args2);
    }
    

    分别修改如上的启动端口参数--server.port和配置文件关键字参数--spring.profiles.active,分别启动三个消费者和一个生产者

  • 验证是否启动成功

    localhost:8800/send/测试消息
    

    在浏览器中,或者用curl命令,运行以下url,连续运行三次,就会在每一个消费者客户端中看到如下输出:

    Received: 测试消息
    

    至此,该快速启动项目演示成功。

    在此过程中,最可能出现问题的地方是在启动zookeeper和kafka集成的时候,会出现kafka启动不起来。这个时候需要删除掉zoo.conf中配置的datadir目录中的version-2文件夹中的所有文件,再重新启动zookeeper和kafka即可。

SC Stream App编程

  • 生产者应用启动类:包含模拟事件触发的接口
@SpringBootApplication
@RestController
public class SourceApplication {	
	@Autowired
	private SendService service;
	
	@RequestMapping(value = "/send/{msg}", method = RequestMethod.GET)
	public void send(@PathVariable("msg") String msg){
		service.sendMessage(msg);
	}
	public static void main(String[] args) {
		String[] args2 = new String[]{"--server.port=8800","--spring.profiles.active=aout"};
		SpringApplication.run(SourceApplication.class, args2);
	}
}

启动生产者应用后,在浏览器中输入模拟事件触发接口地址。后台接收到消息后,会调用sendService,来将消息发送到输出通道中。

@EnableBinding(Source.class)
public class SendService {
	@Autowired
	private Source source;
	public void sendMessage(String msg) {
		try {
			source.output().send(MessageBuilder.withPayload(msg).build());	
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

sendService中,需要使用@EnableBinding注解,来定义该服务为输出通道Source。在服务中,注入stream自定义的输出通道Source,通过该通道将消息发送到消息中间件中。
此时,一个简单的生产者模型编写完成。

  • 消费者应用:输入通道接受消息
@EnableBinding(Sink.class)
public class MsgSink {
	@StreamListener(Sink.INPUT)
	public void messageSink(Object payload) {
		System.out.println("Received: " + payload);
	}
}

需要在该服务中添加@EnableBinding,绑定输入通道Sink。并在其方法messageSink中,添加注解@StreamListener。该注解为实时监听消息中间件中输出通道输出的消息(需要结合topic-group-partition三个概念进行消息的获取)。Stream也支持轮询监听,这里不表,如有需要,可查询末尾的参考文档。接受到消息后,即可对该消息进行消费处理。

  • 属性配置
    • 消费者关键配置属性
      	#启用消息分区
      	spring.cloud.stream.bindings.input.consumer.partitioned=true
      	#处理分区数据的应用实例总数
      	spring.cloud.stream.instanceCount=3
      	#该实例在整个分区处理实例中的标识,本实例中因为0-2
      	spring.cloud.stream.instanceIndex=0
      	
      	#binder绑定的消息中间件的接口
      	spring.cloud.stream.kafka.binder.brokers=192.168.20.88:9092
      	#消息中间件用于节点状态管理的zookeeper的接口
      	spring.cloud.stream.kafka.binder.zk-nodes=192.168.20.88:2181
      	
      	#定义消费者接受的topic
      	spring.cloud.stream.bindings.input.destination=wsh-topic-01
      	#定义消费者组
      	spring.cloud.stream.bindings.input.group=s3
      
    • 生产者配置属性
      	#生产者实例数和标识
      	spring.cloud.stream.instanceCount=1
      	spring.cloud.stream.instanceIndex=0
      	
      	#生产者的消息分区数和分区规则
      	spring.cloud.stream.bindings.output.producer.partitionCount=1
      	spring.cloud.stream.bindings.output.producer.partitionKeyExtractorName=source
      

在配置生产者和消费者的属性时,有三个概念topicgrouppartition

topic:配置属性为destination。在消费者和生产者实例中指定topic,即可实现发布订阅。

group:消费者分组。给同一个应用的多个实例,分配到同一个组,那么这几个实例就形成了竞争关系。发送到该组的每条消息,只会让一个消费者实例接受到。同时即使该组内的应用实例挂掉了,那么在实例重启后,任然会继续接受挂掉期间错过的消息。

partition:消息分区。stream的分区和其他中间件的消息分区,有异曲同工之妙。同时将消息和实例进行分区,分区后对应的消息到对应的实例中进行处理。

参考资料

  • 参考文档:https://docs.spring.io/spring-cloud-stream/docs/Fishtown.M3/reference/htmlsingle/
  • 源代码:https://github.com/seagrape/SpringCloudStream

  91Code-就要编码

Spring Cloud Stream:基于事件(消息)驱动的微服务框架_第4张图片

你可能感兴趣的:(Spring Cloud Stream:基于事件(消息)驱动的微服务框架)