SpringCloud微服务架构之,Hystrix 熔断器,Gateway 网关

29 篇文章 0 订阅

Hystrix 概述

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

pom依耐

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

• 雪崩:一个服务失败,导致整条链路的服务都失败的情形。
• Hystix 主要功能

  • 隔离:用于隔离不同调用链之间相互不受影响
  • 降级:封装友好的错误提示并返回
  • 熔断:当请求错误率较高时,自动降级熔断
  • 限流:合理分配每个调用的并发请求数量

隔离

1. 线程池隔离
将多个请求线程按照每个服务的配置,分发到不同的微服务去调用,这样就解决的,线程一窝蜂的同一微服务中,影响的雪崩
在这里插入图片描述

2. 信号量隔离
在这里插入图片描述

降级

异常,超时
在A调用C的时候,C服务发生了异常,或者执行时间过长,为了避免请求回不友好的错误信息或者线程不一直等待,我们提供一个友好的方法,该方法往往返回一个失败请求的响应结果集,如:服务器繁忙等等,使得请求响应能够快速获得,而且异常后是友好的提示,超时后能快速的返回响应,不占用线程.防止服务雪崩.
这个降级不但可以在服务提供方编写一个降级方法,也可以在服务消费方编写.
在这里插入图片描述

熔断

使用服务熔断,首先要导入pom依耐
然后在主启动开启熔断:@EnableCircuitBreaker//开启hystrix的断路器
在服务业务类上书写:
注意的是:不编写那些超时,请求次数,hystrix都会有默认的值,都默认支持熔断

    //======服务熔断,providerCircuitBreakerMethod异常或者超时调用的方法
    @HystrixCommand(fallbackMethod = "providerCircuitBreakerMethod",commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),//是否开启断路器
            //sleepWindowInMilliseconds请求量阈值 默认失败次数20次
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),//请求次数
            //监控时间,默认5000毫秒 就是打开状态与半开状态之间的休眠时间
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000"),//时间窗口日期
            //误差阈值百分比errorThresholdPercentage 失败率默认百分之50
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),//失败率60%达到多少跳闸(进行服务熔断)
    })
    public Result providerCircuitBreaker(@PathVariable("id") Integer id){
        //制作异常,然后调用这个方法就会去调用配置的降级方法
        if (id==0){
            //id==0.就异常
            int i = 1/0;
        }
        return new Result(true,"providerCircuitBreaker调用成功");
    }

    //熔断友好提示方法
    @Override
    public Result providerCircuitBreakerMethod(Integer id){
        return new Result(false,"服务器繁忙,请稍候再试~~~熔断方法");
    }

在这里插入图片描述

在这里插入图片描述

限流

服务限流:(flowLimit)
就好比秒杀商品等高并发操作,禁止一窝蜂的请求过来拥挤,大家排队,一秒钟处理N个,有序的进行

测试Hystrix的代码

搭建一个父工程
在这里插入图片描述

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.fs</groupId>
    <artifactId>study-springcloud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>fs-server-eureka-7001</module>
        <module>fs-provider-hystrix-8001</module>
        <module>fs-consumer-hystrix-80</module>
    </modules>
    <!--    作为父工程-->
    <packaging>pom</packaging>




    <dependencyManagement>
        <dependencies>
            <!--      spring boot -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.2.RELEASE</version>
                <type>pom</type>
<!--        import        导入父工程的配置-->
                <scope>import</scope>
            </dependency>
            <!--      spring cloud -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR6</version>
                <type>pom</type>
<!--        import        导入父工程的配置-->
                <scope>import</scope>
            </dependency>

            <!--   spring-cloud-alibaba-dependencies  2.2.1.RELEASE -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.1.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

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

<!--            整合MyBatis-->

            <!--    mysql  -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.20</version>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.20</version>
            </dependency>
            <!--     MyBatisPlus   -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.3.2</version>
            </dependency>
<!--            lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.12</version>
            </dependency>

        </dependencies>
    </dependencyManagement>

    <dependencies>


    </dependencies>

</project>

fs-server-eureka-7001(省略,请查阅上一偏博客,服务治理)

fs-provider-hystrix-8001 服务提供者

