作者:🍧dabing(王甜甜)

视频:尚硅谷 2020 周阳 SpringCloud(H 版 & alibaba)

官方文档:https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/#features

github 上代码地址:https://github.com/dabing85/springcloud2020

gitee 上代码地址:https://gitee.com/hedabing/springcloud2020

笔记来自视频,只不过再加些自己练习过程的笔记。

# 十一、 Gateway 新一代网关

# 1 - 概述简介

# 1.1. 官网

https://docs.spring.io/spring-cloud-gateway/docs/2.2.6.RELEASE/reference/html/ img

# 1.2. 是什么

Cloud 全家桶中有个很重要的组件就是网关,在 1.x 版本中都是采用的 Zuul 网关 https://github.com/Netflix/zuul/wiki

但在 2.x 版本中,zuul 的升级一直跳票,SpringCloud 最后自己研发了一个网关代替 Zull,那就是 SpringCloud Geteway;

# 1.2.1. 一句话:Geteway 是原 Zuul1.x 版的替代

img

# 1.2.2. 概述

Gateway 是在 spring 生态系统之上构建的 API 网关服务,基于 Spring5,SpringBoot2 和 Project Reactor 等技术。

Gateway 旨在提供一种简单而有效的方式来对 API 进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试

SpringCloud Gateway 是 SpringCloud 的一个全新项目,基于 Spring5.X+SpringBoot2.X 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

为了提升网关的性能,SpringCloud Gatway 是基于 WebFlux 框架实现的,而 WebFlux 框架底层则使用了高性能的 Reactor 模式通讯框架 Netty

SpringCloud Gateway 的目标提供统一的路由方式且基于 Filter 链的方式提供了网关基本的功能,例如:安全、监控 / 指标、和限流

# 1.2.3. 一句话

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

源码架构

img

# 1.3. 能干嘛

🌸反向代理

🌸 鉴权

🌸 流量控制

🌸 熔断

🌸 日志监控

🌸。。。。。。

# 1.4. 微服务架构中网关在哪里

img

# 1.5 有 Zuul 了怎么又出来 gateway

image-20221026102617179

# 1. 我们为什么选择 Gateway?

  1. netflix 不太靠谱,zuul2.0 一直跳票,迟迟不发布

image-20221026102753341

  1. SpringCloud Gateway 具有如下特性

image-20221026102807391

  1. SpringCloud Gateway 与 Zuul 的区别

image-20221026102836753

# 2. Zuul1.x 模型

image-20221026102955311

image-20221026103006485

# 3. Gateway 模型

WebFlux 是什么?官网:https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#spring-webflux

image-20221026103044408

# 2 - 三大核心概念

# 2.1. Route (路由)

路由是构建网关的基本模块,它由 ID,目标 URI,一系列的断言和过滤器组成,如果断言为 true 则匹配该路由

# 2.2. Predicate(断言)

参考的是 java8 的 java.util.function.Predicate

开发人员可以匹配 HTTP 请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由

# 2.3. Filter (过滤)

指的是 Spring 框架中 GatewayFilter 的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。

# 2.4. 总体

img

Web 请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制。

Predicate 就是我们的匹配条件: 而 Filter,就是可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标 uri, 就可以实现一个具体的路由了。

# 3 - Gateway 工作流程

# 3.1. 官网总结

https://docs.spring.io/spring-cloud-gateway/docs/2.2.6.RELEASE/reference/html/

img

img

客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求匹配的路由,将其发送到 Gateway Web Handler.

Handler 再通过指定的过滤器链来将请求发送给我们实际的服务执行业务逻辑,然后返回。

过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后 (“post”) 执行业务逻辑。

Filter 在 **"pre" 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在 "post" 类型 ** 的过滤器中可以做响应内容、响应头的修改,日志的输出,流量控制等有着非常重要的作用

# 3.2. 核心逻辑:路由转发 + 执行过滤器链

# 4 - 入门配置

# 4.1. 新建 Module:cloud-gateway-gateway9527

# 4.2. POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>Cloud2020</artifactId>
        <groupId>com.dabing</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloud-gateway-gateway9527</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- 新增 gateway,不需要引入 web 和 actuator 模块 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>com.dabing</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</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>

