SpringCloud 笔记(中)

247 阅读11分钟

zuul路由网关

Gateway新一代网关

总路线图

image.png

SpringCloud Gateway 使用的Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架。

image.png

微服务中的网关在哪里:

image.png

image.png

SpringCloud Gateway具有如下特性

  • 基于Spring Framework 5, Project Reactor 和 Spring Boot 2.0 进行构建;
  • 动态路由:能够匹配任何请求属性;
  • 可以对路由指定 Predicate(断言)和 Filter(过滤器);
  • 集成Hystrix的断路器功能;
  • 集成 Spring Cloud 服务发现功能;
  • 易于编写的 Predicate(断言)和 Filter(过滤器);
  • 请求限流功能;
  • 支持路径重写。

SpringCloud Gateway 与 Zuul的区别

  Spring Cloud Gateway 与 Zuul的区别 在SpringCloud Finchley 正式版之前,Spring Cloud 推荐的网关是 Netflix 提供的Zuul:

  • Zuul 1.x,是一个基于阻塞 I/ O 的 API Gateway
  • Zuul 1.x 基于Servlet 2. 5使用阻塞架构它不支持任何长连接(如 WebSocket) Zuul 的设计模式和Nginx较像,每次 I/ O 操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是差别是Nginx 用C++ 实现,Zuul 用 Java 实现,而 JVM 本身会有第一次加载较慢的情况,使得Zuul 的性能相对较差。
  • Zuul 2.x理念更先进,想基于Netty非阻塞和支持长连接,但SpringCloud目前还没有整合。 Zuul 2.x的性能较 Zuul 1.x 有较大提升。在性能方面,根据官方提供的基准测试, Spring Cloud Gateway 的 RPS(每秒请求数)是Zuul 的 1. 6 倍。
  • Spring Cloud Gateway 建立 在 Spring Framework 5、 Project Reactor 和 Spring Boot 2 之上, 使用非阻塞 API。
  • Spring Cloud Gateway 还 支持 WebSocket, 并且与Spring紧密集成拥有更好的开发体验  

三大核心概念

image.png

9527网关做路由映射

image.png 添加网关前:http://localhost:8001/payment/get/31

添加网关后:http://localhost:9527/payment/get/31

通过微服务名实现动态路由

server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
            #- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
            #- Cookie=username,zzyy
            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式

eureka:
  instance:
    hostname: cloud-gateway-service
  client: #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

Predicate的使用

说白了,Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理。

curl的使用

curl相当于一个postman,可以发送get,post请求的命令式窗口 image.png

Filter的使用

image.png

 

Filter是什么?

路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。

Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生  

SpringCloud Config分布式配置中心

   微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。

SpringCloud提供了ConfigServer来解决这个问题,我们每一个微服务自己带着一个application.yml,上百个配置文件的管理...... /(ㄒoㄒ)/~~  

Config服务端配置与测试

测试通过Config微服务是否可以从GitHub上获取配置内容

  • windows下修改hosts文件,增加映射 127.0.0.1 config-3344.com

  • 配置启动微服务3344yml

server:
  port: 3344

spring:
  application:
    name:  cloud-config-center #注册进Eureka服务器的微服务名
  cloud:
    config:
      server:
        git:
          #uri: git@github.com:zzyybs/springcloud-config.git #
#          uri: git@github.com:Zhouyp513/springcloud-config.git #GitHub上面的git仓库名字
          uri: https://github.com/Zhouyp513/springcloud-config.git
        ####搜索目录
          search-paths:
            - springcloud-config
          skip-ssl-validation: true
      ####读取分支
#      label: master
      label: main
##rabbitmq相关配置
#rabbitmq:
#    host: localhost
#    port: 5672
#    username: guest
#    password: guest
#
##服务注册到eureka地址
#eureka:
#  client:
#    service-url:
#      defaultZone: http://localhost:7001/eureka
#
###rabbitmq相关配置,暴露bus刷新配置的端点
#management:
#  endpoints: #暴露bus刷新配置的端点
#    web:
#      exposure:
#        include: 'bus-refresh'

image.png

image.png

Config客户端配置与测试

  applicaiton.yml是用户级的资源配置项 bootstrap.yml是系统级的,优先级更加高   Spring Cloud会创建一个“Bootstrap Context”,作为Spring应用的Application Context的父上下文。初始化的时候,Bootstrap Context负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的Environment

