springcloud

springcloud

第一章 SpringCloud简介

#一、 软件架构演进

单体架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aWmVJW2S-1681790672557)(null)]

垂直架构(将原来的单体架构依依拆分成多个小模块,方便扩展)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tnhddo5z-1681790673129)(null)]

当有数十万用户同时登录时,就需要分布式架构,通过nginx负载均衡将请求平均分发到分布的登录模块上减轻了压力。同理订单模块如果负载过大也可以多分布几个订单模块减轻压力。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-purGpJAr-1681790673234)(null)]

SOA架构(类似一个复杂的蜘蛛网结构,所有服务通过总线服务来解决。) 用户买东西先登录认证,选好商品后服务总线返回给用户,用户下单后,服务总线在订单模块下单后原路返回结果给用户,下订单时也可调用支付服务,服务总线就回去调用支付模块。有要求告诉总线,总线去给你操作,无论多么繁杂都没问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eIrZK8Ao-1681790673348)(null)]

SOA架构很好,但是操作都是依靠总线服务来解决复杂的解构中的请求,但是如果总线服务挂了,那么整个架构就挂了。所以就有了微服务架构。

注册中心记录了用户进行过哪些服务,之后用户想直接买的话,注册中心记录有支付功能,直接让用户去调用支付功能了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-spXqHrT7-1681790673407)(null)]

二、微服务架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WDBeWFEG-1681790670443)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230310210436508.png)]

将每个服务的ip+端口记录在注册中心,某个服务要调用哪个服务直接去注册中心找到了要调用的服务的信息,之后直接去调用目标服务。而相对SOA,是需要将信息放到服务总线,要调用时需要跟总线说,总线去调用了后返回给自己,相对来说耗费时间要比微服务架构多得多。微服务知道目标服务信息后,直接去调用即可。

#1、 微服务理念

①"微服务”一词源 于 Martin Fowler的名为 Microservices的博文,可以在他的官方博客上找到http://martinfowler.com/articles/microservices.html

②微服务是系统架构上的一种设计风格,它的主旨是将一个原本独立的系统拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间一般通过 HTTP 的 RESTfuL API 进行通信协作。

restfull 风格:数据的增删改查,使用http的不同方式。数据传输用json。

查询 GET ip:port/user/1

新增 POST ip:port/user json{username:itlils,age:18}

修改 PUT ip:port/user/1 json{username:itlils,age:19}

删除 DELETE ip:port/user/1

③由于有了轻量级的通信协作基础,所以这些微服务可以使用不同的语言来编写。大厂,各种语言混用。(比如前端用java写的,后端用c来写也可以)

第四章 微服务架构编码构建

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LjCqBXBd-1681790673536)(null)]

用户下单id=1的商品,随后订单表去数据库订单表下单,因为id=1去商品表查id=1的商品信息,商品表去数据库库存表查到该商品信息返回给客户。

一、 搭建 Provider 和 Consumer 服务

#1、父工程 spring-cloud-parent

pom.xml配置:

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cgboy</groupId>
    <artifactId>spring-cloud-parent</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--spring boot 环境 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.11.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>
2、提供者 eureka-provider

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-brdUQUVT-1681790670444)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105124116469.png)]

application.yml配置:

server:
  port: 8000

主启动类:

@SpringBootApplication
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }
}

domain层:goods类

public class Goods implements Serializable {
    private Integer goodsId;
    private String goodsName;
    private double price;
    //库存量
    private Integer stock;

    @Override
    public String toString() {
        return "Goods{" +
                "goodsId=" + goodsId +
                ", goodsName='" + goodsName + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                '}';
    }

    public Goods() {
    }

    public Goods(Integer goodsId, String goodsName, double price, Integer stock) {
        this.goodsId = goodsId;
        this.goodsName = goodsName;
        this.price = price;
        this.stock = stock;
    }

    public Integer getGoodsId() {
        return goodsId;
    }

    public void setGoodsId(Integer goodsId) {
        this.goodsId = goodsId;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }
}

dao层:

@Repository
public class GoodsDao {
    public Goods findById(Integer id){
        //模拟从数据库中查询
        Goods goods = new Goods();
        goods.setGoodsId(id);
        goods.setGoodsName("手机");
        goods.setPrice(5999.00);
        goods.setStock(100);
        return goods;
    }
}

controller:

@RestController
@RequestMapping("/goods")
public class GoodsController {
    @Autowired
    GoodsService goodsService;

    @GetMapping("findById/{id}")
    public Goods findById(@PathVariable("id") Integer id){
        Goods goods = goodsService.findById(id);
        return goods;
    }

}

运行主启动类后,我们在浏览器输入请求:http://localhost:8000/goods/findById/1显示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-poAEQVwM-1681790670444)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105124147959.png)]

此时生产者模块基础设置完毕。

3、消费者 eureka-consumer

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K4JKvk2s-1681790670445)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105130140352.png)]

pom.xml配置:

<?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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.cgboy</groupId>
        <artifactId>spring-cloud-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>eureka-consumer</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--spring boot web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

    </dependencies>

</project>

application.yml配置:

server:
  port: 9000

主启动类:

@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

domain层:goods类

public class Goods implements Serializable {
    private Integer goodsId;
    private String goodsName;
    private double price;
    //库存量
    private Integer stock;

    @Override
    public String toString() {
        return "Goods{" +
                "goodsId=" + goodsId +
                ", goodsName='" + goodsName + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                '}';
    }

    public Goods() {
    }

    public Goods(Integer goodsId, String goodsName, double price, Integer stock) {
        this.goodsId = goodsId;
        this.goodsName = goodsName;
        this.price = price;
        this.stock = stock;
    }

    public Integer getGoodsId() {
        return goodsId;
    }

    public void setGoodsId(Integer goodsId) {
        this.goodsId = goodsId;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }
}

controller层:

@RestController
@RequestMapping("/order")
public class OrderController {

    @GetMapping("/add/{id}")
    public Goods add(@PathVariable("id") Integer id){
        //业务逻辑
        //1.查询商品
        //2.查库存
        //3.支付
        //4.物流
        return new Goods();
    }
}

运行主启动类后,浏览器输入请求:http://localhost:9000/order/add/2 增加一个id=2的订单

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BTAqxkSh-1681790670445)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105130437240.png)]

此时消费者模块基础设置完毕。

二、使用 RestTemplate 完成远程调用

  • Spring提供的一种简单便捷的模板类,用于在 java 代码里访问 restful 服务。
  • 其功能与 HttpClient 类似,但是 RestTemplate 实现更优雅,使用更方便。

我们现在要消费者发送请求生产者那边,查查商品的信息生产者返回给消费者显示:让order远程调用goods的信息,显示到浏览器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IOkDE91z-1681790670445)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105134437129.png)]

consumer工程中建立config包

RestTemplateConfig配置类:

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

随后在controller中拿到restTemplate的bean,通过它调用方法实现远程调用生产者的goods信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W7IV9lZ3-1681790670446)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105135729529.png)]

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    RestTemplate restTemplate;

    @GetMapping("/add/{id}")
    public Goods add(@PathVariable("id") Integer id){
        //业务逻辑
        //1.查询商品
        //2.查库存
        //3.支付
        //4.物流

        String url = "http://localhost:8000/goods/findById/"+id;
        Goods goods= restTemplate.getForObject(url, Goods.class);
        return goods;
    }

运行消费者的该主启动类后,浏览器输入请求:http://localhost:9000/order/add/2

随后显示出生产者的goods信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nY06Pemg-1681790670446)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105135950032.png)]

注册中心:

但是这样子,我们指定url后也就意味着我们要远程调用的生产者写死了,如果有很多生产者,那就不灵活了。所以需要使用注册中心。

如下:项目启动后,各个服务组件就会将他们的服务,ip端口发给注册中心保存,这就是服务注册。而一旦有服务需要访问其他服务组件时就会使用注册中心使用其中的一个ip端口来进行发送请求给其他服务,这就是服务发现。而如果有服务宕机的情况,注册中心会将对应的服务的ip端口删除掉不允许使用,这是服务维护。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gAxLY2AY-1681790670446)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105141422515.png)]

注册中心有eureka,consul,zookeeper,nacos等。

第五章 Eureka服务注册与发现

#一、Eureka

Eureka 包含两个组件:Eureka Server (注册中心) 和 Eureka Client (服务提供者、服务消费者)。

操作:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PTRjFvdk-1681790673773)(null)]

#二、 搭建 Eureka Server 服务

(1)创建 eureka-server 模块

(2) 引入 SpringCloud 和 euraka-server 相关依赖

(3)完成 Eureka Server 相关配置

(4)启动该模块

父工程依赖:加入

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cgboy</groupId>
    <artifactId>spring-cloud-parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>eureka-provider</module>
        <module>eureka-consumer</module>
    </modules>

    <!--spring boot 环境 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.11.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <!--spring cloud 版本-->
        <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
    </properties>

    <!--引入Spring Cloud 依赖-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

eureka-server工程

pom.xml配置:

<?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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.cgboy</groupId>
        <artifactId>spring-cloud-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>eureka-server</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <!--springboot工程-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

</project>

设置eureka相关配置:

server:
  port: 8761
# eureka 配置
# eureka 一共有4部分 配置
# 1. dashboard:eureka的web控制台配置
# 2. server:eureka的服务端配置
# 3. client:eureka的客户端配置
# 4. instance:eureka的实例配置


eureka:
  instance:
    hostname: localhost # 主机名
  client:
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信

    register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
    fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要

spring:
  application:
    name: eureka-server

随后我们在主启动类加上注解,表示该工程为服务端并开启:

@SpringBootApplication
@EnableEurekaServer//开启eureka的服务端
public class EurekaApp {
    public static void main(String[] args) {
        SpringApplication.run(com.cgboy.eureka.EurekaApp.class,args);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tlAdvUPC-1681790670447)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105152715525.png)]

我们将该服务端也注册到该服务端自己的注册中心上,随后测试看看:运行后,浏览器输入请求http://localhost:8761/,随后显示eureka的控制台界面,并显示了服务端名字。运行状态等:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ON1fLeyL-1681790670447)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105145916957.png)]

eureka搭建完成后,将消费者和生产者改造成eureka的客户端,使它们成为注册中心中的一部分。

