SpringCloud-整体学习(八)Config、Bus、Stream(服务配置和消息交互)

SpringCloud-整体学习(一)SpringCloud简介+版本选择
SpringCloud-整体学习(二)项目初始构建-加公共部分提取
SpringCloud-整体学习(三)Eureka、zookeeper、Consul(注册中心)
SpringCloud-整体学习(四)Ribbon(负载均衡+手写轮询算法)
SpringCloud-整体学习(五)OpenFeign(服务调用)
SpringCloud-整体学习(六)Hystrix(服务降级)
SpringCloud-整体学习(七)GateWay(服务网关)
SpringCloud-整体学习(八)Config、Bus、Stream(服务配置和消息交互)
SpringCloud-整体学习(九)Sleuth(分布式请求链路追踪)
SpringCloud-整体学习(十)SpringCloudAlibaba(注册中心+配置中心)
SpringCloud-整体学习(十一) Sentinel(服务降级)
SpringCloud-整体学习(十二) Seata(分布式事务)

git :
https://github.com/lucine-maker/cloud2020
gitee:
https://gitee.com/lucine_li_tao/springcloud

Config分布式配置中心介绍

在微服务架构中项目模块众多、有需要区分不同的环境
这样application.yml就会变得难以维护 —Config就是用来解决这个问题的。

在这里插入图片描述
文档:
https://docs.spring.io/spring-cloud-config/docs/2.2.6.RELEASE/reference/html/

Config配置总控中心搭建

新建cloud-config-center-3344

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
 </dependency>

yml

server:
    port: 3344

spring:
  application:
    name: cloud-config-center
  cloud:
    config:
      server:
        git:
          #uri: git@github.com:lucine-maker/springcloud-config.git #Github上的git仓库名字
          uri: https://github.com/lucine-maker/springcloud-config.git
          ##搜索目录.这个目录指的是github上的目录
          search-paths:
          - springcloud-config
      ##读取分支
      label: master
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

@EnableConfigServer

hosts 中加入 模拟映射

127.0.0.1 config-3344.com

效果:
在这里插入图片描述

配置命名规则:
在这里插入图片描述

坑:
启动3344:
Authentication is required but no CredentialsProvider has been registered
(因为设置的库是私有库)
解决:
在这里插入图片描述

Config客户端配置与测试

新建cloud-config-client-3355
这里采用 :bootstrap.yml (优先级高于application.yml)
在这里插入图片描述
pom:

 <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

yml

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    #Config客户端配置
    config:
      label: master #分支名称
      name: config #配置文件名称
      profile: dev #读取后缀名称 上诉3个综合就是 master分支上 config-dev.yml
      uri: http://localhost:3344

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

controller

 // 因为config仓库以rest形式暴露,所以所有客户端都可以通过config服务端访问到github上对应的文件信息
    @Value("${config.info}")
    private String configInfo;

    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/configInfo")
    public String getConfigInfo() {
        return "serverPort: " + serverPort + "\t\n\n configInfo" + configInfo;
    }

效果:
在这里插入图片描述
但是目前还有问题,就是当你github已经变更了信息,但是,3355不会立即显示(重启后可以)。
3344可以因为是直接连接的github

坑:
pom (以为只在3344中删除server)
问题

 <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

在这里插入图片描述

Config动态刷新之手动版

解决上面说的不能读取到更新后的数据

pom(必须有)

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

在controller 加入@RefreshScope注解在类上
yml:

##暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: "*"

但是也是不能马上生效,需要进行一个请求的激活。执行下面的命令。
curl -X POST “http://localhost:3355/actuator/refresh”
效果:
在这里插入图片描述

此时,基本可以满足需求了,不用重启服务只要,发一个post请求。
但是如果集群很多 。。 就可能要发5—100个,还是很繁琐需要写脚本发送

Bus消息总线是什么

可以现实:
分布式自动刷新配置功能
SpringCloud Bus 配合 SpringCloud Config 实现自动动态刷新
Bus支持RabbitMQ、Kafka

下面的图是 在第三步的时候 推送给A->由A在继续向后面传递
在这里插入图片描述
下面的是发送给ConfigServer - 然后每个Service 在拉取信息。
在这里插入图片描述

在这里插入图片描述

Bus动态刷新全局广播的设计思想和选型

rabbitMQ 安装就不详细记录了。
新建cloud-config-center-3366
除了端口和3355都一致。

在这里插入图片描述
1、打破了微服务的职责单一性,因为微服务本身是业务模块,它本不应该承担配置的职责
2、破坏了微服务各节点的对等性。
3、有一定的局限性。例如:在微服务迁徙时,他的网络地址常常会发生变化,此时如果想要做的自动刷新,就会增加更多的修改。(不利于维护)

Bus动态刷新全局广播配置实现

在3344、3355、3366
pom中加入Bus

<!--添加消息总线RabbitMQ支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>

yml 中加入RabbitMQ(yml用bootstrap)
注意在spring的yml下。

rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

然后启动7001 - 3344 – 3355 --3366
然后去github更改信息
执行下面的命令
curl -X POST “http://localhost:3344/actuator/bus-refresh”
然后3355、3366就自动更新了。(一次更改、广播通知,处处生效)