Bootstrap属性有高优先级,默认情况下,它们不会被本地配置覆盖。 Bootstrap contextApplication Context有着不同的约定,所以新增了一个bootstrap.yml文件,保证Bootstrap ContextApplication Context配置的分离。   要将Client模块下的application.yml文件改为bootstrap.yml,这是很关键的, 因为bootstrap.yml是比application.yml先加载的。bootstrap.yml优先级高于application.yml   实现了客户端3355访问SpringCloud Config3344通过GitHub获取配置信息

  • 客户端3355yml
server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    #Config客户端配置
    config:
#      label: master #分支名称
      label: main #分支名称
      name: config #配置文件名称
      profile: dev #读取后缀名称   上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
      uri: http://localhost:3344 #配置中心地址k

##rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
#  rabbitmq:
#    host: localhost
#    port: 5672
#    username: guest
#    password: guest

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

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

image.png

image.png

image.png

SpringCloud Bus 消息总线

广播版的自动刷新

  • 分布式自动刷新配置功能
  • Spring Cloud Bus 配合 Spring Cloud Config 使用可以实现配置的动态刷新。

是什么?

  Spring Cloud Bus 配合 Spring Cloud Config 使用可以实现配置的动态刷新。

Spring Cloud Bus是用来将分布式系统的节点与轻量级消息系统链接起来的框架, 它整合了Java的事件处理机制和消息中间件的功能。 Spring Clud Bus目前支持RabbitMQ和Kafka。  

能干嘛?

Spring Cloud Bus能管理和传播分布式系统间的消息,就像一个分布式执行器,可用于广播状态更改、事件推送等,也可以当作微服务间的通信通道。

什么是总线

在微服务架构的系统中,通常会使用轻量级的消息代理来构建一个共用的消息主题,并让系统中所有微服务实例都连接上来。由于该主题中产生的消息会被所有实例监听和消费,所以称它为消息总线。在总线上的各个实例,都可以方便地广播一些需要让其他连接在该主题上的实例都知道的消息。  

基本原理

ConfigClient实例都监听MQ中同一个topic(默认是springCloudBus)。当一个服务刷新数据的时候,它会把这个信息放入到Topic中,这样其它监听同一Topic的服务就能得到通知,然后去更新自身的配置。   www.bilibili.com/video/av559…  

RabbitMQ环境配置

image.png 安装教程: rabbitmq消息队列的安装(Windows)和使用_代码的更新者的博客-CSDN博客 rabbitmq github.com/rabbitmq/ra…

window环境下安装成功

image.png

SpringCloud Bus动态刷新全局广播

image.png

  • 利用消息总线触发一个客户端/bus/refresh,而刷新所有客户端的配置
  • 利用消息总线触发一个服务端ConfigServer的/bus/refresh端点,而刷新所有客户端的配置 image.png

image.png

image.png

  • 给cloud-config-center-3344配置中心服务端添加消息总线支持,修改yml,添加bus
#rabbitmq相关配置
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
#
#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka
#
##rabbitmq相关配置,暴露bus刷新配置的端点
management:
  endpoints: #暴露bus刷新配置的端点
    web:
      exposure:
        include: 'bus-refresh'
  • 给cloud-config-client-3355客户端添加消息总线支持,3366客户端同理
  #rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

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

一次发送,处处生效

  • 测试 修改github上的配置文件,发送post请求,刷新3344可以获取到最新的配置值,不用重启3355,3366也可以获取到最新的配置值,利用了消息总线的原理,刷新了所以的客户端

SpringCloud Bus动态刷新定点通知

  • 我们这里以刷新运行在3355端口上的config-client为例
curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"
  • 通知所有
curl -X POST "http://localhost:3344/actuator/bus-refresh"

SpringCloud Stream 消息驱动

image.png

image.png

  • 消息驱动之生产者 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: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost: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层调用dao层的数据,在这里,service层调用mq消息接口获取数据

@EnableBinding(Source.class) //定义消息的推送管道
public class MessageProviderImpl implements IMessageProvider
{
    @Resource
    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;
    }
}
  • 消息驱动之消费者 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: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
    instance-id: receive-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);
    }
}

image.png

image.png

image.png

分组消费与持久化

微服务分组后,在消息中间件中获取到消息后可以避免重复消费和持久化,在服务宕机后重新启动还是可以重新获取到消息。

group: atguiguA

image.png

image.png

image.png

SpringCloud Sleuth 分布式请求链路跟踪

image.png