在这里插入图片描述

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>study-springcloud</artifactId>
        <groupId>com.fs</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>fs-provider-hystrix-8001</artifactId>

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


        <!--     spring-boot-starter-web  spring-boot-starter-actuator绑定在一块 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

            <!--
            第一种是:如果你的应用不会再需要返回xml的系列化格式,那么直接在pom.xml文件中将jackson-dataformat-xml这外包排除即可(如果其他包也进行了jackson-dataformat-xml的依赖引用也要视情况排除):
             第二种是:不排除jackson-dataformat-xml包,而是直接在相应接口方法或Controller上明确指定将返回JSON格式的值:@GetMapping(value = "/user-instance", produces = MediaType.APPLICATION_PROBLEM_JSON_VALUE)
            -->
            <!--            排除controller返回的格式为xml-->
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.dataformat</groupId>
                    <artifactId>jackson-dataformat-xml</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--        mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--        jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--        druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        <!--        MyBatis-puls-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>

        <!--        自己的实体类-->
        <dependency>
            <groupId>com.fs</groupId>
            <artifactId>fs-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>
application.yml
server:
  port: 8001
spring:
  application:
    name: fs-provider-hystrix

  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.93.132:3306/fs_springcloud
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource #自定义数据源

# 配置eureka
eureka:
  instance:
    hostname: localhost # 主机名,写的是域名,本机在host文件中映射
    prefer-ip-address: true # 将当前实例的ip注册到eureka server中.默认是false 注册主机名
    ip-address: 127.0.0.1 # 修改instance-id显示
#    # 修改instance-id显示,在eureka中的显示名称
#    instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port}
#    lease-renewal-interval-in-seconds: 30 # 每一次eureka client 向 eureka server发送心跳的时间间隔
#    lease-expiration-duration-in-seconds: 90 # 如果90秒内eureka server没有收到eureka client的心跳包,则剔除该服务
  client:
    register-with-eureka: true # 将提供注册到注册eureka中心
    fetch-registry: true # 从eureka上抓取已有的注册信息
    service-url:
      defaultZone: http://localhost:7001/eureka #,http://localhost2:7002/eureka,http://localhost3:7003/eureka # 注册中心地址

# 配置MyBatis-plus日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
FsProviderHystrix8001 主启动

注意:@EnableCircuitBreaker//开启hystrix的断路器

package com.fs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
//开启Eureka客户端
@EnableEurekaClient
@EnableCircuitBreaker//开启hystrix的断路器
public class FsProviderHystrix8001 {
    public static void main(String[] args) {
        SpringApplication.run(FsProviderHystrix8001.class,args);
    }
}

PaymentServiceImpl 业务接口实现类

主要注解:@HystrixCommand

package com.fs.service.impl;

import com.fs.dao.PaymentDao;
import com.fs.pojo.Payment;
import com.fs.result.Result;
import com.fs.service.PaymentService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.List;

@Service
public class PaymentServiceImpl implements PaymentService {

    //注入dao
    @Autowired
    private PaymentDao paymentDao;


    @Override
    public List<Payment> findAll() {
        //使用MyBatis提供的方法
        return paymentDao.selectList(null);
    }

    /*
    测试消费端配置的服务降级方法
     */
    @Override
    public Result testConsumer(Integer id) {
        //制作异常,然后调用这个方法就会去调用配置的降级方法
        if (id==0){
            //id==0.就异常
            int i = 1/0;
        }
        return new Result(true,"testConsumer调用成功");
    }

    /*
    降级:
    1.服务出现异常
    2.服务调用超时,默认为1秒
    */
    @Override
    //@HystrixCommand一旦调用服务方法失败并抛出了错误信息后,会自动调用标注好的fallbackMethod()指定降级后调用的方法名称
    @HystrixCommand(fallbackMethod = "providerFallbackMethod",commandProperties = {
            //HystrixCommandProperties:这个类中有HystrixCommand注解的所有配置
            //timeoutInMilliseconds规定这个方法在3秒内没有正常执行,就服务降级,方法异常会立马进行降级,不配置默认1秒
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
            //熔断不配置默认是 默认失败次数20次 失败率默认百分之50 默认5000毫秒 就是打开状态与半开状态之间的休眠时间
    })
    public Result testFallbackMethod(Integer id){
        //制作异常,然后调用这个方法就会去调用配置的降级方法
        if (id==0){
            //id==0.就异常
            int i = 1/0;
        }
        return new Result(true,"testFallbackMethod调用成功");
    }

