SpringCloud-20-Spring Cloud Hystrix客户端服务降级

发布于:2022-12-07 ⋅ 阅读:(483) ⋅ 点赞:(0)

8.5 客户端服务降级

  • 通常情况下,我们都会在客户端进行服务降级,当客户端调用的服务端的服务不可用时,客户端直接进行服务降级处理,避免其线程被长时间、不必要地占用。
  • 沿用microservice-cloud-consumer-dept-openFeign客户端工程,在pom.xml 中添加 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">
    <!--引入父工程pom-->
    <parent>
        <artifactId>spring-cloud-microservice</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>microservice-cloud-consumer-dept-openFeign</artifactId>
    <!--实体类API+web-->
    <dependencies>
        <!--引入公共子模块-->
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>microservice-cloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--devtools 开发工具 这个热部署重启得更快-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--logback -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--springboot-test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--jetty-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <!-- 修改后立即生效,热部署 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
            <version>1.2.8.RELEASE</version>
        </dependency>
        <!--日志-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <!--Spring Cloud Eureka 客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>3.1.3</version>
        </dependency>
        <!--Spring Cloud Ribbon 依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
            <version>3.1.3</version>
        </dependency>
        <dependency>
            <groupId>com.netflix.ribbon</groupId>
            <artifactId>ribbon-loadbalancer</artifactId>
            <version>2.7.18</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-ribbon</artifactId>
            <version>2.2.10.RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <!--hystrix 依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>2.2.10.RELEASE</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
  • 在 microservice-cloud-consumer-dept-openFeign 的 application.yml 中添加以下配置,开启客户端的 Hystrix 功能。
feign:
 circuitbreaker:
   enabled: true
  • 在 com.example.service包下,创建一个名为 DeptHystrixService 的服务绑定接口,与 microservice-cloud-provider-dept-hystrix-8004中提供的服务接口进行绑定,代码如下。
package com.example.service;

import com.example.config.FeignConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Service
@FeignClient(value = "MICROSERVICECLOUDPROVIDERDEPTHYSTRIX",configuration = FeignConfiguration.class)
public interface DeptHystrixService {

    @GetMapping("/dept/getInfo/Hystrix/200/{id}")
    String dept_200(@PathVariable("id") Integer id);

    @GetMapping("/dept/testTimeOut/Hystrix/{id}")
    String testTimeOut(@PathVariable("id") Integer id);
}
  • 在 com.example.controller 包下创建一个名为 DeptHystrixController的 Controller ,注意超时提示要与服务端进行区分,方便测试。代码如下。
package com.example.controller;

import com.example.service.DeptHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class DeptHystrixController {

    @Autowired
    private DeptHystrixService deptHystrixService;

    @GetMapping("/consumer/dept/getInfo/Hystrix/200/{id}")
    public String dept_200(@PathVariable("id") Integer id) {
        String info = deptHystrixService.dept_200(id);
        log.info(info);
        return "客户端请求"+info;
    }
    //在客户端进行降级
    //超时测试,该服务的响应时间为 3 秒
    @GetMapping("/consumer/dept/testTimeOut/Hystrix/{id}")
    @HystrixCommand(fallbackMethod = "deptTimeoutHandler")
    public String testTimeOut(@PathVariable("id") Integer id){
        String info = deptHystrixService.testTimeOut(id);
        //当Application.yml中没有配置当前端口号,只能使用此方式获取端口
        log.info(info);
        return info;
    }

    // testTimeOut方法的 专用 fallback 方法
    public String deptTimeoutHandler(Integer id){
        log.info("testTimeOut 出错,服务被降级!");
        return "因当前请求testTimeOut超时,客户端服务降级,返回提示信息!当前线程:"+Thread.currentThread().getName()+"请求超时500。ID+"+id;
    }
}
  • 在配置文件 appliction.yml 中添加以下配置,在客户端配置ribbon和hystrix全局和特定方法请求超时的时间。
spring:
  application:
    name: feignServer
server:
  port: 80
  servlet:
    context-path: /
#Jetty specific properties
  jetty:
    threads:
      acceptors: -1                   #Number of acceptor threads to use. When the value is -1, the default, the number of acceptors is derived from the operating environment.
      selectors: -1                   #Number of selector threads to use. When the value is -1, the default, thenumber of selectors is derived from the operating environment.
    max-http-form-post-size: 200000   #Maximum size of the form content in any HTTP post request.

eureka:
  client:
    register-with-eureka: false #false表示不向注册中心注册自己。
    fetch-registry: true #指示此客户端是否应从 eureka 服务器获取 eureka 注册表信息
    service-url: #监控页面地址
      #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #发布的服务注册中心地址,单机
      defaultZone: http://eurekaserver7001.com:7001/eureka/,http://eurekaserver7002.com:7002/eureka/,http://eurekaserver7003.com:7003/eureka/ #集群版 将当前的 Eureka Server 注册到 7003 和 7003 上,形成一组互相注册的 Eureka Server 集群