# 4.3. YML

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
      register-with-eureka: true
      fetch-registry: true
      service-url:
          defaultZone: http://localhost:7001/eureka

# 8.4.4. 业务类

# 4.5. 主启动类

package com.dabing.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
    public static void main(String[] args) {
        SpringApplication.run(GateWayMain9527.class,args);
    }
}

# 4.6. 9527 网关如何做路由映射呢???

我们目前不想暴露 8001 端口,希望在 8001 外面套一层 9527

# 4.7. YML 新增网关配置

在 yml 上添加上中间路由那段

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
       - id: payment_routh #路由的 ID,没有固定规则但要求唯一,建议配合服务名
         uri: http://localhost:8001   #匹配后提供服务的路由地址
         predicates:
           - Path=/payment/get/**   #断言,路径相匹配的进行路由
 
       - id: payment_routh2
         uri: http://localhost:8001
         predicates:
           - Path=/payment/lb/**   #断言,路径相匹配的进行路由
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://localhost:7001/eureka

# 4.8. 测试

启动 7001:cloud-eureka-server7001

启动 8001:cloud-provider-payment8001

启动 9527 网关:cloud-gateway-gateway9527

访问说明

img

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

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

image-20221027093644328

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

默认情况下 Gateway 会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能

# 5.1. 启动

一个 eureka7001 + 两个服务提供者 8001/8002

# 5.2. POM

# 5.3. YML

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh #路由的 ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001   #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service 
          #进行动态路由实现负载均衡时使用的协议是 lb 协议,地址是反向代理的服务的名称
          predicates:
            - Path=/payment/get/**   #断言,路径相匹配的进行路由
 
        - id: payment_routh2
          #uri: http://localhost:8001   #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service
          predicates:
            - Path=/payment/lb/**   #断言,路径相匹配的进行路由
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://localhost:7001/eureka

需要注意的是 uri 的协议为 lb,表示启用 Gateway 的负载均衡功能。

lb://serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri

# 5.4. 测试

http://localhost:9527/payment/lb

8001/8002 两个端口切换

# 6 - Predicate 的使用

# 6.1. 是什么

启动我们的 gatewat9527,查看启动日志

这里我们只使用到了 Path

img

# 6.2. Route Predicate Factories 这个是什么东东?

img

Spring Cloud Gateway 将路由匹配作为 Spring WebFlux HandlerMapper 基础框架的一部分。

Spring Cloud Gateway 包括许多内置的 Route Predicate 工厂。所有这些 Predicate 都与 HTTP 请求的不同属性匹配。多个 Route Predicate 工厂可以进行组合

Spring Cloud Gateway 创建 Route 对象时,使用 RoutePredicateFactory 创建 Predicate 对象,Predicate 对象可以赋值给 Route。Spring Cloud Gateway 包含许

多内置的 Route Predicate Factories。

所有这些谓词都匹配 HTTP 请求的不同属性。多种谓词工厂可以组合,并通过 逻辑and

# 6.3. 常用的 Route Predicate

# 1.After Route Predicate

img

ZonedDateTime zonedDateTime = ZonedDateTime.now();

System.out.println(zonedDateTime);

需要到这个时间后执行才通过,即没到时间执行会操作。

- After=2022-11-08T10:59:34.102+08:00[Asia/Shanghai]

image-20221027100516243

# 2.Before Route Predicate

需在这个时间前执行才能通过。

- Before=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]

# 3.Between Route Predicate

在该时间段请求才能通过

- Between=2020-03-08T10:59:34.102+08:00[Asia/Shanghai],2020-03-08T10:59:34.102+08:00[Asia/Shanghai]

# 4.Cookie Route Predicate

img

- Cookie=username,atguigu    #并且 Cookie 是 username=atguigu 才能访问

可使用 curl 进行测试,curl 下载地址:https://curl.haxx.se/download.html

不带 cookies 访问

img

带上 cookies 访问

img

加入 curl 返回中文乱码问题(帖子): https://blog.csdn.net/leedee/article/details/82685636

# 5.Header Route Predicate

img

- Header=X-Request-Id, \d+   #请求头中要有 X-Request-Id 属性并且值为整数的正则表达式

img

# 6.Host Route Predicate

- Host=**.atguigu.com

# 7.Method Route Predicate

- Method=GET

# 8.Path Route Predicate

刚开始使用的就是 Path

- Path=/payment/get/**   #断言,路径相匹配的进行路由

# 9. Query Route Predicate

-  Query=username, \d+ #要有参数名称并且是正整数才能路由

# 10. 小总结

  • All
server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh #路由的 ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001   #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service
          predicates:
            - Path=/payment/get/**   #断言,路径相匹配的进行路由
        - id: payment_routh2
          #uri: http://localhost:8001   #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service
          predicates:
            - Path=/payment/lb/**   #断言,路径相匹配的进行路由
            #- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
            #- Cookie=username,zhangshuai #并且 Cookie 是 username=zhangshuai 才能访问
            #- Header=X-Request-Id, \d+ #请求头中要有 X-Request-Id 属性并且值为整数的正则表达式
            #- Host=**.atguigu.com
            #- Method=GET
            #- Query=username, \d+ #要有参数名称并且是正整数才能路由
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://localhost:7001/eureka

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

# 7 - Filter 的使用

# 7.1. 是什么

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

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

# 7.2. Spring Cloud Gateway 的 Filter

# 1. 生命周期,Only Two

pre : 在业务逻辑之前

post :在业务逻辑之后

# 2. 种类,Only Two

https://docs.spring.io/spring-cloud-gateway/docs/2.2.6.RELEASE/reference/html/

# 1) GatewayFilter(31 种之多)

img

# 2) GlobalFilter

image-20221020194105151

# 7.3. 常用的 GatewayFilter

AddRequestParameter

YML,这个 yaml 的缩进有点问题哈~~

img

省略

# 7.4. 自定义过滤器

# 1. 自定义全局 GlobalFilter

两个主要接口介绍

impiemerts GlobalFilter ,Ordered

# 2. 能干嘛

全局日志记录

统一网关鉴权

。。。。。。

# 3. 案例代码

package com.dabing.springcloud.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter,Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("*********come in MyLogGateWayFilter: "+new Date());
        String uname = exchange.getRequest().getQueryParams().getFirst("username");
        if(StringUtils.isEmpty(uname)){
            log.info("*****用户名为Null 非法用户,(┬_┬)");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
    @Override
    public int getOrder() {
        return 0;
    }
}

# 4. 测试

启动

img

正确:http://localhost:9527/payment/get/1?username=z3

错误:http://localhost:9527/payment/get/1?uname=z3

错误时打印:

image-20221027145314856

页面:

image-20221027145409945

中间有 springcloud config、springcloud bus、springcloud Stream 三个还没学,后期不,挖个坑,后面填!!

image-20221027160318310

下面只是对阳哥视频做笔记,未做练习,后期补坑~~~

# 十二、SpringCloud config 分布式配置中心

# 1 - 概述

# 1.1. 分布式系统面临的问题–配置问题

image-20221027161913074

# 1.2 是什么?

是什么
Springcloud config 为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供一个中心化的外部配置。

怎么玩
Springcloud Config 分为服务端和客户端两部分。

服务端 也称分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并未客户端提供获取配置信息,加密、解密信息等访问接口。

客户端 则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息配置服务器默认采用 gt 来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过 gt 客户端工具来方便的管理和访问配置内容

# 1.3 能干嘛?

image-20221027162403527

# 1.4 与 GitHub 整合配置

由于 SpringCloud Config 默认使用 Git 来存储配置文件(也有其它方式,比如支持 SVN 和本地文件),
但最推荐的还是 Git, 而且使用的是 http/https 访问的形式

# 2 - Config 服务端配置与测试

image-20221027212001019

# 2.1 建仓库,再本地初始化

image-20221027210117101

# 2.2 module

新建 Module 模块 cloud-config-center-3344 它即为 Cloud 的配置中心模块 cloudCofing Center

# 2.3 POM 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>Cloud2020</artifactId>
        <groupId>com.dabing.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloud-config-center-3344</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.dabing</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

# 2.4 YML

server:
  port: 3344
eureka:
  client:
    service-url:
      defaultZone: http://www.eureka7001.com:7001/eureka/
spring:
  application:
    name: cloud-config-center
  cloud:
    config:
      server:
        git:
          uri:
          search-paths:
            - springcloud-config
      label: master

# 2.5 主启动类

创建主启动类 ConfigCenterMain3344,添加注解 @EnableConfigServer

# 2.6 测试

修改 host 文件, C:\Windows\System32\drivers\etc 路径下,添加映射:127.0.0.1 config-3344.com

启动微服务 3344,测试是否可以从 GitHub 上获取配置信息,http://config-3344.com:3344/master/config-dev.yml

# 3 - Config 客户端配置与测试

image-20221027212408576

  1. 建 module - 新建 cloud-config-center-3355
  2. pom - spring-cloud-starter-config
  3. bootstrap.yml - config 信息
  4. 主启动类
  5. 业务类 - 用 controller 读取一下配置信息测试即可

POM.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.dabing</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
</dependencies>

bootstrap.yml

是什么东东?

image-20221027212738495

server:
  port: 3355
spring:
  application:
    name: config-client
  cloud:
    config:
      label: master  #分支名称
      name: config  #配置文件名称
      profile: dev  #读取后缀名称   上述三个综合 http://localhost:3344/master/config-dev.yml
      uri: http://localhost:3344  #配置中心的地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

# 4 - Config 客户端只动态刷新

image-20221027213046881

修改 YML, 暴露监控接口:

management:
  endpoints:
    web:
      exposure:
        include: "*"

# 十三、 SpringCloud Bus 消息总线

image-20221027222629850

# 1 - 概述

上一讲解的加深和扩充,一言以蔽之,分布式自动刷新配置功能,SpringCloud Bus 配合 Springcloud Config 使用可以实现配置的动态刷新

是什么?

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

image-20221027224017854

能干嘛?

image-20221027224100330

为何被称为总线?

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

基本原理:
ConfigClient 实例都监听 MQ 中的同一个 topic(默认是 SpringcloudBus)。当一个服务刷新数据的时候,它会把这个信息放入到 topic 中,这样其它监听同一个 topic 的服务就能得到通知,然后去更新自身的配置。

http://www.bilibili.com/video/av55976700?from=searche&seid=15010075915728605208

# 2 - RabbitMQ 环境配置

我安装过了,安装再服务器了。客户端端口 15672。

RabbitMQ 也有 md 的笔记,但是是尚硅谷的,我只不过是将 word 改成了 md 而已,有需要的人可以管我要。

# 3 - SpringCloud Bus 动态刷新全局广播

image-20221027230115460

必须先具备良好的 RabbitMQ 环境

演示广播效果增加复杂度,再以 3355 为模板制作一个 3366

  1. 新建 module - cloud-config-client-3366 (以 3355 为模板)

  2. pom.xml - spring-cloud-starter-config

  3. bootstrap.yml - config 信息

  4. 主启动类

  5. 业务类

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </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.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.atguigu.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
</dependencies>

bootstrap.yml

server:
  port: 3366
spring:
  application:
    name: config-client
  cloud:
    config:
      label: master  #分支名称
      name: config  #配置文件名称
      profile: dev  #读取后缀名称   上述三个综合 http://localhost:3344/master/config-dev.yml
      uri: http://localhost:3344  #配置中心的地址
eureka:
  client:
    service-url:
      defaultZone: http://www.eureka7001.com:7001/eureka/
management:
  endpoints:
    web:
      exposure:
        include: "*"

主启动类

package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ConfigClientMain3366 {
    public static void main(String[] args) {
        SpringApplication.run(ConfigClientMain3366.class,args);
    }
}

controller

package com.atguigu.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope
public class ConfigController {
    @Value("${info.age}")
    private String infoAge;
    @RequestMapping("/getServerPort")
    public String getServerPort() {
        return infoAge;
    }
}

# 3.2 设计思想

  1. 利用消息总线触发一个客户端 /bus/refresh, 而刷新所有客户端的配置

image-20221029222915526

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

image-20221029222927617

图二的架构显然更加合适,图一不适合的原因如下

1、打破了微服务的职责单一性,因为微服务本身是业务模块,它不应该承担配置刷新的职责

2、打破了微服务各个节点的对等性

3、有一定的局限性。例如:微服务在迁移时,它的网络地址常常会发生变化,此时如果想要做到自动刷新,那就回增加更多的的修改

# 3.3 给 3344 配置中心服务端添加消息总线支持

pom.xml

<!-- 增加 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

yml:

server:
  port: 3344
eureka:
  client:
    service-url:
      defaultZone: http://www.eureka7001.com:7001/eureka/
  instance:
    ip-address: 127.0.0.1
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 1
    lease-expiration-duration-in-seconds: 2
spring:
  application:
    name: cloud-config-center
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/cunjinFS/springcloud-config.git
          search-paths:
            - springcloud-config
          username: 630278734@qq.com
          password: jin960106
      label: master
  rabbitmq:
    host: localhost
    port: 5672s
    username: guest
    password: guest
management:
  endpoints:
    web:
      exposure:
        include: 'bus-refresh'

# 3.4 给 3355 配置中心服务端添加消息总线支持

pom.xml

增加
 
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

yml:

server:
  port: 3355
spring:
  application:
    name: config-client
  cloud:
    config:
      label: master  #分支名称
      name: config  #配置 a 文件名称
      profile: dev  #读取后缀名称   上述三个综合 http://localhost:3344/master/config-dev.yml
      uri: http://localhost:3344  #配置中心的地址
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    
eureka:
  client:
    service-url:
      defaultZone: http://www.eureka7001.com:7001/eureka/
management:
  endpoints:
    web:
      exposure:
        include: "*"

# 3.5 给 3366 配置中心服务端添加消息总线支持

pom.xml

增加
 
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

yaml

server:
  port: 3366
spring:
  application:
    name: config-client
  cloud:
    config:
      label: master  #分支名称
      name: config  #配置文件名称
      profile: dev  #读取后缀名称   上述三个综合 http://localhost:3344/master/config-dev.yml
      uri: http://localhost:3344  #配置中心的地址
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    
eureka:
  client:
    service-url:
      defaultZone: http://www.eureka7001.com:7001/eureka/
management:
  endpoints:
    web:
      exposure:
        include: "*"

# 3.6 测试:

image-20221029223619477

# 4 - Springcloud Bus 动态刷新定点通知

image-20221029223729157

image-20221029223814539

# 十四、SpringCloud Stream 消息驱动

image-20221029223853391

# 十五、 SpringCloud Sleuth 分布式链路请求跟踪

# 1 - 概述

# 1.1. 为什么会出现这个技术?需要解决哪些问题?

问题

在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,每一个前端请求都会形成一个复杂的分布式服务调用链路,链路中的任何一环出现高延时或错误都会引起整个请求最后的失败。

img

# 1.2. 是什么

Spring Cloud Sleuth 提供了一套完整的服务跟踪的解决方案

在分布式系统中提供追踪解决方案并且兼容支持了 zipkin (负责展现)

https://docs.spring.io/spring-cloud-sleuth/docs/2.2.6.RELEASE/reference/html/

https://zipkin.io/

img

img

# 2 - 搭建链路监控步骤

Spring Cloud Sleuth 和 OpenZipkin(也称为 Zipkin)集成。Zipkin 是一个分布式跟踪平台,可用于跟踪跨多个服务调用的事务。Zipkin 允许开发人员以图形方式查看事务占用的时间量,并分解在调用中涉及的每个微服务所用的时间。在微服务架构中,Zipkin 是识别性能问题的宝贵工具。

建立 Spring Cloud Sleuth 和 Zipkin 涉及 4 项操作:

  • 将 Spring Cloud Sleuth 和 Zipkin JAR 文件添加到捕获跟踪数据的服务中;

  • 在每个服务中配置 Spring 属性以指向收集跟踪数据的 Zipkin 服务器;

  • 安装和配置 Zipkin 服务器以收集数据;

  • 定义每个客户端所使用的采样策略,便于向 Zipkin 发送跟踪信息。

# 2.1. zipkin

下载:https://github.com/openzipkin/zipkin

img

curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar

img

运行控制台:

http://localhost:9411/zipkin/

img

术语

完整的调用链路

表示一请求链路,一条链路通过 Trace Id 唯一标识,Span 标识发起的请求信息,各 span 通过 parent id 关联起来。

img

上图 what

一条链路通过 Trace Id 唯一标识,Span 标识发起的请求信息,各 span 通过 parent id 关联起来。

img

整个链路的依赖关系如下:

img

名词解释

Trace : 类似于树结构的 Span 集合,表示一条调用链路,存在唯一标识

span : 表示调用链路来源,通俗的理解 span 就是一次请求信息

# 2.2. 服务提供者

# 1. 修改:cloud-provider-payment8001

# 2. POM

<!-- 包含了 sleuth+zipkin-->
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

# 3. YML

仅添加上 zipkin 的配置即可。

#微服务建议一定要写服务端口号和微服务名称
server:
  #端口号
  port: 8001
spring:
  application:
    #微服务名称
    name: cloud-payment-service
  #数据库配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    #mysql5.x 的没有 cj
    driver-class-name: com.mysql.cj.jdbc.Driver
    #记得先创建数据库
    url: jdbc:mysql://localhost:3306/cloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
  zipkin:
    base-url: http://localhost:9411
    sleuth:
      sampler:
        #采样率值介于 0~1 之间,1 表示全部采样
        probability: 1
#mybatis 配置
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.dabing.springcloud.entities  #所有 Entity 别名类所在包
#eureka 配置
eureka:
  client:
    register-with-eureka: true  #true 表示自己要注册到服务中心
    fetch-registry: true        #true 表示自己要去检索下有没有其他的服务可用
    service-url:
      defaultZone: http://localhost:7001/eureka/
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
  instance:
    instance-id: payment8001
    prefer-ip-address: true  # 访问路径可以显示 IP 地址
    #Eureka 客户端向服务端发送心跳的时间间隔,单位秒(默认 30 秒)
    lease-renewal-interval-in-seconds: 1
    #Eureka 服务端在收到最后一次心跳后等待的时间上限,单位秒(默认 90 秒),超时剔除服务
    lease-expiration-duration-in-seconds: 2

# 4. 业务类 PaymentController

@GetMapping("/payment/zipkin")
public String paymentZipkin(){
        return "hi ,i'am paymentzipkin server,welcome to atguigu,O(∩_∩)O哈哈~";
}

# 2.3. 服务消费者(调用方)

# 1. 修改:cloud-consumer-order80

# 2. POM

<!-- 包含了 sleuth+zipkin-->
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

# 3. YML

同样仅添加 zipkin 的配置即可

server:
  port: 80
spring:
    application:
        name: cloud-order-service
    zipkin:
        base-url: http://localhost:9411
        sleuth:
          sampler:
            probability: 1
eureka:
  client:
    #表示是否将自己注册进 EurekaServer 默认为 true。
    register-with-eureka: false
    #是否从 EurekaServer 抓取已有的注册信息,默认为 true。单节点无所谓,集群必须设置为 true 才能配合 ribbon 使用负载均衡
    fetchRegistry: true
    service-url:
      #单机
      defaultZone: http://localhost:7001/eureka
      #集群
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  # 集群版

# 4. 业务类 OrderController

//==> zipkin+sleuth
@GetMapping("/consumer/payment/zipkin")
public String paymentZipkin(){
        String result = restTemplate.getForObject("http://CLOUD-PAYMENT-SERVICE"+"/payment/zipkin/", String.class);
        return result;
}

# 2.4. 依次启动 eureka7001/8001/80

80 调用 8001 几次测试下

# 2.5. 打开浏览器访问: http://localhost:9411

会出现以下界面

查看

img

点击【SHOW】按钮,查看依赖关系。

img

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Dabing-He 微信支付

微信支付