Bus动态刷新定点通知

curl -X POST “http://localhost:3344/actuator/bus-refresh/{服务名:端口}”
curl -X POST “http://localhost:3344/actuator/bus-refresh/config-client:3355”

Stream为什么被引入

比方说我们用到了RabbitMQ和Kafka,由于这两个消息中间件的架构上的不同,像RabbitMQ有exchange,kafka有Topic,partitions分区,这些中间件的差异性导致我们实际项目开发给我们造成了一定的困扰,我们如果用了两个消息队列的其中一种,
后面的业务需求,我想往另外一种消息队列进行迁移,这时候无疑就是一个灾难性的,一大堆东西都要重新推倒重新做,因为它跟我们的系统耦合了,这时候springcloud Stream给我们提供了一种解耦合的方式。
一句话:
屏蔽底层的消息中间件,降低切换成本,统一消息编程模型

Stream是什么及Binder介绍

在这里插入图片描述
我的理解:用来交互消息中间件的(binder、binding)。

官网文档:

https://docs.spring.io/spring-cloud-stream/docs/3.1.0-SNAPSHOT/reference/html/
中文:
http://m.wang1314.com/doc/webapp/topic/20971999.html

Stream的设计思想

标准的MQ:
Pub —Message—> QUEUE -----Message---->Sub
在这里插入图片描述
消息通道MessageChannel的子接口SubscribableChannel,由MessageHandler
消息处理器所订阅

引用了之后
在这里插入图片描述
在这里插入图片描述

Stream编码常用注解简介

在这里插入图片描述

Stream消息驱动之生产者

新建cloud-stream-rabbitmq-provider8801
pom:

<dependencies>
        <!--stream-rabbit-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>
        <!--eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>com.lt.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <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.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <!--如果没写版本,从父层面找,找到了就直接用,全局统一-->
        </dependency>
        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</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>
    </dependencies>
</project>

yml

server:
  port: 8801

spring:
  application:
    name: cloud-stream-provider
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitMQ的服务信息
        defaultRabbit: # 表示定义的名称,用于binding的整合
          type: rabbit # 消息中间件类型
          environment: # 设置rabbitMQ的相关环境配置
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
      bindings: # 服务的整合处理
        output: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设为text/plain
          binder: defaultRabbit # 设置要绑定的消息服务的具体设置

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的间隔时间,默认30
    lease-expiration-duration-in-seconds: 5 # 超过5秒间隔,默认90
    instance-id: send-8801.com # 主机名
    prefer-ip-address: true # 显示ip

service:

public interface IMessageProvider {

    public String send();
}

iml:

@EnableBinding(Source.class)
public class MessageProvider implements IMessageProvider {

    @Autowired
    private MessageChannel output;

    @Override
    public String send() {
        String serial = UUID.randomUUID().toString();
        output.send(MessageBuilder.withPayload(serial).build());
        System.out.println("*****serial : "+serial);
        return null;
    }
}

controller

@RestController
public class SendMessageController {

    @Autowired
    private IMessageProvider messageProvider;


    @GetMapping(value = "/sendMessage")
    public String sendMessage(){
        return  messageProvider.send();
    }
}

效果:

当请求8801sendMessage接口的时候在rabbitMQ中 又起伏
在这里插入图片描述

Stream消息驱动之消费者

新建cloud-stream-rabbitmq-consumer8802
pom、启动类和8801一致

yml (基本一致)

server:
  port: 8802

spring:
  application:
    name: cloud-stream-consumer
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitMQ的服务信息
        defaultRabbit: # 表示定义的名称,用于binding的整合
          type: rabbit # 消息中间件类型
          environment: # 设置rabbitMQ的相关环境配置
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
      bindings: # 服务的整合处理
        input: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设为text/plain
          binder: defaultRabbit # 设置要绑定的消息服务的具体设置

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的间隔时间,默认30
    lease-expiration-duration-in-seconds: 5 # 超过5秒间隔,默认90
    instance-id: send-8802.com # 主机名
    prefer-ip-address: true # 显示ip

controller:

@Component
@EnableBinding(Sink.class)
public class ReceiveMessageListenerController {

    @Value("${server.port}")
    private  String  serverPort;

    @StreamListener(Sink.INPUT)
    public void input(Message<String> message){
        System.out.println("消费者1号,---->接收到的消息:"+message.getPayload()+"\t port:"+serverPort);
    }

}

效果:

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

Stream之消息重复消费

新建cloud-stream-rabbitmq-consumer8803
基本和8802一致(就不记录了)

目前环境:
在这里插入图片描述

此时8801发送一个消息 会有重复消费现象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Stream之group解决消息重复消费

故障问题:一个订单重复消费
导致原因:默认的分组是不一致的,组流水号不一致,被认为是不同组,可以消费

解决方案:
自定义分组- 到同一个组中(发生竞争关系-就会只有一个可以消费)

修改yml
在这里插入图片描述
就完成了。

Stream之消息持久化

一句话 :group 分组属性,加上可以防止消息丢失

SpringCloud-整体学习(九)Sleuth(分布式请求链路追踪)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值