SpringCloud学习3-服务降级

504 阅读7分钟

前言

分布式系统中,由于多个微服务之间互相调用,这就是所谓的扇出。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,就会占用越来越多的系统资源,进而导致系统崩溃。这就是“雪崩效应”。为了处理这种情况,我们需要做服务降级、服务熔断、服务限流等处理

服务断路器

Hystrix

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败。比如超时、异常等。Hystrix能够保证在一个依赖出错的情况下,不会导致整体服务失败,避免出现级联故障,以提高分布式系统的弹性

原理

当某个服务单元发生故障的时候,通过断路器的故障监控,向服务消费方返回一个符合预期的、可处理的备选响应,而不是长时间的等待或者抛出消费方无法处理的异常,这样就保证了服务调用方的线程不会长时间、不必要的被占用,从而避免了故障在分布式系统的蔓延,引起服务雪崩

服务降级fallback

服务器忙,请稍后再试,不让客户端等待,立刻返回一个友好的提示。比如:程序运行异常、超时、服务熔断触发服务降级、线程池满等

服务熔断

请求达到最大访问后,直接拒绝访问,然后调用服务降级的方法

服务限流

秒杀等高并发操作,严禁请求一窝蜂的过来,一秒钟N个,进行排队

服务降级

服务提供方

添加依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!--hystrix依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <!--eureka client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>

业务类

@Service
//针对指定的服务,使用默认的服务降级方法,下面方法启用@HystrixCommand即可
// @DefaultProperties(defaultFallback = "timeoutFallBack")
public class PaymentServiceImpl implements PaymentService {

    @Override
    public String success(Integer id) {
        return Thread.currentThread().getName() + "success: " + id;
    }

    @Override
    @HystrixCommand(fallbackMethod = "timeoutFallBack", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000") // hystrix 调用超时时间
    })
    public String timeout(Integer id) {
        // int i = 10 / 0;
        int time = 2;
        try {
            TimeUnit.SECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return Thread.currentThread().getName() + "暂停(秒):" + time + "timeout: " + id;
    }

    public String timeoutFallBack(Integer id) {
        return "线程:" + Thread.currentThread().getName() + "调用timeout方法出错";
    }
}

主启动类添加启用Hystrix的注解@EnableCircuitBreaker

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

当请求访问业务类的timeout方法时,如果方法调用失败,则会进行服务降级,按照指定的降级方法timeoutFallBack进行调用,返回给预期指定结果,可以指定超时时间等,各种相关设置等

服务消费方

在feign服务消费方进行服务降低处理

添加依赖

<dependencies>
    <!--hystrix-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!--openfeign依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>provided</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.sun.cloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
</dependencies>

修改配置文件application.yml

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

feign:
  hystrix:
    # 开启feign的hystrix服务
    enabled: true

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000  #熔断超时时间
#logging:
#  level:
#    com.sun.cloud.service: debug

ribbon:
  ReadTimeout: 60000  #请求处理的超时时间
  ConnectTimeout: 60000 #请求连接超时时间
  MaxAutoRetries: 0 #对当前实例的重试次数
  MaxAutoRetriesNextServer: 1 #切换实例的重试次数 1

创建openfeign接口

// fallback参数指定默认的降低方法,可以将接口异常和逻辑代码分离开来
@FeignClient(value = "HYSTRIX-PAYMENT-SERVICE", fallback = PaymentFeignFallbackService.class)
public interface PaymentFeignService {

    @GetMapping("/payment/success/{id}")
    public String success(@PathVariable("id") Integer id);

    @GetMapping("/payment/timeout/{id}")
    public String timeout(@PathVariable("id") Integer id);

}

默认的降级方法

@Component
public class PaymentFeignFallbackService implements PaymentFeignService {

    @Override
    public String success(Integer id) {
        return "我是success的fallback方法";
    }
    
    @Override
    public String timeout(Integer id) {
        return "我是timeout的fallback方法";
    }
}

主启动类启用Hystrix

@SpringBootApplication
@EnableFeignClients
// feign中调用Hystrix使用该注解@EnableHystrix
@EnableHystrix
public class FeignHystrixOrderMain80 {
    public static void main(String[] args) {
        SpringApplication.run(FeignHystrixOrderMain80.class, args);
    }
}

服务熔断

熔断机制的概述

熔断机制是应对雪崩效应的一种微服务链路保护机制,当扇出链路的某个微服务出错不可用或响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当服务请求书减少的时候,会自动的抽取某条请求,去重新调用,如果调用恢复正常,则恢复调用链路。

在SpringCloud框架中,使用hystrix实现服务熔断,hystrix会监控微服务的状况,当失败的调用达到某个阈值的时候,服务熔断。缺省的熔断是5秒中20次调用失败,使用@HystrixCommand注解

业务类的熔断配置

@Service
public class PaymentServiceImpl implements PaymentService {
    @HystrixCommand(fallbackMethod = "timeoutFallBack", commandProperties = {
            // 开启断路器
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
            // 请求总数阀值,满足总阀值才有资格熔断
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            // 时间范围
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),
            // 失败率多少后跳闸
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")
    })
    @Override
    public String circuit(Integer id) {
        if(id < 0) {
            throw new RuntimeException("id不能为负数");
        }
        String uuid = UUID.randomUUID().toString();
        return uuid;
    }
}

熔断的类型

  • 1 熔断打开:请求不在调用当前服务,内部设置一般为MTTR(平均故障处理时间),当打开长达导所设时钟则进入半熔断状态
  • 2 熔断关闭:熔断关闭后不会对服务进行熔断
  • 3 熔断半开:部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断

Hystrix DashBoard仪表盘

除了隔离依赖服务的调用之外,Hystrix提供准实时的调用监控,Hystrix DashBoard会持续的记录通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少次成功、失败等。

添加依赖

<dependencies>
    <!--hystrix dashboard-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    </dependency>
    <!--监控-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!--热部署-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

配置文件的修改

server:
  port: 9001

主启动类

@SpringBootApplication
// 启用HystrixDashboard
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {

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

}

注意点

所有需要监听的服务都需要添加如下依赖:

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

在服务提供端主启动类添加监听路径

/**
 * 此配置是为了服务监控而配置,与服务容错本身无观,springCloud 升级之后的坑
 * ServletRegistrationBean因为springboot的默认路径不是/hystrix.stream
 * 只要在自己的项目中配置上下面的servlet即可
 * @return
 */
@Bean
public ServletRegistrationBean getServlet() {
    HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
    registrationBean.setLoadOnStartup(1);
    registrationBean.addUrlMappings("/hystrix.stream");
    registrationBean.setName("HystrixMetricsStreamServlet");
    return registrationBean;
}

访问地址:http://localhost:9001/hystrix
监听地址:http://localhost:8001/hystrix.stream