SpringCloud消息驱动:Stream(MQ客户端要开启)

1. Spring Cloud Stream(屏蔽多个消息中间件差异,用Strem整合中间件发送消息)

现在一个很项目可能分为三部分:
			前端--->后端---->大数据
			而后端开发使用消息中间件,可能会使用RabbitMq
			而大数据开发,一般都是使用Kafka,
			那么一个项目中有多个消息中间件,对于程序员,因为人员都不友好

而Spring Cloud Stream就类似jpa,屏蔽底层消息中间件的差异,程序员主要操作Spring Cloud Stream即可

不需要管底层是kafka还是rabbitMq
在这里插入图片描述

1.1 什么是Spring Cloud Stream

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2 Spring Cloud Stream是怎么屏蔽底层差异的

在这里插入图片描述
绑定器:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3 Spring Cloud Streamd 通信模式

在这里插入图片描述
在这里插入图片描述

1.31 Spring Cloud Stream的业务流程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
类似flume中的channel,source,sink 估计是借鉴(抄袭)的

  • source用于从外界获取数据(发送到Channel通道,要发送到mq的数据),类似SpringCloudStream的生产者
  • channel类似SpringCloudStream中的中间件,即kafka的partition分区或rabbitMQ的queue队列,用于存放source接收到的数据,或者是存放binder拉取的数据 (SpringCloudStream存储消息
  • Sink用于从Channel通道获取数据,然后外界消费者从Sink获取数据(SpringCloudStream的消费者
  • Binder是一个绑定器,用于动态获取不同类型的消息中间件(比如微服务存在kafka、RabbitMQ两种消息中间件,那么为了是两种消息类型一致,需要一个绑定器去实现类型的统一,而Stream中Binder绑定器就可以)
1.32 常用注解和api

在这里插入图片描述

2. SpringCloudStream案例演示

屏蔽多个消息中间件差异,用Strem整合中间件发送消息,代码不用消息中间件的API(如RabbitMQ、Kafka等),而是直接使用Stream的一套API去实现消息中间件的使用(生产者、消息队列、消费者)

为了演示Stream,我们需要再创建3个子模块,分别是cloud-stream-rabbitmq-provider8801,cloud-stream-rabbitmq-consumer8802,cloud-stream-rabbitmq-consumer8803,另外,需要把RabbitMQ安装并启动.
在这里插入图片描述

2.1 创建生产者8801

(1)pom.xml

添加了Spring cloud stream和rabbitMQ的整合spring-cloud-starter-stream-rabbit

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

(2)8801yaml配置文件

注意:8801生产者使用的是output通道。
在这里插入图片描述
在这里插入图片描述
(3)8801主启动类
在这里插入图片描述
(4)service和实现类

service定义发送消息
在这里插入图片描述
接口实现类

这里是消息中间件的绑定使用,不用像之前的业务一样使用@service注解,不用调用Dao数据层,直接引入Channel消息管道

package com.atguigu.springcloud.service.impl;
//这里使用@EnableBinding(Source.class),这是Stream里的注解,定义一个消息推送管道,不需要使用@Service注解
@EnableBinding(Source.class)
public class MessageProviderImpl implements IMessageProvider {
    @Resource
    private MessageChannel output;// 定义消息发送管道Channel,名称必须是output,否则会报错
 
    @Override
    public String send() {
        String uuid = UUID.randomUUID().toString();
        output.send(MessageBuilder.withPayload(uuid).build());
        System.out.println("uuid=" + uuid);
        return null;
    }
}

这里,就会调用send方法,将消息发送给channel,

然后channel将消费发送给binder,然后发送到rabbitmq中

(5)controller
在这里插入图片描述
(6)可以测试

启动rabbitmq

启动7001,8801

​ 确定8801后,会在rabbitmq中创建一个Exchange,就是我们配置文件yaml中配置的destination:studyExchange

访问8801的/sendMessage

2.2 创建消费者8802

(1)8802 pom.xml

和8801生产者一样

(2)8802 yaml配置文件

注意这里通道名称改成input,之前cloud-stream-rabbitmq-provider8801生产者使用的是output。

input就表示,当前服务是一个消费者,需要消费消息,下面就是指定消费哪个Exchange中的消息
在这里插入图片描述
在这里插入图片描述
(3)8802主启动类
在这里插入图片描述
(4)8802业务类(消费数据)

这里没有service,直接定义controller层,从消息队列Channel拿数据

在这里插入图片描述
生产者发送消息时,使用send方法发送,send方法发送的是一个个Message,里面封装了数据

(5)测试

启动7001.8801.8802

此时使用生产者生产消息
在这里插入图片描述
可以看到,消费者已经接收到消息了

2.3 创建消费者8803

创建8803,

与8802创建一模一样,就不写了

创建8803主要是为了演示重复消费等问题


在这里插入图片描述

2.4 重复消费问题(多个消费者配置成一个组)

此时启动7001.8801.8802.8803

此时生产者生产一条消息

但是此时查询消费者,发现8802,8803都消费到了同一条数据
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.4.1 自定义分组

在Stream中,处于同一个group的多个消费者是竞争关系,一条消息只能消费一次,不存在重复消费。

处于不同group组的消费者都可以拿到消息,是可以重复消费的

通过查看RabbitMQ的管理后台,点击exchange标签,找到我们指定的exchange,发现Bindings里面有两个组,可以重复消费,所以出现了重复消费问题

所以,解决重复消费的办法也很简单,自定义配置分组分为同一个组group,解决重复消费问题

(1)修改8802,8803的yaml配置文件,添加分组group
在这里插入图片描述
在这里插入图片描述
现在将8802,8803都分到了A组

然后去重启02,03

然后此时生产者生产两条消息
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,每人只消费了一条消息,并且没有重复消费,就是轮循机制,每次生产者发送消息,只有一个消费者可以获得。

2.5 持久化问题

就是当服务挂了,怎么消费没有消费的数据??

这里,先将8802移除A组,

​ 然后将02,03服务关闭

此时生产者开启,发送3条消息

​ 此时重启02,03

​ 可以看到,当02退出group:atguiguA组后,它就获取不到在它宕机的时间段内的数据

​ 但是03重启后,直接获取到了宕机期间它没有消费的数据,并且消费了,实现了持久化。

总结:
也就是,当我们没有配置分组时,会出现消息漏消费的问题

​ 而配置分组后,即使我们宕机了,我们也可以自动获取未消费的数据,这就是持久化消费

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值