feign:
  client:
    config:
      ## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
      feignServer:  #feignServer这个服务单独配置超时时间
        connectTimeout: 6000
        readTimeout: 6000
  circuitbreaker:
    enabled: true
ribbon:
  eager-load:
    enabled: true  #关闭懒加载
  # 指的是建立连接后从服务器读取到可用资源所用的时间
  ReadTimeout: 6000
  # 指的是建立连接所用的时间,适用于网络状态正常的情况下,两端连接所用的时间
  ConnectTimeout: 6000
  eureka:
    enabled: false #禁用Eureka
logging:
  level:
    com:
      example:
        service: debug

MICROSERVICECLOUDPROVIDERDEPT:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 7000  #配置请求超时时间
    DeptHystrixService#testTimeOut(Integer):
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000   #配置具体方法超时时间 为 3 秒
  • 在配置文件中设计请求的超时时间时,需要注意以下 2 点:
    • Hystrix 可以来为所有请求(方法)设置超时时间(单位为毫秒),若请求超时则触发全局的回退方法进行处理。
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=mmm
    • Hystrix 还可以为某个特定的服务请求(方法)设置超时时间,格式如下:
hystrix.command.xxx#yyy(zzz).execution.isolation.thread.timeoutInMilliseconds=mmm

格式说明如下:

  • xxx:为包含该服务方法的类的名称(通常为服务绑定接口的名称),例如 DeptHystrixService 接口。
  • yyy:服务方法名,例如 testTimeOut 方法。
  • zzz:方法内的参数类型,例如 Integer、String 等等
  • mmm:要设置的超时时间,单位为毫秒(1 秒 =1000 毫秒)
  • 在 microservice-cloud-consumer-dept-openFeign 的主启动类上,使用 @EnableHystrix 注解开启客户端 Hystrix 功能,代码如下。
package com.example;

import com.example.config.FeignConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.openfeign.EnableFeignClients;

//OpenFeign和Eureka整合以后,容户端可以直接调用用,不用关心服务的IP地址和端口号
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients //开启 OpenFeign 功能
// 如果只有一个服务就可以直接使用@RibbonClient注解,而不需要@RibbonClients。
// name是写服务提供方的服务名     configuration是指定我们上面创建的配置类
@RibbonClients(value = {
        @RibbonClient(name = "MICROSERVICECLOUDPROVIDERDEPT",configuration = FeignConfiguration.class)
})
//@RibbonClient(name = "MICROSERVICECLOUDPROVIDERDEPT",configuration = FeignConfiguration.class)
@EnableHystrix //启用 Hystrix
public class MicroserviceCloudConsumerDeptOpenFeignApplication {

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

}
  • 测试前提是保证服务端请求正常不被降级。所以要修改 microservice-cloud-provider-dept-hystrix-8004 中 DeptServiceImpl的代码,将 dept_timeout_500() 方法的运行时间修改为 4 秒(小于超时时间 5 秒),以,代码如下。
//一旦该方法失败并抛出了异常信息后,会自动调用  @HystrixCommand 注解标注的 fallbackMethod 指定的方法
@HystrixCommand(fallbackMethod = "dept_timeout_handler",
        规定 5 秒钟以内就不报错,正常运行,超过 5 秒就报错,调用指定的方法
        commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000")})
@Override
public String dept_timeout_500(Integer id) {
    try {
        //Thread.sleep(6000);
        TimeUnit.SECONDS.sleep(4);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "服务端当前线程:"+Thread.currentThread().getName()+"请求超时500。ID+"+id;
}
// 当服务出现故障后,调用该方法给出友好提示
    public String dept_timeout_handler(Integer id){
        return "服务端因当前请求超时,服务降级,返回提示信息!当前线程:"+Thread.currentThread().getName()+"请求超时500。ID+"+id;
    }
  • 先测试下服务端dept_timeout_500() 方法是否被降级,重启 microservice-cloud-provider-dept-hystrix-8004 和 microservice-cloud-consumer-dept-openFeign,使用浏览器访问,访问http://127.0.0.1:8004/dept/testTimeOut/Hystrix/1
    在这里插入图片描述
  • 使用浏览器访问“http://localhost/consumer/dept/testTimeOut/Hystrix/1”,结果如下图。
    在这里插入图片描述在这里插入图片描述
  • 修改microservice-cloud-consumer-dept-openFeign的application.yml,将超时方法请求时间改为5 秒
DeptHystrixService#testTimeOut(Integer):
  execution:
    isolation:
      thread:
        timeoutInMilliseconds: 5000   #配置具体方法超时时间 为 5 秒
  • 重启 microservice-cloud-consumer-dept-openFeign,使用浏览器访问,访问http://localhost/consumer/dept/testTimeOut/Hystrix/1
    在这里插入图片描述在这里插入图片描述

  • 由此可见可以正常访问dept_timeout_500方法内的数据,请求并未超时。

下一篇:SpringCloud-21-Hystrix全局降级和解耦降级逻辑

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到