    //服务对应的降级方法
    /*
    1.方法的返回值需要和原方法一样
    2,方法的参数需要和原方法一样
     */
    @Override
    public Result providerFallbackMethod(Integer id){
        return new Result(false,"小二开小差中,请稍候再试~~~服务降级方法");
    }


    //======服务熔断,providerCircuitBreakerMethod异常或者超时调用的方法
    @HystrixCommand(fallbackMethod = "providerCircuitBreakerMethod",commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),//是否开启断路器
            //sleepWindowInMilliseconds请求量阈值 默认失败次数20次
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),//请求次数
            //监控时间,默认5000毫秒 就是打开状态与半开状态之间的休眠时间
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000"),//时间窗口日期
            //误差阈值百分比errorThresholdPercentage 失败率默认百分之50
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),//失败率60%达到多少跳闸(进行服务熔断)
    })
    public Result providerCircuitBreaker(@PathVariable("id") Integer id){
        //制作异常,然后调用这个方法就会去调用配置的降级方法
        if (id==0){
            //id==0.就异常
            int i = 1/0;
        }
        return new Result(true,"providerCircuitBreaker调用成功");
    }

    //熔断友好提示方法
    @Override
    public Result providerCircuitBreakerMethod(Integer id){
        return new Result(false,"服务器繁忙,请稍候再试~~~熔断方法");
    }

}

fs-consumer-hystrix-80 使用feign远程调用 服务消费端

在这里插入图片描述

pom.xml

== hystrix 因为OpenFeign集成了hystrix,所以不用导入hystrix的依耐==

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

    <artifactId>fs-consumer-hystrix-80</artifactId>

    <dependencies>
<!--        hystrix  因为OpenFeign集成了hystrix,所以不用导入hystrix的依耐-->

        <!--     spring-boot-starter-web  spring-boot-starter-actuator绑定在一块 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--        openFeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--        eureka-Client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <!--            排除controller返回的格式为xml-->
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.dataformat</groupId>
                    <artifactId>jackson-dataformat-xml</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--        自己的实体类-->
        <dependency>
            <groupId>com.fs</groupId>
            <artifactId>fs-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>
application.yml

主要的是加上:
因为feign默认是不开启hystrix的

# 开启feign对hystrix的支持,因为feign默认是不开启hystrix的
feign:
  hystrix:
    enabled: true

application.yml

server:
  port: 80

spring:
  application:
    name: fs-consumer-hystrix-80
eureka:
  client:
    register-with-eureka: false # 消费者我目前的用途不需要将消费者注册到注册中心
    fetch-registry: true # 从注册中心拉取服务
    registry-fetch-interval-seconds: 30 # 默认30秒定时去注册中心拉取服务
    service-url:
      defaultZone: http://localhost:7001/eureka #,http://localhost2:7002/eureka,http://localhost3:7003/eureka # 注册中心地址

# 设置feign客户端超时时间(OpenFeign默认支持Ribbon) 不配置,默认1秒,因为feign底层是使用的Ribbon,Ribbon默认超时是1秒
ribbon:
  #指的是建立链接后从服务器读取到可用资源所用的时间,等5秒
  ReadTimeout: 5000
  #指的是建立连接所用的时间,适用于网络状态正常的情况下,两端连接所用的时间,等5秒
  ConnectTimeout: 5000
logging:
  level:
    #    root: debug # 开启springboot的debug的日志信息,不配置springboot默认是info
    #    com.fs: debug # 开启部分springboot的debug的日志信息

    # feign日志以什么级别监控那个feign组件功能使用的接口,使用debug级别(只能记录debug级别),然后调用服务方法,在控制台就能看到详细debug信息
    com.fs.springcloud.server.PaymentOpenFeignService: debug

# 开启feign对hystrix的支持,因为feign默认是不开启hystrix的
feign:
  hystrix:
    enabled: true
FsConsumerHystrix80 主启动
package com.fs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
//使用openFeign,激活并开启,feign集成了robbin同时集成了hystrix,自动默认轮询的负载均衡规则
@EnableFeignClients
@EnableEurekaClient
public class FsConsumerHystrix80 {
    public static void main(String[] args) {
        SpringApplication.run(FsConsumerHystrix80.class,args);
    }
}

PaymentOpenFeignHystrix 定义 OpenFeign的接口

指定服务降级友好方法类:fallback = PaymentHystrixFallbackServiceImpl.class