三、 改造 Provider 和 Consumer 称为 Eureka Client

① 引 eureka-client 相关依赖

② 完成 eureka client 相关配置

③ 启动 测试

Provider工程

pom.xml加入依赖:

<!-- eureka-client -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IrSqwiT6-1681790670447)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105152456265.png)]

生产者工程主启动类加入注解表示该为eureka的客户端并开启:

@SpringBootApplication
@EnableEurekaClient //表示这是eureka的客户端
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xZGOZ8jZ-1681790670448)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105152921386.png)]

application配置类配置:

server:
  port: 8001


eureka:
  instance:
    hostname: localhost # 主机名
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
  application:
    name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

最后重启生产者eureka客户端即可

同理消费者Consumer也是怎么操作

在消费者工程加入依赖:

    <!-- eureka-client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

主启动类,加入注解使igai工程为eureka的客户端:

@SpringBootApplication
@EnableEurekaClient
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pnWLVSkp-1681790670448)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105153301946.png)]

随后application.yml配置:

server:
  port: 9000

eureka:
  instance:
    hostname: localhost # 主机名
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
  application:
    name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

最后重启消费者eureka客户端即可。

最后我们打开eureka的控制台刷新后显示出了三个服务的在线状态:此时我们改造成功。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5N3LotXg-1681790670448)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105153838458.png)]

现在回到最初的问题,我们不将消费者客户端的url写死,去直接调用该url,这样不灵活:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GFQHKb4O-1681790670448)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105154256915.png)]

我们应该使用eureka的服务发现功能来操作:通过DiscoveryClient的bean来拿到客户端实列,之后通过拼串儿方式取得对应url,最后调用

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    RestTemplate restTemplate;

    @GetMapping("/add/{id}")
    public Goods add(@PathVariable("id") Integer id){
        //业务逻辑
        //1.查询商品
        //2.查库存
        //3.支付
        //4.物流
        //直接调用:
//        String url = "http://localhost:8000/goods/findById/"+id;
//        Goods goods= restTemplate.getForObject(url, Goods.class);

        //服务发现:拿到eureka的名叫EUREKA-PROVIDER的客户端实例(生产者客户端的实列)
        List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");
        if(instances == null || instances.size()<= 0){
            return  null;
        }
        ServiceInstance serviceInstance = instances.get(0);
        String host = serviceInstance.getHost();
        int port = serviceInstance.getPort();

        String url = "http://" + host + ":"+ port + "/goods/findById/"+id;
        Goods goods= restTemplate.getForObject(url, Goods.class);
        return goods;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Hfgthhx-1681790670449)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105162133649.png)]

重启消费者客户端后,我们在浏览器输入请求:

http://localhost:9000/order/add/2,也能拿到生产者客户端中goods的信息,说明我们的消费者成功的通过eureka的注册中心去访问到了生产者的goods:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AbTWLon1-1681790670449)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105162336433.png)]

五、 Euraka配置详解

Eureka包含四个部分的配置

  • instance:当前Eureka Instance实例信息配置
  • client:Eureka Client客户端特性配置
  • server:Eureka Server注册中心特性配置
  • dashboard:Eureka Server注册中心仪表盘配置
1、实例信息配置
eureka:
    instance:
        hostname: localhost # 主机名
        prefer-ip-address: # 是否将自己的ip注册到eureka中,默认false 注册 主机名
        ip-address: # 设置当前实例ip
        instance-id: # 修改instance-id显示
        lease-renewal-interval-in-seconds: 30 # 每一次eureka client 向 eureka server发送心跳的时间间隔
        lease-expiration-duration-in-seconds: 90 # 如果90秒内eureka server没有收到eureka client的心

以生产者客户端为例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CAY8vMQQ-1681790670449)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105163532156.png)]

server:
  port: 8001


eureka:
  instance:
    hostname: localhost # 主机名
    prefer-ip-address: true # 是否将自己的ip注册到eureka中,默认false 注册 主机名
    ip-address: 127.0.0.1 # 设置当前实例ip
    #instance-id: # 修改instance-id显示
    lease-renewal-interval-in-seconds: 30 # 每一次eureka client 向 eureka server发送心跳的时间间隔
    lease-expiration-duration-in-seconds: 90 # 如果90秒内eureka server没有收到eureka client的心跳包,则剔除该服务
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
  application:
    name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
2、客户端特性配置
eureka:
    client:
        service-url:
       		 # eureka服务端地址,将来客户端使用该地址和eureka进行通信
        	defaultZone: 
        register-with-eureka: # 是否将自己的路径 注册到eureka上。
        fetch-registry: # 是否需要从eureka中抓取数据。
3、注册中心端配置
eureka:
    server: #是否开启自我保护机制,默认true
        enable-self-preservation: 
        eviction-interval-timer-in-ms: 120 2月#清理间隔(单位毫秒,默认是60*1000)
	instance:
        lease-renewal-interval-in-seconds: 30 # 每一次eureka client 向 eureka server发送心跳的时间间隔
        lease-expiration-duration-in-seconds: 90 # 如果90秒内eureka server没有收到eureka client的心跳包,则剔除

对consumer,provider,eureka-serveryml配置进行改造:

改造 provider

server:
  port: 8001


eureka:
  instance:
    hostname: localhost # 主机名
    prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
    ip-address: 127.0.0.1 # 设置当前实例的ip
    instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} # 设置web控制台显示的 实例id
    lease-renewal-interval-in-seconds: 3 # 每隔3 秒发一次心跳包
    lease-expiration-duration-in-seconds: 9 # 如果9秒没有发心跳包,服务器呀,你把我干掉吧~
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
    register-with-eureka: true # 是否将自己的路径 注册到eureka上。
    fetch-registry: true # 是否需要从eureka中抓取数据。
spring:
  application:
    name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

consumer

server:
  port: 9000


eureka:
  instance:
    hostname: localhost # 主机名
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
  application:
    name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

server

server:
  port: 8761

# eureka 配置
# eureka 一共有4部分 配置
# 1. dashboard:eureka的web控制台配置
# 2. server:eureka的服务端配置
# 3. client:eureka的客户端配置
# 4. instance:eureka的实例配置


eureka:
  instance:
    hostname: localhost # 主机名
  client:
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
    register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
    fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
  server:
    enable-self-preservation: true # 关闭自我保护机制,默认true
    eviction-interval-timer-in-ms: 120000 # 检查服务的时间间隔
spring:
  application:
    name: eureka-server

最后重启即可。

六、高可用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZBx5u9Xn-1681790674088)(null)]

  1. 准备两个Eureka Server
  2. 分别进行配置,相互注册
  3. Eureka Client 分别注册到这两个 Eureka Server中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CBcfkFGW-1681790670450)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105183252862.png)]

如上:我们的各个服务都成功引入注册中心了,但是如果只有一个注册中心,那么该注册中心宕机后就会导致各个服务奔溃不可用了,所以我们要高可用多设置几个注册中心,并让注册中心之间相互注册对方如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l4JXhROr-1681790670450)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105183453740.png)]

新建一个注册中心的工程:

创建eureka-server2

server:
  port: 8762


eureka:
  instance:
    hostname: eureka-server2 # 主机名
  client:
    service-url:
      defaultZone: http://eureka-server1:8761/eureka

    register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
    fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
spring:
  application:
    name: eureka-server-ha

主启动类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LghNnwTR-1681790670450)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105185138640.png)]

eureka-server的yml配置:

server:
  port: 8761

# eureka 配置
# eureka 一共有4部分 配置
# 1. dashboard:eureka的web控制台配置
# 2. server:eureka的服务端配置
# 3. client:eureka的客户端配置
# 4. instance:eureka的实例配置


eureka:
  instance:
    hostname: eureka-server1 # 主机名
  client:
    service-url:
      defaultZone: http://eureka-server2:8762/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
    register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
    fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
  server:
    enable-self-preservation: true # 关闭自我保护机制,默认true
    eviction-interval-timer-in-ms: 120000 # 检查服务的时间间隔
spring:
  application:
    name: eureka-server-ha

修改:C:\Windows\System32\drivers\etc\hosts下添加配置:

127.0.0.1 eureka-server1

127.0.0.1 eureka-server2

两个注册中心启动后,在eureka控制台能看到,eureka-server2注册了eureka-server1,eureka-server1注册了eureka-server2,他们互相注册。

例如,我们输入请求:http://eureka-server2:8762/,eureka-server2的副本为eureka-server1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KKNB9SU1-1681790670451)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105185642405.png)]

我们输入请求:http://eureka-server1:8761/,eureka-server1的副本eureka-server2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rppMNhSv-1681790670451)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105185804525.png)]

我们让生产者和消费者两个模块的yml配置都注册到两个注册中心当中:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GMIC1Cll-1681790670451)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105202224002.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pF43pcjh-1681790670452)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105202237715.png)]

随后重启各个服务后,我们输入请求:http://localhost:9000/order/add/2显示出数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ChiWevga-1681790670452)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105202313474.png)]

此时我们停掉一个注册中心的服务,此时注册中心只有一个在运行:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JTEcuzxI-1681790670452)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105202451265.png)]

然后继续输入请求http://localhost:9000/order/add/2:依然能拿到数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S2VFmowi-1681790670452)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105202508061.png)]

此时说明我的eureka高可用设置成功了。就算其中一个注册中心宕机也不影响服务的运行。

eureka目前已被淘汰,但是以前五年前的老项目还会使用。

第六章 Zookeeper服务注册与发现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLACxdf0-1681790674400)(null)]

有的老项目以前是dubbo,升级到微服务,使用zookeeper做注册中心。

zookeeper是一个分布式协调工具,可以实现注册中心功能。dubbo,大数据组件hadoop,hive,kafka。

安装后将zoo-simaple.cfg文件改为zoo.cfg

zoo.cfg配置:我们在F:/apache-zookeeper-3.5.6-bin/data创建data文件夹,我们的数据都放在这里

# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just 
# example sakes.
dataDir=F:/apache-zookeeper-3.5.6-bin/data
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the 
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1

启动 bin目录下

zkServer.cmd

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jmqUSx4i-1681790674463)(null)]

zookeeper注册中心服务端启动后,启动zookeeper注册中心客户端:同样操作zkCli.cmd启动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iesNT1V9-1681790670453)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105210301624.png)]

