SpringCloud-服务降级_服务熔断_服务限流(Hystrix)

 

Hystrix

https://github.com/Netflix/Hystrix/

概述

前言

分布式系统面临的问题

复杂的分布式体系结构的应用 可能有很多个依赖,每个依赖在某些时刻将不可避免的失败;

服务雪崩

 

what

1、Hystrix是一个 处理分布式系统的延迟/容错的 开源库;

2、在分布式系统里,许多依赖不可避免的会调用失败(超时、异常...),Hystrix能保证在一个依赖出现异常的情况下,不会导致服务整体失败,避免级联故障,保证分布式系统的弹性;

3、"断路器"本身是一种开关,当某个服务单元发生故障时,通过断路器的故障检测 向调用方 返回一个符合预期、备选的FallBack,而不是长时间的等待或抛出调用方无法处理的异常;

    这样保证了服务调用方的线程 不会被长时间占用,从而避免故障在分布式系统中蔓延,乃至雪崩;

停更维护怎么办

 

解决

 

 resilience4j、 

Hystrix概念

服务降级

what

当服务不可用时,给调用方的兜底响应;

什么情况会发生服务降级?

程序异常、超时、服务熔断触发服务降级、线程池满

服务熔断

what

当服务达到峰值,直接拒绝访问,给调用方一个兜底响应;

服务限流

what

当服务突然接收到大量请求时,限制单位时间内可处理的数量;

主要的问题

超时导致服务变慢

解决

超时不再继续等待

出错(服务宕机/程序出错)

解决

出错有兜底

解决方案

1、服务提供方超时/运行报错/宕机 -> 调用方不能卡死等待,必须有服务降级;

 

2、服务提供方正常,调用方自己故障/有自己要求(自己等待时间<服务提供方时间) ->  调用方自己服务降级;

How

服务降级

一般服务降级用在 服务调用方;

服务提供方

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


@EnableCircuitBreaker // 开启Hystrix
@EnableEurekaClient
@SpringBootApplication
public class HystrixPaymentStarter8001 {

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

}


@RestController
public class Controller {

    @Autowired
    PaymentService paymentService;

    @HystrixCommand(fallbackMethod = "timeOutFallback", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
    })
    @GetMapping(value = "/hystrix/timeout")
    public String timeout(){
        int i = 1/0;  // 运行报错

        return paymentService.timeout(); // 服务超时
    }

    /**
     * 服务降级 Fallback方法
     * @return
     */
    public String timeOutFallback(){
        return Thread.currentThread().getName() + "payment系统繁忙,请稍后再试!  o(╥﹏╥)o";
    }


}

  

服务调用方 

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

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


#开启Feign的Hystrix
feign:
  hystrix:
    enabled: true


@EnableHystrix // 开启Hystrix
@EnableFeignClients // 开启Feign支持
@SpringBootApplication
public class OpenFeignHystrixOrderStarter80 {

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

}



@RestController
public class OrderController {

    @Autowired
    private PaymentService paymentService;

    @HystrixCommand(fallbackMethod = "timeOutFallback", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
    })
    @GetMapping(value = "/order/timeout")
    public String timeOut(){
        int a = 1/0; // 程序运行报错

        return paymentService.timeOut();
    }

    /**
     * 服务降级 Fallback方法
     * @return
     */
    public String timeOutFallback(){
        return Thread.currentThread().getName() + "由于 payment系统繁忙,请稍后再试!  o(╥﹏╥)o";
    }

}

  

 

全局Fallback

标记@HystrixCommand方法才会进行服务降级:

  有自定义的fallbackMethod,按自定义处理;

  无自定义的fallbackMethod,按全局处理;

 

@DefaultProperties(defaultFallback = "globalFallback")  // 全局fallback定义
@RestController
public class OrderController {

    @Autowired
    private PaymentService paymentService;

    @HystrixCommand  // 全局服务降级
    @GetMapping(value = "/order/ok")
    public String ok(){
        int a = 1/0; // 程序运行报错

        return paymentService.ok();
    }

    @HystrixCommand(fallbackMethod = "timeOutFallback", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
    })
    @GetMapping(value = "/order/timeout")
    public String timeOut(){
        int a = 1/0; // 程序运行报错

        return paymentService.timeOut();
    }

    /**
     * 服务降级 Fallback方法
     * @return
     */
    public String timeOutFallback(){
        return Thread.currentThread().getName() + "由于 payment系统繁忙,请稍后再试!  o(╥﹏╥)o";
    }

    /**
     * 服务降级 globalFallback方法
     * @return
     */
    public String globalFallback(){
        return Thread.currentThread().getName() + "全局Fallback payment系统繁忙,请稍后再试!  o(╥﹏╥)o";
    }

}

  

fallback方法与业务代码解耦 

#开启Feign的Hystrix
feign:
  hystrix:
    enabled: true