package com.fs.feign;

import com.fs.config.OpenFeignConfig;
import com.fs.pojo.Payment;
import com.fs.result.Result;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;
/**
 * feign的声明式接口,发起远程调用的,简化restTemplate
 *
 * 1.定义接口
 * 2.接口上添加注解@FeignClient(value = "注册中心服务提供者名",configuration=定义的OpenFeign的日志类,fallback定义服务降级方法)
 * 3.编写调用接口,接口的声明规则和提供方接口保持一致
 * 4.去controller注入改接口对象,调用接口方法来完成远程调用
 */
@FeignClient(value = "fs-provider-hystrix",configuration = OpenFeignConfig.class,fallback = PaymentHystrixFallbackServiceImpl.class)
public interface PaymentOpenFeignHystrix {

    //复制服务提供的controller方法,路径记得加上controller类上的路径
    @RequestMapping("/payment/findAll")
    Result<List<Payment>> findAll();

    //测试time超时,由于我们在服务提供方的这个方法制作了sleep2秒,由于feign底层基于Ribbon,
    //Ribbon默认超时时间为1秒,所以报错java.net.SocketTimeoutException: Read timed out
    //解决办法在配置文件中配置Ribbon的超时时间
    @RequestMapping("/payment/testTimeOut/{id}")
    Result test(@PathVariable("id") Integer id);
}

PaymentHystrixFallbackServiceImpl 远程调用异常或者超时的服务降级友好方法类
package com.fs.feign;

import com.fs.pojo.Payment;
import com.fs.result.Result;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * Feign 客户端的降级处理类(feign自动集成hystrix,但是默认关闭,需要在yml中开启)
 * 1. 定义类 实现 Feign 客户端接口
 * 2. 使用@Component注解将该类的Bean加入SpringIOC容器
 * 默认异常降级,默认等待超时1秒,默认异常占比百分之50,默认的半开时间5秒,默认10秒20次失败请求
 */
@Component
public class PaymentHystrixFallbackServiceImpl implements PaymentOpenFeignHystrix {

    @Override
    public Result<List<Payment>> findAll() {
        return new Result(false,"fs-consumer-hystrix-80-findAll服务降级");
    }

    @Override
    public Result test(Integer id) {
        return new Result(false,"fs-consumer-hystrix-80-test服务降级");
    }
}

OpenFeignConfig
package com.fs.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/*
OpenFeign的日志配置类
 */
@Configuration
public class OpenFeignConfig {

    @Bean
    Logger.Level feignLoggerLevel(){
        //表示开启的是详细的feign日志,FULL表示最为详细的,点进去有4个
        return Logger.Level.FULL;
    }
    //还需要在yml中配置feign日志已什么级别监控那个接口
}

PaymentController 消费端controller
package com.fs.controller;

import com.fs.feign.PaymentOpenFeignHystrix;
import com.fs.pojo.Payment;
import com.fs.result.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/consumer")
public class PaymentController {

    //注入OpenFeign接口
    @Autowired
    private PaymentOpenFeignHystrix paymentOpenFeign;



    @RequestMapping("/payment/findAll")
    public Result<List<Payment>> findAll(){
        //调用OpenFeign接口
        Result<List<Payment>> all = paymentOpenFeign.findAll();
        return all;
    }


    //测试OpenFeign远程调用,服务降级方法
    @RequestMapping("/payment/testTimeOut/{id}")
    Result test(@PathVariable("id")Integer id){
        Result test = paymentOpenFeign.test(id);
        return test;
    }

}

启动项目测试

先启动eureka注册中心:fs-server-eureka-7001
在启动服务提供端:fs-provider-hystrix-8001
在启动服务消费端:fs-consumer-hystrix-80
在这里插入图片描述

首先浏览器输入:http://localhost:7001/
在这里插入图片描述

然后测试服务提供方的业务是否能正常访问,我们直接访问被指定降级的业务方法
在这里插入图片描述
在这里插入图片描述
然后测试服务消费端配置的服务降级接口
在这里插入图片描述
在这里插入图片描述

Hystrix 熔断监控

在这里插入图片描述

Gateway 网关

网关概述