搭建zookeeper服务注册中心:

搭建zookeeper-provider工程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wfr3gDtS-1681790670453)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105211227287.png)]

pom.xml引入依赖:

<?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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.cgboy</groupId>
        <artifactId>spring-cloud-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>zookeeper-provider</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--springcloud 整合 zookeeper 组件-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <!--zk发现-->
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.5.6</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

application.yml配置:

server:
  port: 8004

spring:
  application:
    name: zookeeper-provider
  cloud:
    zookeeper:
      connect-string: 127.0.0.1:2181 # zk地址

domain包下的goods:

package com.cgboy.zk.domain;

import java.io.Serializable;

public class Goods implements Serializable {
    private Integer goodsId;
    private String goodsName;
    private double price;
    //库存量
    private Integer stock;

    @Override
    public String toString() {
        return "Goods{" +
                "goodsId=" + goodsId +
                ", goodsName='" + goodsName + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                '}';
    }

    public Goods() {
    }

    public Goods(Integer goodsId, String goodsName, double price, Integer stock) {
        this.goodsId = goodsId;
        this.goodsName = goodsName;
        this.price = price;
        this.stock = stock;
    }

    public Integer getGoodsId() {
        return goodsId;
    }

    public void setGoodsId(Integer goodsId) {
        this.goodsId = goodsId;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }
}

dao层:

@Repository
public class GoodsDao {
    public Goods findById(Integer id){
        //模拟从数据库中查询
        Goods goods = new Goods();
        goods.setGoodsId(id);
        goods.setGoodsName("手机");
        goods.setPrice(5999.00);
        goods.setStock(100);
        return goods;
    }
}

service层:

@Service
public class GoodsService {

    @Autowired
    GoodsDao goodsDao;

    public Goods findById(Integer id){
        Goods goods = goodsDao.findById(id);
        return goods;
    }
}

controller层:

@RestController
@RequestMapping("/goods")
public class GoodsController {
    @Autowired
    GoodsService goodsService;

    @GetMapping("findById/{id}")
    public Goods findById(@PathVariable("id") Integer id){
        Goods goods = goodsService.findById(id);
        return goods;
    }

}

主启动类:

@SpringBootApplication
@EnableDiscoveryClient//开启发现客户端(不管是eureka或zookeeper,只要有就会发现并拿到使用)
public class ProviderApp {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApp.class,args);
    }
}

运行主启动类后,打开zookeeper客户端黑窗口,输入ls /显示出以下界面说明我们新建的zookeeper-provider客户端服务成功注册到zookeeper的注册中心:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ubEUpEs4-1681790670454)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105211629789.png)]

生产者完成后,搭建消费者工程:zookeeper-consumer:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y5seonAy-1681790670454)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105213637003.png)]

pom.xml配置:

<?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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.cgboy</groupId>
        <artifactId>spring-cloud-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>zookeeper-consumer</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--springcloud 整合 zookeeper 组件-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <!--zk发现-->
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.5.6</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

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

    </dependencies>

</project>

application.yml配置:

server:
  port: 8005

spring:
  application:
    name: zookeeper-consumer
  cloud:
    zookeeper:
      connect-string: 127.0.0.1:2181 # zk地址

config包下配置类:

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

controller下:

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private DiscoveryClient discoveryClient;
    @Autowired
    RestTemplate restTemplate;

    @GetMapping("/add/{id}")
    public Goods add(@PathVariable("id") Integer id){
        //业务逻辑//1.查询商品//2.查库存//3.支付//4.物流
        //直接调用:
//        String url = "http://localhost:8000/goods/findById/"+id;
//        Goods goods= restTemplate.getForObject(url, Goods.class);
        //服务发现:拿到eureka的名叫EUREKA-PROVIDER的客户端实例(生产者客户端的实列)
        List<ServiceInstance> instances = discoveryClient.getInstances("zookeeper-provider");
        if(instances == null || instances.size()<= 0){
            return  null;
        }
        ServiceInstance serviceInstance = instances.get(0);
        String host = serviceInstance.getHost();
        int port = serviceInstance.getPort();

        String url = "http://" + host + ":"+ port + "/goods/findById/"+id;
        Goods goods= restTemplate.getForObject(url, Goods.class);
        return goods;
    }
}

domainxiagoods类:

public class Goods implements Serializable {
    private Integer goodsId;
    private String goodsName;
    private double price;
    //库存量
    private Integer stock;

    @Override
    public String toString() {
        return "Goods{" +
                "goodsId=" + goodsId +
                ", goodsName='" + goodsName + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                '}';
    }

    public Goods() {
    }

    public Goods(Integer goodsId, String goodsName, double price, Integer stock) {
        this.goodsId = goodsId;
        this.goodsName = goodsName;
        this.price = price;
        this.stock = stock;
    }

    public Integer getGoodsId() {
        return goodsId;
    }

    public void setGoodsId(Integer goodsId) {
        this.goodsId = goodsId;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }
}

主启动类:

@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

主启动类运行后,我们在浏览器输入请求:http://localhost:8005/order/add/2成功拿到值:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jVfohOL2-1681790670454)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105213846565.png)]

说明我们消费者端成功通过zookeeper注册中心去访问到了生产者端的goods数据信息。

第七章 Consul服务注册与发现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMsQXdyc-1681790674673)(null)]

二、 怎么用:

#1、 准备

在.exe文件下cmd进入黑窗口输入指令consul.exe agent -dev运行启动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wrfd59Cz-1681790674796)(null)]

consul.exe agent -dev

输入请求:http://localhost:8500/显示出:consul自身的服务端注册中心已经启动成功了,且已经注册到自己的注册中心上了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9XPT6zqw-1681790670455)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105221331698.png)]

2、 搭建 consul-provider

业务逻辑复制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bd1XCgS0-1681790674922)(null)]

跟上述zk操作相同。

启动主启动类后,输入请求http://localhost:8500/,发现我们的consul-provider工程已经成功注册到consul注册中心内:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c82Vjni8-1681790674991)(null)]

3、搭建 consul-consumer

pom.xml配置:

<?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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.cgboy</groupId>
        <artifactId>spring-cloud-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>consul-consumer</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

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

</project>

业务逻辑复制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pl8OCleF-1681790675099)(null)]

application.yml:

server:
  port: 8007

spring:
  application:
    name: consul-consumer
  cloud:
    consul:
      host: 127.0.0.1
      port: 8500
      discovery:
        service-name: ${spring.application.name}

controller:

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private DiscoveryClient discoveryClient;
    @Autowired
    RestTemplate restTemplate;

    @GetMapping("/add/{id}")
    public Goods add(@PathVariable("id") Integer id){
        //业务逻辑//1.查询商品//2.查库存//3.支付//4.物流
        //直接调用:
//        String url = "http://localhost:8000/goods/findById/"+id;
//        Goods goods= restTemplate.getForObject(url, Goods.class);
        //服务发现:拿到eureka的名叫EUREKA-PROVIDER的客户端实例(生产者客户端的实列)
        List<ServiceInstance> instances = discoveryClient.getInstances("consul-provider");
        if(instances == null || instances.size() <= 0){
            return  null;
        }
        ServiceInstance serviceInstance = instances.get(0);
        String host = serviceInstance.getHost();
        int port = serviceInstance.getPort();

        String url = "http://" + host + ":"+ port + "/goods/findById/"+id;
        Goods goods= restTemplate.getForObject(url, Goods.class);
        return goods;
    }
}

主启动类:

@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

运行后,查看consul控制台发现搭建的两个都成功注册到注册中心:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YbQkfJgS-1681790670456)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105223522256.png)]

此时我们输入请求http://localhost:8006/goods/findById/5

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VUBE5SCc-1681790670457)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105224147331.png)]

然后我们访问8007通过注册中心访问到goods的信息:

http://localhost:8007/order/add/5显示了生产者的goods信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-muTzVNTR-1681790670457)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230105224759613.png)]

三、 三个注册中心的异同

组件语言cap健康检查暴露接口cloud集成
eurekajavaap支持http已经集成
zookeeperjavacp支持tcp已经集成
consulgocp支持http已经集成

tcp直接连直接断,节省了时间,速度较快

cap

  • c:consustency 强一致性(必须整个集群数据强一致的)
  • a:avalibility 可用性
  • p:partition tolerance 分区容忍性

#第八章 Ribbon负载均衡服务调用

1、服务端负载均衡

负载均衡算法在服务端,服务端维护服务列表。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cDBe2gsX-1681790675242)(null)]

2、客户端负载均衡

多启鸡哥客户端,来分担压力。

  • 负载均衡算法在客户端
  • 客户端维护服务列表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JlDoUPRt-1681790675303)(null)]

#二、如何使用

以eureka:

1.新版的eureka依赖以及集成了Ribbon依赖,所以可以不引用

  <!--Ribbon的依赖-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
 </dependency>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Exh0uF2c-1681790675397)(null)]

2.声明restTemplate时加上@LoadBalanced注解:

@Configuration
public class RestTemplateConfig {
    @Bean
    @LoadBalanced//加上该注解后,此时就进化成ribbon客户端了
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

在controller中我们也不用写那么多东西了,直接通过以下代码就可以操作:

3.restTemplate请求远程服务时,ip端口替换为服务名

String url="http://EUREKA-PROVIDER/goods/findById/"+id;
Goods goods = restTemplate.getForObject(url, Goods.class);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-plIjC7gZ-1681790670458)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106103904546.png)]

随后因为我们之前做过高可用设置,让两个客户端都注册在两个注册中心上,我们修改让他们只注册在一个注册中心上:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2r2jx8Cs-1681790670458)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106104517572.png)]

测试:

1.启动2个provider

在各个客户端服务端设置goods的title属性以及getset方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rs46GG3M-1681790670458)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106113630315.png)]

controller:查看我们调用的是哪个端口的provider:

goods.setTitle(goods.getTitle()+"|端口号:"+port);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-twkyp27d-1681790670459)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106112241711.png)]

idea设置 能启动两份 provider

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uCSLSdIM-1681790675555)(null)]

先启动eureka服务端,在启动eureka生产者客户端8001,随后,我们在eureka生产者客户端的端口修改为8002再启动一个新的eureka生产者客户端