@Component
public class PaymentFallbackService implements PaymentService{
    @Override
    public String ok() {
        return "PaymentFallbackService.ok O(∩_∩)O";
    }

    @Override
    public String timeOut() {
        return "PaymentFallbackService.timeOut O(∩_∩)O";
    }
}


@Component
@FeignClient(value = "eureka-hystrix-payment-service", fallback = PaymentFallbackService.class)
public interface PaymentService {

    @GetMapping(value = "/hystrix/ok")
    String ok();

    @GetMapping(value = "/hystrix/timeout")
    String timeOut();

}


@RestController
public class OrderController {

    @Autowired
    private PaymentService paymentService;

    @GetMapping(value = "/order/ok")
    public String ok(){
        return paymentService.ok();
    }

}


@EnableHystrix // 开启Hystrix
@EnableFeignClients // 开启Feign支持
@SpringBootApplication
public class OpenFeignHystrixOrderStarter80 {

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

}

 

服务熔断 

https://martinfowler.com/bliki/CircuitBreaker.html

熔断机制是什么

 

 

应对雪崩效应的 一种微服务链路保护机制;

当扇出链路的某个微服务不可用或响应时间过长,进行服务降级,进而熔断该节点微服务的调用,快速返回错误的响应信息;

当检测到该节点微服务调用正常后,恢复调用链路;

实现

在SpringCloud中,使用Hystrix实现;

Hystrix会监控微服务之间的调用情况,当失败的调用达到一定的阈值,缺省是5秒内20次失败,就会启动熔断机制;

Hystrix服务熔断机制注解 @HystrixCommand;

How

服务降级 -> 服务熔断 -> 恢复服务

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



server:
  port: 8001

spring:
  application:
    name: eureka-hystrix-payment-service

eureka:
  client:
    register-with-eureka: true #是否向注册中心注册自己
    fetchRegistry: true #是否从注册中心抓取已有的注册信息 默认true,集群必须设置为true
    service-url:
      defaultZone: http://localhost:7001/eureka/   #单机版




@EnableCircuitBreaker // 开启Hystrix
@EnableEurekaClient
@SpringBootApplication
public class HystrixPaymentStarter8001 {

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

}





package com.an;

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.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author apy
 * @description
 * @date 2022/8/5 10:57
 */
@RestController
public class Controller {

    // 服务熔断

    @HystrixCommand(fallbackMethod = "circuitBreakerFallback", commandProperties = {
            // 在10s访问时间内,进行10次访问,失败率达到60%后,进行熔断
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),  // 是否开启断路器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),   //  时间窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")    //  失败率达到多少后跳闸
    })
    @GetMapping(value = "/hystrix/circuitBreaker/{id}")
    public String circuitBreaker(@PathVariable(value = "id") Long id){
        if (id < 0){
            throw new IllegalArgumentException("param error");
        }
        return Thread.currentThread().getName() + "success";
    }

    /**
     * 服务降级 Fallback方法
     * @param id
     * @return
     */
    public String circuitBreakerFallback(Long id){
        return "circuitBreakerFallback...id:"+ id;
    }
}

 

熔断类型 

Open

  请求不再调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟进入HalfOpen状态;

  不会调用主逻辑,直接调用降级fallback;

Half Open

  部分请求根据规则调用当前服务,如果请求成功且符合规则,任务当前服务恢复正常,关闭熔断;

Close

  不会对服务进行熔断;

 

服务限流

...

Hystrix工作流程

https://github.com/Netflix/Hystrix/wiki/How-it-Works

Hystrix图形化Dashboard

what

Hystrix还提供了 图形化Dashboard,会持续记录所有通过Hystrix发起的请求的执行信息,并以图形报表的形式展示;

Netflix通过hystrix-metrics-event-stream实现了以上监控;

SpringCloud也整合了Hystrix Dashboard,对监控内容转化为图形化界面;

How

Hystrix Dashboard

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



server:
  port: 9001



@EnableHystrixDashboard
@SpringBootApplication
public class HystrixDashboardStarter9001 {

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

}



http://localhost:9001/hystrix

  

Hystrix Dashboard监控8001微服务

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

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>    被监控的服务必须的依赖 
        </dependency>


@EnableCircuitBreaker // 开启Hystrix
@EnableEurekaClient
@SpringBootApplication
public class HystrixPaymentStarter8001 {

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

    /**
     * 为服务监控而配置,与容错本身无关;
     * @return
     */
    @Bean
    public ServletRegistrationBean getServlet(){

        ServletRegistrationBean bean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        bean.setLoadOnStartup(1);
        bean.addUrlMappings("/hystrix.stream");
        bean.setName("HystrixMetricsStreamServlet");

        return bean;
    }

}

 

 

  

  

posted on 2022-08-04 17:08  anpeiyong  阅读(243)  评论(0编辑  收藏  举报

导航