• 网关旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。
• 在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N个微服务的接口完成一个用户请求。
• 存在的问题:
• 客户端多次请求不同的微服务,增加客户端的复杂性
• 认证复杂,每个服务都要进行认证
• http请求不同服务次数增加,性能不高
• 网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等
• 在目前的网关解决方案里,有Nginx+ Lua、Netflix Zuul 、Spring Cloud Gateway等等
在这里插入图片描述

什么是Gateway

  • 定义:前端统一访问微服务的人口
  • 功能:
    • 认证
    • 鉴权
    • 日志
    • 监控
    • 缓存
    • 负载均衡
    • 流量控制
  • 事实:
    • Gateway自动集成Ribbon,且默认开启相关功能

Gateway 网关路由配置

Gateway 网关路由配置 – 静态路由

    # 网关配置
    gateway:
      discovery:
        locator:
          enabled: true #使用情况少,不常用(了解) 开启从注册中心动态创建路由的功能,利用微服务进行路由,请求路径前可以添加微服务名称
          lower-case-service-id: true #(了解) 允许请求路径的微服务名称为小写
      routes:
        - id: payment_routh #payment_routh 路由的id,若不配置,默认是UUID,没有固定规则但要求唯一
          uri: http://localhost:8001 # 静态路由 这样配置是死的,不好 匹配后提供服务的路由地址

Gateway 网关路由配置 – 动态路由
• 引入eureka-client配置
• 修改uri属性:uri: lb://服务名称

    # 网关配置
    gateway:
      discovery:
        locator:
          enabled: true #使用情况少,不常用(了解) 开启从注册中心动态创建路由的功能,利用微服务进行路由,请求路径前可以添加微服务名称
          lower-case-service-id: true #(了解) 允许请求路径的微服务名称为小写
      routes:
        - id: payment_routh #payment_routh 路由的id,若不配置,默认是UUID,没有固定规则但要求唯一
          uri: lb://FS-PROVIDER # 动态路由 匹配提供服务的路由地址,达到路由是去服务中心找端口,而不是写死:原理是使用自动集成Ribbon,使用默认配置

Gateway 网关路由配置 – 微服务名称配置

    # 网关配置
    gateway:
      discovery:
        locator:
          enabled: true #使用情况少,不常用(了解) 开启从注册中心动态创建路由的功能,利用微服务进行路由,请求路径前可以添加微服务名称
          lower-case-service-id: true #(了解) 允许请求路径的微服务名称为小写

Gateway 过滤器在这里插入图片描述

在这里插入图片描述
局部过滤器配置
predicates 断言

spring:
  application:
    name: fs-gateway
  cloud:
    # 网关配置
    gateway:
      discovery:
        locator:
          enabled: true #使用情况少,不常用(了解) 开启从注册中心动态创建路由的功能,利用微服务进行路由,请求路径前可以添加微服务名称
          lower-case-service-id: true #(了解) 允许请求路径的微服务名称为小写
      # 路由配置:转发规则
      routes:
        - id: payment_routh #payment_routh 路由的id,若不配置,默认是UUID,没有固定规则但要求唯一
#          uri: http://localhost:8001 # 静态路由 这样配置是死的,不好 匹配后提供服务的路由地址
          uri: lb://FS-PROVIDER # 动态路由 匹配提供服务的路由地址,达到路由是去服务中心找端口,而不是写死:原理是使用自动集成Ribbon,使用默认配置
          filters:
#            下面是官方给定的局部过滤器,我们一般还是使用自定义过滤器
#            - AddRequestParameter=username,xiaofu  # 通过过滤工厂会在匹配的请求头上加上一对请求头参数,名称为username值为xiaofu
          predicates:  # predicates就是为了实现一组匹配规则,让请求过来找到对应的route进行处理
            - Path=/payment/get/** # 断言,路径相匹配的地址 注意Path要大写
#            - Cookie=username,xiaofu #携带cookie访问,断言是否有,有就允许访问,这里写死了 使用cmd命令curl携带cookie测试 curl http://localhost:9527/payment/get/2 --cookie "username=xiaofu"

# 可以配置多个
#        - id: payment_routh02 #payment_routh02 路由的id,没有固定规则但要求唯一
#          uri: http://localhost:8001 #匹配后提供服务的路由地址
#          predicates:
#            - Path=/payment/lb/**   # 断言,路径相匹配的地址

全局过滤器在下面的案列中在这里插入图片描述

使用Gateway

1.导入依耐
2.编写application.yml配置

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

搭建Gateway工程

在这里插入图片描述

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>shangguiguSpringCloud</artifactId>
        <groupId>com.fs</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>fs_gateway_gateway9527</artifactId>

    <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>
<!--        基础配置-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
<!--        test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

</project>
application.yml

配置

  • 路由配置
    • id:自定义服务名称(唯一)
    • uri:请求转发的目的地
      • 静态路由:http://localhost:8080/
      • 动态路由:lb://服务名称
    • predicates:那些请求需要使用该路由配置进行转发
      • Path=/Result/** 依据请求路径来匹配转发的请求
    • filter
      • 可以使用官方定义的过滤器,但一般使用我们自己定义的
server:
  port: 9527

spring:
  application:
    name: fs-gateway
  cloud:
    # 网关配置
    gateway:
      discovery:
        locator:
          enabled: true #使用情况少,不常用(了解) 开启从注册中心动态创建路由的功能,利用微服务进行路由,请求路径前可以添加微服务名称
          lower-case-service-id: true #(了解) 允许请求路径的微服务名称为小写
      # 路由配置:转发规则
      routes:
        - id: payment_routh #payment_routh 路由的id,若不配置,默认是UUID,没有固定规则但要求唯一
#          uri: http://localhost:8001 # 静态路由 这样配置是死的,不好 匹配后提供服务的路由地址
          uri: lb://FS-PROVIDER # 动态路由 匹配提供服务的路由地址,达到路由是去服务中心找端口,而不是写死:原理是使用自动集成Ribbon,使用默认配置
          filters:
#            下面是官方给定的局部过滤器,我们一般还是使用自定义过滤器
#            - AddRequestParameter=username,xiaofu  # 通过过滤工厂会在匹配的请求头上加上一对请求头参数,名称为username值为xiaofu
          predicates:  # predicates就是为了实现一组匹配规则,让请求过来找到对应的route进行处理
            - Path=/payment/get/** # 断言,路径相匹配的地址 注意Path要大写
#            - Cookie=username,xiaofu #携带cookie访问,断言是否有,有就允许访问,这里写死了 使用cmd命令curl携带cookie测试 curl http://localhost:9527/payment/get/2 --cookie "username=xiaofu"

# 可以配置多个
#        - id: payment_routh02 #payment_routh02 路由的id,没有固定规则但要求唯一
#          uri: http://localhost:8001 #匹配后提供服务的路由地址
#          predicates:
#            - Path=/payment/lb/**   # 断言,路径相匹配的地址

eureka:
  instance:
    hostname: fs-gateway-service
    #服务提供者provider,注册进eureka服务列表内
  client:
    service-url:
      register-with-eureka: true # 注册到服务中心
      fetch-register: true # 从注册中心获取注册的服务信息
      defaultZone: http://localhost:7001/eureka #,http://localhost2:7002/eureka,http://localhost3:7003/eureka # 注册中心地址


主启动
package com.fs.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

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

自定义网关过滤器MyGatewayFilter(全局过滤器)

对请求进行功能的增强(认证、设置凭证信息等)

  • 局部过滤器:只对配置的路由进行生效
    • org.springframework.cloud.gateway.filter.factory.过滤器名称GatewayFilterFactory
  • 全局过滤器:所有请求都生效
    • GlobalFilter
    • Ordered指定过滤器执行的顺序,越小越先执行)
package com.fs.springcloud.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;

/*
自定义gateway路由全局过滤器,只需要编码,不需要进行任何配置
    implements GlobalFilter, Ordered需要实现这两个接口
 */
@Component
@Slf4j
public class MyGatewayFilter implements GlobalFilter, Ordered {
    //过滤方法
    //测试http://localhost:9527/payment/get/2?username=xiaofu
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("~~~~~进到了MyGatewayFilter自定义过滤器:"+new Date().getTime());
        //获取请求参数中有没有username
        String username = exchange.getRequest().getQueryParams().getFirst("username");
        //没有就非法
        if (username== null){
            log.info("~~~用户名为null,非法用户~~~~");
            //没有传递用户名,就返回个状态码不能接受的状态码
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);

            return exchange.getResponse().setComplete();
        }

        //放行,向下继续执行
        return chain.filter(exchange);
    }

    /**
     * 过滤器排序
     * @return 数值越低,越先加载
     */
    @Override
    public int getOrder() {
        //加载过滤器顺序,数值越低,越先加载
        return 0;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值