,这样就有两个eureka生产者客户端了:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7wYNVXMR-1681790670459)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106111531821.png)]

查看eureka控制台也有对应服务:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GUxh4ZqD-1681790670459)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106111610350.png)]

最后我们启动consumer客户端:现在总共四个服务在启动:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NCZgM4cZ-1681790670460)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106113718584.png)]

最后我们输入请求:http://localhost:9000/order/add/2显示成功从provider客户端拿到goods的数据,且显示了使用的是哪个端口的provider:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9NMyPIte-1681790670460)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106113848634.png)]

我们刷新网页时,使用的客户端都是不同的:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kZUTrqAE-1681790670460)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106113912558.png)]

再刷新:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0DRt5uAP-1681790670461)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106113924859.png)]

因为我们只有这两个生产者客户端,所以轮流被调用,这样当很多请求发来时就平衡了系统的负载,减轻了压力。

多次刷新,发现:ribbon客户端,默认使用轮询算法,经行负载均衡调用。

三、ribbon 负载均衡策略

内置负载均衡规则类规则描述
RoundRobinRule简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。
AvailabilityFilteringRule对以下两种服务器进行忽略:(1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。注意:可以通过修改配置loadbalancer.<clientName>.connectionFailureCountThreshold来修改连接失败多少次之后被设置为短路状态。默认是3次。(2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上线,可以由客户端的<clientName>.<clientName>.ActiveConnectionsLimit属性进行配置。
WeightedResponseTimeRule为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。
ZoneAvoidanceRule以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。
BestAvailableRule忽略哪些短路的服务器,并选择并发数较低的服务器。
RandomRule随机选择一个可用的服务器。
Retry重试机制的选择逻辑

#四、 设置ribbon 负载均衡策略

#1、代码

consumer工程

1.MyRule 返回想要的规则即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OdRJ5QSd-1681790670461)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106120631003.png)]

@Configuration
public class MyRule {

    @Bean
    public IRule iRule(){
        //设置负载均衡策略的算法为随机
        return new RandomRule();
    }
}

主启动类设置:

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "EUREKA-PROVIDER",configuration = MyRule.class)
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GfqkAFn1-1681790670461)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106120737061.png)]

之后我们同样的测试,发现使用的客户端为随机使用了。

2、配置

consumer工程

application.yml

EUREKA-PROVIDER: #远程服务名
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #策略

作用:方便运维修改,重启。随时切换策略。

#第九章、OpenFeign服务接口调用

#一、概述

第九章、OpenFeign服务接口调用

#一、概述

  • Feign 是一个声明式的 REST 客户端,它用了基于接口的注解方式,很方便实现客户端像调用本地接口方法一样,进行远程调用。
  • Feign 最初由 Netflix 公司提供,但不支持SpringMVC注解,后由 SpringCloud 对其封装,支持了SpringMVC注解,让使用者更易于接受。
  • https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/#spring-cloud-openfeign

#二、快速入门

a.在消费端引入 open-feign 依赖:

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

主启动类加入注解开启feign的调用:在启动类 添加 @EnableFeignClients 注解,开启Feign功能

@SpringBootApplication
@EnableEurekaClient
//@RibbonClient(name = "EUREKA-PROVIDER",configuration = MyRule.class)
@EnableFeignClients//开启feign远程调用
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YPFRiaXo-1681790670461)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106123356859.png)]

b.编写Feign调用接口。复制粘贴被调方的conreoller方法,加上类路径。

//加上该注解就代表是feign的客户端,并且调用EUREKA-PROVIDER的方法
@FeignClient("EUREKA-PROVIDER")
public interface GoodsFeign {

    //调用了EUREKA-PROVIDER的controller方法
    @GetMapping("/goods/findById/{id}")
    public Goods findById(@PathVariable("id") Integer id);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AolNVwL2-1681790670462)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106124328109.png)]

OrderController更加简便:

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private DiscoveryClient discoveryClient;
    @Autowired
    RestTemplate restTemplate;

    @Autowired
    GoodsFeign goodsFeign;

    @GetMapping("/add/{id}")
    public Goods add(@PathVariable("id") Integer id){
        //业务逻辑//1.查询商品//2.查库存//3.支付//4.物流
        //直接调用:
//        String url = "http://localhost:8000/goods/findById/"+id;
//        Goods goods= restTemplate.getForObject(url, Goods.class);
        //服务发现:拿到eureka的名叫EUREKA-PROVIDER的客户端实例(生产者客户端的实列)
//        List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");
//        if(instances == null || instances.size()<= 0){
//            return  null;
//        }
//        ServiceInstance serviceInstance = instances.get(0);
//        String host = serviceInstance.getHost();
//        int port = serviceInstance.getPort();
//
//        String url = "http://" + host + ":"+ port + "/goods/findById/"+id;
//        Goods goods= restTemplate.getForObject(url, Goods.class);

//        ribbon
//        String url="http://EUREKA-PROVIDER/goods/findById/"+id;
//        Goods goods = restTemplate.getForObject(url, Goods.class);

        //feign的调用:
        Goods goods = goodsFeign.findById(id);
        return goods;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7372D0VP-1681790670462)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106124421933.png)]

重启consumer客户端后,浏览器输入请求:http://localhost:9000/order/add/8也能拿到生产者端的goods数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CgDcIsgR-1681790670462)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106124610562.png)]

三、其他设置

#1、超时设置

• Feign 底层依赖于 Ribbon 实现负载均衡和远程调用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HSBOEgX7-1681790675857)(null)]

• Ribbon默认1秒超时。

• 超时配置: yml中

# 设置Ribbon的超时时间
ribbon:
  ConnectTimeout: 1000 # 连接超时时间 默认1s
  ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s

测试:

1.连接超时,provider都停掉,再去连接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MKwHkWmP-1681790675915)(null)]

2.逻辑处理的超时时间

provider

 @GetMapping("/findById/{id}")
    public Goods findById(@PathVariable("id") Integer id){
        Goods goods = goodsService.findById(id);
        goods.setTitle(goods.getTitle()+"|端口号:"+port);
        
        //模拟业务逻辑比较繁忙
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return goods;
    }
2、日志记录

1.Feign 只能记录 debug 级别的日志信息。

# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
  level:
    com.ydlclass: debug

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NoM31Vln-1681790670463)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106142029327.png)]

• 定义Feign日志级别Bean,打印所有的日志

@Configuration
public class FeignLogConfig {

    /*
        NONE,不记录
        BASIC,记录基本的请求行,响应状态码数据
        HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
        FULL;记录完成的请求 响应数据
     */
    @Bean
    public Logger.Level level(){
        return Logger.Level.FULL;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RldVGz28-1681790670463)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106142205710.png)]

远程调用的接口启用该Bean:

//加上该注解就代表是feign的客户端,并且调用EUREKA-PROVIDER的方法
@FeignClient(value = "EUREKA-PROVIDER",configuration = FeignLogConfig.class)
public interface GoodsFeign {

    //调用了EUREKA-PROVIDER的controller方法
    @GetMapping("/goods/findById/{id}")
    public Goods findById(@PathVariable("id") Integer id);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z4vAlO7n-1681790670464)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106144958918.png)]

重启consumer客户端后,输入请求:http://localhost:9000/order/add/9,成功拿到生产客户端的数据,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FHDyiqlO-1681790670464)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106145055987.png)]

且日志所有的都打印到了控制台:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WG1Dvvax-1681790670464)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106145136473.png)]

第十章 Hystrix断路器 (豪猪)-保险丝

#一、概述

重点:能让服务的调用方,够快的知道被调方挂了!不至于说让用户在等待。

Hystix 是 Netflix 开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败(雪崩)。

雪崩:一个服务失败,导致整条链路的服务都失败的情形。

D挂了,C调用D,一直调用不了,一直卡着

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-16vO8sid-1681790676113)(null)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u3dzVT7g-1681790676219)(null)]C调用D,一直调用不了,一直卡着,导致C也挂了,后续的跟着挂了,以此类推:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vvYbhWcI-1681790676278)(null)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CufhDTGb-1681790676370)(null)]

最后全部都挂了。

Hystix 主要功能

C去调用D获取id=1的数据,此时D查询数据库表时发现数据库坏了,连不上数据库,会返回数据库连接不上的信息给C:比如id=-1,title:数据库坏了,连不上的信息,C得到了D给的数据,这样这些数据C就返回给后面的B,A,所有的微服务都不会跟着挂掉。最后用户也会知道访问失败了,不会一直在哪儿傻等着,不会造成系统整个崩溃的雪崩现象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gGtVTRFl-1681790676424)(null)]

隔离

  1. 线程池隔离

    没有hystrix,a重试100次,才知道c挂了!

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4mPxydok-1681790676516)(null)]

    如下:使用了hystrix,更细分线程池比如总共一百次调用,B分配30次,D分配30次。C分配40次,只需要重试40次,C都没有返回数据,说明C确实挂了,让a更快的知道c挂了,而不是前面的面要重试100次才知道C挂了。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ifLn29kW-1681790676575)(null)]

  2. 信号量隔离

    没有hystrix,a一个带着认证信息(如jwt的令牌)的线程,重试100次,才知道c挂了!

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ajVFgtZ-1681790676673)(null)]

    使用了hystrix,更细分线程池,一个带着认证信息的线程,只需要重试40次,让a更快的知道c挂了

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-35X1tWYC-1681790676734)(null)]

降级

服务提供方降级(异常,超时)

consumer访问provider数据时,provider方因为超时报错了,此时provider放会返回一个特殊对象给consumer方,让他们知道。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vRyH1VJx-1681790676831)(null)]

消费方降级

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KYed2x9t-1681790676886)(null)]

熔断

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-okwSsOFc-1681790670467)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107110723025.png)]

限流

是有限流,但是,项目一般不用。nginx或者网关限流。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z6jQ7AjY-1681790670468)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107110800533.png)]

二、服务降级

服务提供方

a、在服务提供方,引入 hystrix 依赖

	<!-- hystrix -->
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
         </dependency>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uWx0ORPe-1681790670468)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106164209547.png)]

b、定义降级方法

//定义一个降级方法:
//1.方法的返回值要和原方法一致
//2.方法参数和原方法一致
//返回一个特殊对象
public Goods findById_fallback(Integer id){
    Goods goods = new Goods();
    goods.setGoodsId(-1);
    goods.setTitle("provider提供方降级: ");
    goods.setPrice(-9.9);
    goods.setStock(-10);
    return goods;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ftKDQ3qg-1681790670468)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106165231070.png)]

当controller方法出现异常时,就会调用该降级方法返回一个特殊对象:

@GetMapping("findById/{id}")
//该方法出现异常时就会调用降级方法findById_fallback
@HystrixCommand(fallbackMethod = "findById_fallback")
public Goods findById(@PathVariable("id") Integer id){
    Goods goods = goodsService.findById(id);
    goods.setTitle(goods.getTitle()+"|端口号:"+port);
    return goods;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F4GDFJBF-1681790670468)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106165341563.png)]

主启动类开启Hystrix:

@SpringBootApplication
@EnableEurekaClient //表示这是eureka的客户端
@EnableCircuitBreaker//开启Hystrix功能
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AusYwuek-1681790670469)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106165431707.png)]

已知我们再controller方法中加入了一个计算数学异常:1/0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GBBDFHWB-1681790670469)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106165641382.png)]

重启provider客户端:输入请求:http://localhost:9000/order/add/3,因为controller方法出现异常,所以调用降级方法返回一个特殊对象显示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3JkTzKjZ-1681790670469)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106172425072.png)]

此时说明我们的服务降级设置成功。

使用 @HystrixCommand 注解配置降级方法:

    @GetMapping("findById/{id}")
    //该方法出现异常时就会调用降级方法findById_fallback
    @HystrixCommand(fallbackMethod = "findById_fallback",commandProperties = {
            //设置Hystrix的超时时间,默认1s,给定调用该方法处理逻辑时间为3s
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    public Goods findById(@PathVariable("id") Integer id){

        //模拟业务逻辑比较繁忙
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        Goods goods = goodsService.findById(id);
        goods.setTitle(goods.getTitle()+"|端口号:"+port);
        return goods;
    }
//定义一个降级方法:
//1.方法的返回值要和原方法一致
//2.方法参数和原方法一致
//返回一个特殊对象
public Goods findById_fallback(Integer id){
    Goods goods = new Goods();
    goods.setGoodsId(-1);
    goods.setTitle("provider提供方降级: ");
    goods.setPrice(-9.9);
    goods.setStock(-10);
    return goods;
}

已知消费客户端逻辑处理时间设置为6秒,提供足够的时间:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V3ItmSkc-1681790670469)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106175416582.png)]

我们我们提供者客户端再带controller方法时睡了5s,而我们只给我们的方法设置3s的时间去处理调用,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xjB3AyaW-1681790670470)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106175924375.png)]

超出了超时时间限制,所以调用了降级方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P7EfUhOA-1681790670470)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106175943814.png)]

返回特殊对象给消费客户端显示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wiGv1Hkx-1681790670470)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106175953744.png)]

消费客户端调用生产客户端时,生产客户端调用自身controller方法设置了3s的时间处理,而再controller方法内却睡了5s,超时了,所以去调用了降级方法。

服务消费方

a、feign 组件已经集成了 hystrix 组件。

b、

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kzxpJ8CR-1681790677184)(null)]

c、定义feign 调用接口实现类,复写方法,即 降级方法

GoodsFeignClientFallback

package com.ydlclass.consumer.feign;

import com.ydlclass.consumer.domain.Goods;
import org.springframework.stereotype.Component;

/**
 * @Created by IT李老师
 * 公主号 “元动力课堂”
 * 个人微 itlils
 */
@Component
public class GoodsFeignCallback implements GoodsFeign{
    @Override
    public Goods findById(Integer id) {
        Goods goods=new Goods();
        goods.setGoodId(-2);
        goods.setTitle("调用方降级了!");
        goods.setPrice(-5.5);
        goods.setStock(-5);
        return goods;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0iZkDBG6-1681790670471)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106181019564.png)]

d、在 @FeignClient 注解中使用 fallback 属性设置降级处理类。

GoodsFeignClient

@FeignClient(value = "EUREKA-PROVIDER",configuration = FeignLogConfig.class,fallback = GoodsFeignCallback.class)
public interface GoodsFeign {
    @GetMapping("/goods/findById/{id}")
    public Goods findById(@PathVariable("id") Integer id);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CsNlge1L-1681790670471)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106181202924.png)]

e、配置开启

# 开启feign对hystrix的支持
feign:
  hystrix:
    enabled: true

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F3CtNwVL-1681790670471)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106181227595.png)]

重启consumer客户端,测试:停掉provider,再来输入请求访问:http://localhost:9000/order/add/3

因为proivider客户端挂掉了,所以访问不到,我们consumer客户端就调用自己的降级方法返回一个特殊对象显示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zg7e3LDM-1681790670472)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230106181711107.png)]

熔断测试:

provider工程controller加入:只要id=1的就出现异常,调用降级方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GWmpeN3h-1681790670472)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107112751397.png)]

运行后:http://localhost:9000/order/add/1,提供方调用了降级方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8faXFwnT-1681790670472)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107112958876.png)]

输入请求http://localhost:9000/order/add/2,不是id=1的成功拿到数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0680n0zX-1681790670472)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107113038341.png)]

此后我们一直访问id=1的数据,访问很多次后,已知都是在调用降级方法,此时我们在访问id不为1的数据时发现也不能访问了,也调用了降级方法,这是因为Hystrix的熔断机制,调用方多次调用时都失败,调用了降级方法,Hystrix会有一个类似断路器的设置让提供方关闭与调用方的联系,拒绝所有的请求,保护提供方。知道服务恢复正常为止.

再过一会儿,半开状态

http://localhost:9000/order/add/10

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SbQRhBkC-1681790677390)(null)]

Hyst rix 熔断机制,用于监控微服务调用情况,当失败的情况达到预定的阈值(5秒失败20次),会打开断路器,拒绝所有请求,直到服务恢复正常为止。

circuitBreaker.sleepWindowInMilliseconds:监控时间
circuitBreaker.requestVolumeThreshold:失败次数
circuitBreaker.errorThresholdPercentage:失败率

提供者provider的controller中

    @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
            //设置Hystrix的超时时间,默认1s
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
            //监控时间 默认5000 毫秒
            @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
            //失败次数。默认20次
            @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
            //失败率 默认50%
            @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")

    })

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vI3JhNLe-1681790670473)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107113552222.png)]

四、熔断监控**-运维

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rlyLRrV6-1681790677504)(null)]

Hystrix 提供了 Hystrix-dashboard 功能,用于实时监控微服务运行状态。

但是Hystrix-dashboard只能监控一个微服务。

Netflix 还提供了 Turbine ,进行聚合监控。

1、搭建监控模块

a、 创建监控模块

创建hystrix-monitor模块,使用Turbine聚合监控多个Hystrix dashboard功能,

b、引入Turbine聚合监控起步依赖

<?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>spring-cloud-parent</artifactId>
        <groupId>com.ydlclass</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>hystrix-monitor</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-turbine</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>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.yml配置:

spring:
  application:
    name: hystrix-monitor
server:
  port: 8769
turbine:
  combine-host-port: true
  # 配置需要监控的服务名称列表
  app-config: EUREKA-PROVIDER,EUREKA-CONSUMER
  cluster-name-expression: "'default'"
  aggregator:
    cluster-config: default
  #instanceUrlSuffix: /actuator/hystrix.stream
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
hystrix:
  dashboard:
    proxy-stream-allow-list: "*"

主启动类设置:

@SpringBootApplication
@EnableEurekaClient
@EnableTurbine//开启Turbine 集合监控功能
@EnableHystrixDashboard//开启Hystrix仪表盘功能
public class HystrixApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixApplication.class,args);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RcoNwcGj-1681790670474)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107114939671.png)]

2、修改被监控模块

需要分别修改 eureka-provider 和 eureka-consumer 模块:

a、导入依赖:

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </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-hystrix-dashboard</artifactId>
        </dependency>

b、配置Bean

此处为了方便,将其配置在启动类中。在provider建立config包中:

	@Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vlGKefJ1-1681790670474)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107115347375.png)]

c、provider启动类上添加注解@EnableHystrixDashboard

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uLSRRWqi-1681790670474)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107115732045.png)]

之后consumer中也配置bean:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o42aQyra-1681790670474)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107115944224.png)]

主启动类加上注解@EnableHystrixDashboard:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QTtWMV77-1681790670475)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107120036087.png)]

重启它们运行后,输入请求:http://localhost:8769/hystrix/显示:在框内输入请求: http://localhost:8769/turbine.stream按照下面设置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5zIapF3f-1681790670475)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107123127082.png)]

点击Monitor Stream显示加载中。

随后我们调用一下cosumer调用provider的数据:http://localhost:9000/order/add/2显示出数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oWNzIZ5I-1681790670475)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107123323855.png)]

此时我们打开Hystrix监控页面显示出画面,如果出现熔断会在页面中的红色数字显示出

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ANaL0OSM-1681790670476)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107123416782.png)]

  • 实心圆:它有颜色和大小之分,分别代表实例的监控程度和流量大小。如上图所示,它的健康度从绿色、黄色、橙色、红色递减。通过该实心圆的展示,我们就可以在大量的实例中快速的发现故障实例和高压力实例。
  • 曲线:用来记录 2 分钟内流量的相对变化,我们可以通过它来观察到流量的上升和下降趋势。

#第十一章、zuul路由网关

zuul核心人员走了两个,zuul2的研发过久,spring公司等不及,自己研发的Gateway网关。

https://github.com/Netflix/zuul/wiki

#第十二章 Gateway新一代网关

功能:路由+过滤

限流拦截,防刷,路由转发,同意鉴权。

#一、 概述

不使用

存在的问题:

解决缺点:
1客户端需要记录不同微服务地址,增加客户端的复杂性
2每个后台微服务都需要认证
3http 发请求,涉及到跨域
4后台新增微服务,不能动态知道地址

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s6zZtPFr-1681790670476)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107124016329.png)]

使用了网关的话:

• 网关旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。

• 在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N个微服务的接口完成一个用户请求。

• 网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发

• 在目前的网关解决方案里,有Nginx+ Lua、Netflix Zuul/zuul2 、Spring Cloud Gateway等等

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qkmbQ05d-1681790677730)(null)]

二、 快速入门

三、 静态路由

(1)搭建网关模块 api-gateway-server

(2)引入依赖:starter-gateway

<?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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.cgboy</groupId>
        <artifactId>spring-cloud-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>api-gateway-server</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--引入gateway 网关-->

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

        <!-- eureka-client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

</project>

(3)编写主启动类

@SpringBootApplication
@EnableEurekaClient
public class GateApp {
    public static void main(String[] args) {
        SpringApplication.run(GateApp.class,args);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ezn1wZCp-1681790670476)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107152909348.png)]

(4)编写application.yml配置文件

server:
  port: 80

spring:
  application:
    name: api-gateway-server

  cloud:
    # 网关配置
    gateway:
      # 路由配置:转发规则
      routes: #集合。
        # id: 唯一标识。默认是一个UUID
        # uri: 转发路径
        # predicates: 条件,用于请求网关路径的匹配规则
        # filters:配置局部过滤器的

        - id: eureka-provider
          # 静态路由
          # uri: http://localhost:8001/
          # 动态路由
          uri: http://localhost:8001/
          predicates: #拦截哪些路径,拦截到后就会去访问http://localhost:8001/
            - Path=/goods/**
          filters:
            - AddRequestParameter=username,zhangsan

        - id: eureka-consumer
          # uri: http://localhost:9000
          uri: http://localhost:9000/
          predicates: #拦截哪些路径,拦截到后就会去访问http://localhost:9000/
            - Path=/order/**
          # 微服务名称配置
      discovery:
        locator:
          enabled: true # 设置为true 请求路径前可以添加微服务名称
          lower-case-service-id: true # 允许为小写


eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

(5)启动测试

http://localhost/goods/findById/2显示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RwlwmXTc-1681790670477)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107153727645.png)]

,后台gateway-server工程拦截到goods/后回去路由访问提供者的http://localhost8001端口如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cc72o5tF-1681790670477)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107153932363.png)]

上述操作为静态路由。

四、动态路由

上述静态路由是被写死了的,只要拦截到就会路由访问到指定的url,如果有多个访问端口,那么就需要动态路由动态选择了:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YrGz72ct-1681790670477)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107154927108.png)]

application.yml配置动态路由:

拦截到后动态路由到指定客户端访问数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UzwiHAQK-1681790670478)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107155158964.png)]

重启后运行:输入请求:http://localhost/goods/findById/2显示出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jTbqWmy4-1681790670478)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107155243953.png)]

六、过滤器

(1)两个维度:

内置过滤器 自定义过滤器

局部过滤器 全局过滤器

(2)过滤器种类:

内置局部过滤器:

我们设置了访问网关时拦截到的请求去访问提供者客户端时会给响应头加上username=张三的信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ckIHLQCX-1681790670478)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107180425623.png)]

运行后:输入请求:http://localhost/goods/findById/2显示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e1hbpW7d-1681790670478)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107180738381.png)]

内置全局过滤器:

内置过滤器 全局过滤器: route同级

      default-filters:
        - AddResponseHeader=yld,itlils

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hL5IxExU-1681790670479)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107181123654.png)]

重启后输入请求:http://localhost/goods/findById/2显示出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DHpR9oLI-1681790670479)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107181432644.png)]

我们输入拦截order请求的网关调用的客户端:http://localhost/order/add/3

显示了全局内置过滤器加入的响应头信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-filXmLSl-1681790670479)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107181529616.png)]

自定义局部过滤器

用的很少。

自定义局过滤器:常用:

自定义全局过滤器步骤:

1. 定义类实现 GlobalFilter 和 Ordered接口
2. 复写方法
3. 完成逻辑处理

需求:1黑客ip,直接给你拒接掉。我们把我们本机的ip当作黑客来测试:

cmd黑窗口 ipconfig 查看我们的本机ip:192.168.0.105

定义类实现 GlobalFilter 和 Ordered接口:

@Component
public class IpFilter implements GlobalFilter, Ordered {

    //写业务逻辑
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1黑客ip过来了,直接给它拒绝掉
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        InetSocketAddress remoteAddress = request.getRemoteAddress();
        //主机名
        String hostName = remoteAddress.getHostName();
        System.out.println(hostName);
        //ip
        InetAddress address = remoteAddress.getAddress();
        String hostAddress = address.getHostAddress();
        System.out.println(hostAddress);
        //主机名
        String hostName1 = address.getHostName();
        System.out.println(hostName1);

        if(hostAddress.equals("192.168.0.105")){
            //拒绝掉黑客的请求
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        //走完了,到下一个过滤器
        return chain.filter(exchange);
    }

    //当有多个过滤器时,返回数值,数值越小的过滤器越先执行,规定好过滤器的执行顺序

    @Override
    public int getOrder() {
        return 0;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7S8Go9dJ-1681790670479)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107191911664.png)]

随后我们浏览器输入请求:http://192.168.0.105/goods/findById/2 直接被当作黑客ip拒绝访问了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9DrwVEVY-1681790670480)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107192046380.png)]

	让我们使用其他ip访问能成功访问:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f6vdHp7k-1681790670480)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107192144973.png)]

此时我们的第一个需求完成。

2某些请求路径 如“goods/findById”,危险操作,记录日志。

定义类实现 GlobalFilter 和 Ordered接口:

@Component
public class UrlFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        URI uri = request.getURI();
        String path = uri.getPath();
        System.out.println(path);

        if(path.contains("goods/findById")){
            //打日志
            System.out.println("path很危险");
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KdL96EHl-1681790670480)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107193218485.png)]

重启后运行,浏览器输入请求:http://localhost/goods/findById/2显示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XeGCRFBD-1681790670480)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107193251292.png)]

后台控制台也输出了该uri路径是危险的信息:

因为我们的getOrder的值设置为1,设置拒绝黑客的过滤器设置为0,高于第一个拒绝黑客过滤器所以先运行黑客过滤器,ip拦截允许访问打印了ip,主机的信息随后运行设置uri路劲报警的过滤器,打印该路径为危险的信息。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dXR94UUE-1681790670481)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230107193337040.png)]

第十三章 分布式配置中心

13-16组件,超大型公司才会用到

国内BATJ,或者国外FLAG:facebook linkedin amazon google

处理大规模微服务的技术。

#一、Config 概述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8yK9w1xl-1681790678151)(null)]

多个服务器他们的配置信息都往一个专门的配置中心服务器去获取,而如果需要改动其中一个A服务器的配置,运维人员需要登录认证该配置中心才能修改,而一般情况都是将微服务的配置放到如gitup,gitee上,这样就直接从github,gitee上获取配置。这样的好处是如果有成百上千的微服务需要同时修改配置,那么直接在github,gitee上编辑配置,这样微服务直接从上面获取到最新的配置信息即可。方便统一的配置和修改。

Spring Cloud Config 解决了在分布式场景下多环境配置文件的管理和维护。

集中管理配置文件

• 不同环境不同配置,动态化的配置更新

• 配置信息改变时,不需要重启即可更新配置信息到服务

二、Config 快速入门

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KEqbnWts-1681790678206)(null)]

config-server:

  1. 使用gitee创建远程仓库,上传配置文件

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uNiTQcax-1681790670481)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108134002860.png)]

    我们模拟将eureka-provider的配置文件上传:点击提交

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wa8rMRxp-1681790670482)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108134601421.png)]

    config-dev.yml,此时我们将配置文件设置到了外部的gitee码云上

  2. 搭建 config-server 模块

    导入 config-server 依赖

    pom

     		<!-- config-server -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-config-server</artifactId>
            </dependency>
    
  3. 主启动类ConfigServerApp

    主启动类:ConfigServerApp

@SpringBootApplication
@EnableConfigServer//开启配置中心的服务端
public class ConfigServerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApp.class,args);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EYSGX7F2-1681790670482)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108135203916.png)]

application.yml配置:

server:
  port: 9527

spring:
  application:
    name: config-server
  # spring cloud config
  cloud:
    config:
      server:
        # git 的 远程仓库地址
        git:
          uri: https://gitee.com/small-volume-cc/config-ydlclass.git
      label: master # 分支配置

运行后,我们输入请求:http://localhost:9527/master/provider-dev.yml显示出配置信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2hbx0Bzg-1681790670482)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108140408977.png)]

此时说明我们搭建的config-server配置中心搭建成功,确确实实从gitee上拿到了想要的配置文件信息。

我们让微服务不要从本地获取配置文件,而是通过config-server去码云获取配置文件。

以eureka-provider为例,我们将它的application.yml删掉,新建一个配置文件bootstrap.yml:这个配置文件就是不从本地获取配置文件,而是去http://localhost:9527去获取名叫provider,环境为dev环境,且是在master分支上的配置文件

# 配置config-server地址
# 配置获得配置文件的名称等信息
spring:
  cloud:
    config:
      # 配置config-server地址
      uri: http://localhost:9527
      # 配置获得配置文件的名称等信息
      name: provider # 文件名
      profile: dev # profile指定,  config-dev.yml
      label: master # 分支

已知我们在gitee上的配置加入了:ydlclass: itlls

在congtroller上获取该配置值:

    @Value("${ydlclass}")
    private String ydlclass;
    
    goods.setTitle(goods.getTitle()+"|端口号:"+port+"|ydlclass"+ydlclass);

我们运行eureka服务器后,重启eureka-provider客户端,然后输入请求:

http://localhost:8001/goods/findById/9c成功拿到了数据:并显示了配置文件中ydlclass=itlls的信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-srXKBqZ6-1681790670483)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108143125945.png)]

此时说明我们的eureka-provider客户端是通过从码云上获取的配置文件,在根据该配置运行拿到数据。这也就证明我们的config-server配置中心和某个微服务相关联上了。

如果我们将码云上的配置做了修改,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8nSNnr5d-1681790670483)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108143508735.png)]

那么其他的微服务就需要对配置进行更新才能改变。

此时我们测试微服务端获取数据后,拿到的配置值为itlls而不是itlls666.而我们访问配置中心config-server显示配置值已经修改了:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FqyOUA01-1681790670483)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108143721690.png)]

说明我们的配置中心确实是从码云上获取的最新的配置文件,但是我们的微服务是不知道的,要知道可以让微服务重启,但是如果微服务成千上万个,那么就要重启成千上万次,太折磨了也。

所以我们想直接通过通知给微服务,微服务就自动去码云更新了配置。

在微服务端eureka-provider加入依赖:

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

在controller类上加入注解:@RefreshScope // 开启刷新功能,也就是我们获取配置文件会动态刷新更新的配置内容。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DsQDDu4j-1681790670483)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108144519981.png)]

bootstrap.yml中添加配置:

management:
  endpoints:
    web:
      exposure:
        include: '*'

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cqvy1DTn-1681790670484)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108145031629.png)]

重启运行后,输入请求http://localhost:8001/goods/findById/9拿到数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YVIj4Yfi-1681790670484)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108145054833.png)]

但是呢,有可能是我们重启了微服务所以才更新了配置信息,所以此时我们在修改码云上的配置ydlclass:666888.

我们输入请求访问配置中心拿到的是最新配置信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-adSlobwb-1681790670484)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108145218955.png)]

而我们继续访问微服务拿到的配置却没有改变:http://localhost:8001/goods/findById/9

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8jXop6k4-1681790670484)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108145250490.png)]

因为我们还没有通知微服务获取最新的配置信息:

该请求需要使用post请求发送该通知:注意我们的微服务是开在8001端口的

可以使用postman发送

http://localhost:8001/actuator/refresh

也可以cmd黑窗口发送:

curl -X POST http://localhost:8001/actuator/refresh

懒得打开postman,使用黑窗口发送:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dSsE0gFr-1681790670485)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108145712090.png)]

此时我们在访问微服务http://localhost:8001/goods/findById/9显示出了最新的配置值:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FvK00gXi-1681790670485)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108145805622.png)]

这样我们就方便多了。

三、Config 集成Eureka

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2V1gUiQn-1681790678629)(null)]

跟注册中心一样,如果只有一个注册中心,这个注册中心挂掉了,整个系统就gg了,所以我们会启多个配置中心,且将它们的相关信息注册到注册中心,微服务要访问配置中心去访问配置信息时就去注册中西去问就行了。

微服务eureka-provider加入依赖:

        <!-- eureka-client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

主启动类加入注解:@EnableEurekaClient

bootstrap.yml配置加入:

# 配置config-server地址
# 配置获得配置文件的名称等信息
spring:
  cloud:
    config:
      # 配置config-server地址
      #uri: http://localhost:9527
      # 配置获得配置文件的名称等信息
      name: provider # 文件名
      profile: dev # profile指定,  provider-dev.yml
      label: master # 分支
      discovery:  #去找具体的配置中心,这里找叫CONFIG-SERVER的配置中心,而不是写死的http://localhost:9527
        enabled: true
        service-id: CONFIG-SERVER

management:
  endpoints:
    web:
      exposure:
        include: '*'

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M1ilM6nZ-1681790670485)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108151400811.png)]

我们将config-server配置中心注册到eureka注册中心上:

config-server加入依赖:

    <!-- eureka-client -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

主启动类加入注解:@EnableEurekaClient

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K5RTG1JT-1681790670486)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108151957908.png)]

在application.yml上加入配置,配置中心config-server注册到哪个eureka的注册中心:

我们启了两个eureka注册中心,让该配置中心都注册上它们:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VzHlZ0Va-1681790670486)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108152302442.png)]

重启运行后,我们打开eureka控制台查看到config-server成功注册到注册中心:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aQaPwi1B-1681790670486)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108152550745.png)]

测试,输入请求:http://localhost:8001/goods/findById/9,它是从注册中心拿到对应的配置中西信息,最后去码云访问到最新的配置文件信息拿到数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eK2eQMHi-1681790670486)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108152653842.png)]

我们应该多启几个配置中心,跟上述操作相同,这里不多阐述。

第十四章 SpringCloud Bus消息总线

如果有成百上千的微服务,需要更新配置,那么就让运维去发送成百上千的请求吗?太折磨了,我们只想发一次请求给配置中心,就可以让成百上千的微服务的配置更新。

远程的配置文件更新了,运维只需要发一个请求,所有用到这个配置文件的几百个应用更新了。

一、Bus 概述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cOSpiJ21-1681790678804)(null)]

Spring Cloud Bus 是用轻量的消息中间件将分布式的节点连接起来,可以用于广播配置文件的更改或者服务的监控管理。关键的思想就是,消息总线可以为微服务做监控,也可以实现应用程序之间相通信。

Spring Cloud Bus 可选的消息中间件包括 RabbitMQ 和 Kafka 。

二、RabbitMQ 回顾

message queue

异步、解耦、削峰填谷

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oqYRbQnA-1681790678902)(null)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wu2SmnsY-1681790678958)(null)]

RabbitMQ 提供了 6 种工作模式:简单模式、work queues(包工头)、Publish/Subscribe 发布与订阅模式、Routing

路由模式(通过路由键路由到对应队列)、Topics 主题模式(路由键过多时,使用通配符来操作)、RPC 远程调用模式(远程调用,不太算 MQ;暂不作介绍)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-36xrQCAo-1681790679066)(null)]

三、Bus 快速入门-运维

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NIdrJS3a-1681790679132)(null)]

1、分别在 config-server和eureka-provider中引入 bus依赖:bus-amqp

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

config-server的application中配置RabbitMq:

rabbitmq:
  host: localhost
  port: 5672
  username: guest
  password: guest
  virtual-host: /

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t6byVXAZ-1681790670488)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108174047002.png)]

随后我们打开RabbitMq控制台:http://localhost:15672/ 登录账号密码。

微服务eureka-provider客户端bootstramp.yml配置RabbitMq:

#配置rabbitmq信息
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    virtual-host: /

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L3PUijjb-1681790670488)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108181739429.png)]

运维往配置中心发消息那么就需要配置中心提供一个刷新端点来接收,在config-server中设置暴露监控断点:bus-refresh

# 暴露bus的刷新端点
management:
  endpoints:
    web:
      exposure:
        include: 'bus-refresh'

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bYRQ7ptE-1681790670488)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108175946533.png)]

重启后,我们刷新RabbitMq后发现有了一个SpringCloudBus的交换机:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T8YLZXPD-1681790670489)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108183542745.png)]

只要我们的微服务启起来,就自动在MQ中建立队列和该交换机进行绑定。

测试:我们在码云修改配置文件ydlclass=cgboy

我们使用微服务调用数据时没有得到最新的配置值:还是原来的值666888

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CaJGI3FM-1681790670489)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108184007010.png)]

我们访问配置中心可以看到最新的值:http://localhost:9527/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pJngncVF-1681790670489)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108184035941.png)]

此时我们在黑窗口发送通知给rabbitMq:curl -X POST http://localhost:9527/actuator/bus-refresh,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wGJPE8xD-1681790679308)(null)]

发送该请求后,该配置中心接收到更新配置信息后,将消息存到RabbitMq中,rabbitMq会通过SpringCloudBus交换机告诉给对应的所有微服务所在的队列,然后相关联的所有微服务都会去自动去配置中心访问,然后配置中心去码云拿到更新配置返回给微服务更新。

此时我们在输入请求成功拿到最新配置值:http://localhost:8001/goods/findById/9

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v7fXDlhG-1681790670490)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108185851770.png)]

第十五章 SpringCloud Stream消息驱动

#一、Stream 概述

本来使用的中间件是rabbitMq,结果突然变成了kafka,那么生产者消费者的工作模式都要从rabbitMq的方式改为kafka的工作方式。这种情况使用SpringCloud Stream来解决,不需要我们去管,SpringCloud Stream可以给我们封装,我们只需要去解决我们的业务就行了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YsBhUohz-1681790679419)(null)]

1.Spring Cloud Stream 是一个构建消息驱动微服务应用的框架。

2.Stream 解决了开发人员无感知的使用消息中间件的问题,因为Stream对消息中间件的进一步封装,可以做到代码层面对中间件的无感知,甚至于动态的切换中间件,使得微服务开发的高度解耦,服务可以关注更多自己的业务流程。

3.Spring Cloud Stream目前支持两种消息中间件RabbitMQ和Kafka

就像jdbc一样

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HjTNYL52-1681790679478)(null)]

Stream 组件:绑定器

绑定器binder保证我们程序能成功将消息发送给中间件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lrNhiVZ1-1681790679575)(null)]

Spring Cloud Stream 构建的应用程序与消息中间件之间是通过绑定器 Binder 相关联的。绑定器对于应用程序而言起到了隔离作用, 它使得不同消息中间件的实现细节对应用程序来说是透明的。

binding 是我们通过配置把应用和spring cloud stream 的 binder 绑定在一起

output:发送消息 Channel,内置 Source接口

input:接收消息 Channel,内置 Sink接口

Middleware:中间件

#二、Stream 消息生产者

搭建stream-producer工程:

pom.xml:

<?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>stream-parent</artifactId>
        <groupId>com.ydlclass</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>stream-producer</artifactId>


    <dependencies>

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


        <!-- stream -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>

    </dependencies>

</project>

application.yml配置:

server:
  port: 8000

spring:
  cloud:
    stream:
      # 定义绑定器,绑定到哪个消息中间件上
      binders:
        ydlclass_binder: # 自定义的绑定器名称
          type: rabbit # 绑定器类型
          environment: # 指定mq的环境
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
                virtual-host: /
      bindings:
        output: # channel名称
          binder: ydlclass_binder #指定使用哪一个binder
          destination: ydlclass_exchange # 消息目的地

controller类:

@RestController
@RequestMapping("test")
public class ProducerController {

    @Autowired
    MessageProducer messageProducer;
    //业务逻辑
    @GetMapping("/send")
    public String send(){
        //发消息
        String msg="使用stream来发消息了!";

        messageProducer.send(msg);

        return "success!";
    }
}

生产者发送消息给交换机:发送成功后输出成功发送的字样

@Component
@EnableBinding(Source.class)//这个类是stream的发送者
public class MessageProducer {
    @Autowired
    MessageChannel output;

    public void send(String msg){
        //将消息发给交换机
        output.send(MessageBuilder.withPayload(msg).build());
        System.out.println("MessageProducer 确实发了消息了!");
    }
}

主启动类:

@SpringBootApplication
public class ProducerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProducerApplication.class,args);
    }
}

运行后,输入请求:http://localhost:8000/test/send后显示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ppNLnIZV-1681790670491)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108210032098.png)]

后台也显示出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lvik9dR6-1681790670491)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108210047384.png)]

查看rabbitMq交换机ydlclass-exchange:成功显示交换机收到了发送的消息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vxLC4msl-1681790670491)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108210205573.png)]

此时生产者工程搭建完成。

三、Stream 消息消费者

搭建stream-consumer工程

pom.xml:

<?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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.cgboy</groupId>
        <artifactId>spring-cloud-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>stream-consumer</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

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


        <!-- stream -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>

    </dependencies>

</project>

主启动类:

@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

application.yml配置:

server:
  port: 9000



spring:
  cloud:
    stream:
      # 定义绑定器,绑定到哪个消息中间件上
      binders:
        ydlclass_binder: # 自定义的绑定器名称
          type: rabbit # 绑定器类型
          environment: # 指定mq的环境
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
                virtual-host: /
      bindings:
        input: # channel名称
          binder: ydlclass_binder #指定使用哪一个binder
          destination: ydlclass_exchange # 从这个交换机获取消息

监听交换机的类:

@Component
@EnableBinding(Sink.class)//表示这个类是stream的消费者监听类,监听交换机有没有消息
public class MessageListener {

    @StreamListener(Sink.INPUT)//只要监听到交换机有消息,就执行下面的方法
    public void receiveMsg(Message message){
        System.out.println(message);
        //打印交换机内消息
        System.out.println(message.getPayload());
    }
}

运行后,我们打开rabbitMq的ydlclass-exchange交换机,发现给我自动创建监听交换机的队列:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4b7uwfda-1681790670492)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108212446817.png)]

测试:输入请求:http://localhost:8000/test/send显示成功页面:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jQc5HsV6-1681790670492)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108212656736.png)]

生产者端后台显示发送消息成功:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Eev6ma9-1681790670492)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108212718892.png)]

查看消费者端:也成功监听到生产者发送给交换机的消息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CMS9wHGg-1681790670492)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108212804372.png)]

此时我们的消费者工程搭建成功。

此时我们的项目中间件是使用的rabbitMq,如果被替换成kafka时,我们只需要引入stream相关kafka依赖:

<!-- stream -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>

在application.yml中只修改使用的中间件类型为kafka,加上kafka相关配置信息即可,其他的业务代码逻辑都可以不用修改:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WwLYADun-1681790670492)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108213341231.png)]

第十六章 SpringCloud Sleuth分布式请求链路追踪

#一、概述

用户请求后A服务完成需要同时调用B和F服务,F服务完成需要调用G服务,B服务完成需要同时调用C,D,D完成需要调用E。此时想要看看当下的请求过来我们涉及到了多少服务。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hBnffhlA-1681790679800)(null)]

Spring Cloud Sleuth 其实是一个工具,它在整个分布式系统中能跟踪一个用户请求的过程,捕获这些跟踪数据,就能构建微服务的整个调用链的视图,这是调试和监控微服务的关键工具。就是将数据的收集起来。

相关优势:

耗时分析 
可视化错误 
链路优化

Zipkin 是 Twitter 的一个开源项目,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。将sleuth收集的数据展现出来。

#二、快速入门

使用sleuth+Zipkin完成链路追踪

  1. 安装启动zipkin。 java –jar zipkin.jar

    找到zikpin的jar包后,cmd黑窗口 java –jar zipkin.jar运行:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hIEzESEh-1681790670493)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108220206941.png)]

我们发现它的默认端口为9411,浏览器输入请求http://localhost:9411/显示出对数据的展现(现在没有收集数据,所以什么也没有):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-it1lMTye-1681790670493)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108220424477.png)]

我们以eureka的消费放和提供方为列:

在服务提供方和消费方分别引入 sleuth 和 zipkin 依赖(ziplin的依赖内部已经有sleuth的包了,所以可以不引入sleuth依赖)

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

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

配置服务提供方:因为我们将eureka-provider的微服务的配置都放到码云上了,所以我们在码云上进行修改:

eureka-provider:一般公司内成百上千的数据采样率值采集百分之10来分析,这里我们学习阶段,所以采样百分之百

 zipkin:
    base-url: http://localhost:9411/  # 设置zipkin的服务端路径
  sleuth:
    sampler:
      probability: 1 # 采集率 默认 0.1 百分之十。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7zwUfMh4-1681790670493)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108221603641.png)]

配置消费方eureka-consumer:

zipkin:
    base-url: http://localhost:9411/  # 设置zipkin的服务端路径
  sleuth:
    sampler:
      probability: 1 # 采集率 默认 0.1 百分之十。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oP0MOuDo-1681790670494)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108221801516.png)]

启动eureka服务端后,分别启动提供者和消费者端。

因为我们使用了配置中心,所以需要启动配置中心的服务器,让provider微服务自动更新配置。

最后输入请求:http://localhost:9000/order/add/2成功显示数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XKC0iHI0-1681790670494)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108223704058.png)]

此时我们打开zipkin点击eureka-consumer进行查看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7FptGZCs-1681790670494)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108223540645.png)]

能看到相关调用过程,我们点击进去海恩那个看到调用耗费时间,调用了那些方法等:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j6S9ubpo-1681790670494)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108223754479.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zj1fTVdS-1681790670494)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108223851539.png)]

点击依赖还可以看到我们是从消费端去调用了提供端的关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KtLmoatD-1681790670494)(C:\Users\陈刚\AppData\Roaming\Typora\typora-user-images\image-20230108223938894.png)]

host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
bindings:
input: # channel名称
binder: ydlclass_binder #指定使用哪一个binder
destination: ydlclass_exchange # 从这个交换机获取消息


监听交换机的类:

```java
@Component
@EnableBinding(Sink.class)//表示这个类是stream的消费者监听类,监听交换机有没有消息
public class MessageListener {

    @StreamListener(Sink.INPUT)//只要监听到交换机有消息,就执行下面的方法
    public void receiveMsg(Message message){
        System.out.println(message);
        //打印交换机内消息
        System.out.println(message.getPayload());
    }
}

运行后,我们打开rabbitMq的ydlclass-exchange交换机,发现给我自动创建监听交换机的队列:

[外链图片转存中…(img-4b7uwfda-1681790670492)]

测试:输入请求:http://localhost:8000/test/send显示成功页面:

[外链图片转存中…(img-jQc5HsV6-1681790670492)]

生产者端后台显示发送消息成功:

[外链图片转存中…(img-3Eev6ma9-1681790670492)]

查看消费者端:也成功监听到生产者发送给交换机的消息

[外链图片转存中…(img-CMS9wHGg-1681790670492)]

此时我们的消费者工程搭建成功。

此时我们的项目中间件是使用的rabbitMq,如果被替换成kafka时,我们只需要引入stream相关kafka依赖:

<!-- stream -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>

在application.yml中只修改使用的中间件类型为kafka,加上kafka相关配置信息即可,其他的业务代码逻辑都可以不用修改:

[外链图片转存中…(img-WwLYADun-1681790670492)]

第十六章 SpringCloud Sleuth分布式请求链路追踪

#一、概述

用户请求后A服务完成需要同时调用B和F服务,F服务完成需要调用G服务,B服务完成需要同时调用C,D,D完成需要调用E。此时想要看看当下的请求过来我们涉及到了多少服务。

[外链图片转存中…(img-GT70P25T-1681790670493)]

Spring Cloud Sleuth 其实是一个工具,它在整个分布式系统中能跟踪一个用户请求的过程,捕获这些跟踪数据,就能构建微服务的整个调用链的视图,这是调试和监控微服务的关键工具。就是将数据的收集起来。

相关优势:

耗时分析 
可视化错误 
链路优化

Zipkin 是 Twitter 的一个开源项目,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。将sleuth收集的数据展现出来。

#二、快速入门

使用sleuth+Zipkin完成链路追踪

  1. 安装启动zipkin。 java –jar zipkin.jar

    找到zikpin的jar包后,cmd黑窗口 java –jar zipkin.jar运行:

    [外链图片转存中…(img-hIEzESEh-1681790670493)]

我们发现它的默认端口为9411,浏览器输入请求http://localhost:9411/显示出对数据的展现(现在没有收集数据,所以什么也没有):

[外链图片转存中…(img-it1lMTye-1681790670493)]

我们以eureka的消费放和提供方为列:

在服务提供方和消费方分别引入 sleuth 和 zipkin 依赖(ziplin的依赖内部已经有sleuth的包了,所以可以不引入sleuth依赖)

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

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

配置服务提供方:因为我们将eureka-provider的微服务的配置都放到码云上了,所以我们在码云上进行修改:

eureka-provider:一般公司内成百上千的数据采样率值采集百分之10来分析,这里我们学习阶段,所以采样百分之百

 zipkin:
    base-url: http://localhost:9411/  # 设置zipkin的服务端路径
  sleuth:
    sampler:
      probability: 1 # 采集率 默认 0.1 百分之十。

[外链图片转存中…(img-7zwUfMh4-1681790670493)]

配置消费方eureka-consumer:

zipkin:
    base-url: http://localhost:9411/  # 设置zipkin的服务端路径
  sleuth:
    sampler:
      probability: 1 # 采集率 默认 0.1 百分之十。

[外链图片转存中…(img-oP0MOuDo-1681790670494)]

启动eureka服务端后,分别启动提供者和消费者端。

因为我们使用了配置中心,所以需要启动配置中心的服务器,让provider微服务自动更新配置。

最后输入请求:http://localhost:9000/order/add/2成功显示数据:

[外链图片转存中…(img-XKC0iHI0-1681790670494)]

此时我们打开zipkin点击eureka-consumer进行查看

[外链图片转存中…(img-7FptGZCs-1681790670494)]

能看到相关调用过程,我们点击进去海恩那个看到调用耗费时间,调用了那些方法等:

[外链图片转存中…(img-j6S9ubpo-1681790670494)]

[外链图片转存中…(img-Zj1fTVdS-1681790670494)]

点击依赖还可以看到我们是从消费端去调用了提供端的关系图:

[外链图片转存中…(img-KtLmoatD-1681790670494)]

我们只是用了两个微服务,所以图很简单,如果在工作中,那么就是错综复杂很多图的关系图了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值