目录

  • 一、概述
  • (1)服务降级(fallback)
  • (2)服务熔断(break)
  • (3)服务限流(flowlimit)
  • 二、服务降级
  • (1)在服务端启动策略
  • (2)在客户端启用策略
  • (3)全局fallback
  • (4)使用fallbackFactory(常用)
  • 三、服务熔断


一、概述

是一个用于处理分布式系统的延迟和容错的开源库。

断路器:是一种开关装置。当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出无法处理的异常,这样就保证了调用方的线程不会被长时间、不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

(1)服务降级(fallback)

当服务器忙时,不让客户端处于一直等待状态,并立刻返回一个友好提示。

java手写断路器 java断路器概述_ci

(2)服务熔断(break)

服务不可用时,停止对该服务的调用,过一段时间,直到完全恢复服务提供。

java手写断路器 java断路器概述_断路器_02

(3)服务限流(flowlimit)

严禁一窝蜂的过来拥挤,大家排队,一秒钟只允许通过 N 个,有序进行。

二、服务降级

  1. 引入pom
<!-- hystrix -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-hystrix</artifactId>
        </dependency>

(1)在服务端启动策略

  1. 在启动类添加@EnableCircuitBreaker注解
  2. 设置服务降级策略(出错或者大于4秒时进入服务降级策略)
@Service
public class PaymentService {

    /**
     * 成功
     * @param id
     * @return
     */
    public String paymentInfo_OK(Integer id) {
        return "线程池:" + Thread.currentThread().getName() + "   paymentInfo_OK,id:  " + id + "\t" + "好好好";
    }

    /**
     * timeout超时
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler", commandProperties = {
            //4秒钟以内就执行正常的业务逻辑,反之执行降级方法
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "4000")  
    })
    public String paymentInfo_TimeOut(Integer id) { ;
        try {
            TimeUnit.MILLISECONDS.sleep(5000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() + "   paymentInfo_TimeOut,id:  " + id + "\t" + "等等等";
    }

    /**
     * 兜底
     */
    public String paymentInfo_TimeOutHandler(Integer id) {
        return "线程池:" + Thread.currentThread().getName() + "出现错误,请稍后重试" + id + "\t";

    }
}

(2)在客户端启用策略

  1. 主启动类添加@EnableHystrix注解
  2. 修改配置文件
server:
  port: 80

spring:
  application:
    name: cloud-provider-hystrix-order

eureka:
  client:
    register-with-eureka: true    #示表不向注册中心注册自己
    fetch-registry: true   #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

####################以下配置需要新增(ribbon相关配置和Feign超时相关)##################
#全局配置
# 请求连接的超时时间 默认的时间为 1 秒
ribbon:
  ConnectTimeout: 5000
  # 请求处理的超时时间
  ReadTimeout: 5000

# feign 配置
feign:
  hystrix:
    enabled: true

# hystrix 配置
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 60000
  1. controller
@RestController
public class OrderHystrixController {

    @Autowired
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfo_OK(id);
    }

    // 添加服务降级相关配置
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")  //1钟以内就是正常的业务逻辑
    })
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }

    //服务降级方法
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
        return "我是消费者80";
    }

}

(3)全局fallback

  • 添加@DefaultProperties注解
  • 添加@HystrixCommand注解
@RestController
@DefaultProperties(defaultFallback = "paymentTimeOutFallbackMethod")
public class OrderHystrixController {

    @Autowired
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfo_OK(id);
    }

    // 添加服务降级相关配置
    @HystrixCommand
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }

    //全局服务降级方法(不能有参数)
    public String paymentTimeOutFallbackMethod() {
        return "我是,全局服务降级方法";
    }

}

(4)使用fallbackFactory(常用)

服务降级三种实现之一

三、服务熔断

当出现错误或超时时,会首先启动服务降级,当次数达到一定的阈值时,会启动熔断机制(所有请求都不会转发),一段时间后,进入半开状态,让一个请求进行转发,若成功则关闭服务熔断

java手写断路器 java断路器概述_断路器_03

  1. service
@Service
public class PaymentService{

	//服务熔断
    @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",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"), //失败率达到多少后跳闸,此处为60%(上面配置意思是:10秒钟内,10次请求,失败率60%就不让用了)
            // 具体需要配置哪些参数,在 HystrixCommandProperties.java 类中
    })
    public String paymentCircuitBreaker(@PathVariable("id") Integer id){
        if (id < 0){
            throw new RuntimeException("*****id 不能负数");
        }
        String serialNumber = IdUtil.simpleUUID();

        return Thread.currentThread().getName()+"\t"+"调用成功,流水号:"+serialNumber;
    }

	//服务降级
    public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){
        return "id 不能负数,请稍候再试,(┬_┬)/~~     id: " +id;
    }
}
  1. controller
//===服务熔断
    @GetMapping("/payment/circuit/{id}")
    public String paymentCircuitBreaker(@PathVariable("id") Integer id){
        String result = paymentService.paymentCircuitBreaker(id);
        log.info("*******result:"+result);
        return result;
    }
  1. 常用配置
@HystrixCommand(fallbackMethod = "str_fallbackMethod",
    groupKey = "strGroupCommand",
    commandKey = "strCommand",
    threadPoolKey = "strThreadPool",

    commandProperties = {
        //设置执行隔离策略,THREAD 表示线程池   SEMAPHORE:信号量隔离    默认为THREAD线程池
        @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
        // 当隔离策略选择信号池隔离的时候,用来设置信号池的大小(最大并发数)
        @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "10"),
        // 配置命令执行的超时时间
        @HystrixProperty(name = "execution.isolation.thread.timeoutinMilliseconds", value = "10"),
        // 是否启用超时时间
        @HystrixProperty(name = "execution.timeout.enabled", value = "true"),
        // 执行超时的时候是否中断
        @HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout", value = "true"),
        // 执行被取消的时候是否中断
        @HystrixProperty(name = "execution.isolation.thread.interruptOnCancel", value = "true"),
        // 允许回调方法执行的最大并发数
        @HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "10"),
        // 服务降级是否启用,是否执行回调函数
        @HystrixProperty(name = "fallback.enabled", value = "true"),
        // 设置断路器是否起作用。
        @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
        // 该属性用来设置在滚动时间窗中,断路器熔断的最小请求数。例如,默认该值为 20 的时候,
        // 如果滚动时间窗(默认10s)内仅收到了19个请求,及时这19个请求都失败了,断路也不会打开。
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
        // 该属性用来设置在滚动时间窗中,表示在滚动时间窗中,在请求数量超过 circuitBreaker.requestVolumeThreshold 的情况下,
        // 如果错误请求数的百分比超过 50,就把断路器设置为"打开"状态,否则就设置为"关闭"状态
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
        // 该属性用来设置当断路器打开之后的休眠时间窗。休眠时间窗结束之后,会将断路器置为"半开"状态,
        // 尝试熔断的请求命令,如果依然失败就将断路器继续设置为"打开"状态,如果成功就设置为"关闭"状态
        @HystrixProperty(name = "circuitBreaker.sleepWindowinMilliseconds", value = "5000"),
        // 断路器强制打开
        @HystrixProperty(name = "circuitBreaker.forceOpen", value = "false"),
        // 断路器强制关闭
        @HystrixProperty(name = "circuitBreaker.forceClosed", value = "false"),
        // 滚动时间窗设置,该时间用于断路器判断健康度时,需要收集信息的持续时间
        @HystrixProperty(name = "metrics.rollingStats.timeinMilliseconds", value = "10000"),
        // 该属性用来设置滚动时间窗统计指标信息时,划分"桶"的数量,断路器在手机指标信息的时候会根据设置的时间窗长度拆分成多个"桶"来累计各度量值,每个
        // "桶"记录了一段时间内的采集指标。比如 10 秒内拆分成 10 个"桶'收集这样,所以 timeinMilliseconds 必须能被 numBuckets 整除。否则会抛异常
        @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10"),
        // 该属性用来设置对命令执行的延迟是否采用百分位数来跟踪和计算。如果设置为 false,name所有的概要统计都将返回-1
        @HystrixProperty(name = "metrics.rollingPercentile.enabled", value = "false"),
        // 该属性用来设置百分位统计的滚动窗口的持续时间,单位为毫秒
        @HystrixProperty(name = "metrics.rollingPercentile.timeInMilliseconds", value = "60000"),
        // 该属性用来设置百分位统计滚动窗口中使用 "桶" 的数量
        @HystrixProperty(name = "metrics.rollingPercentile.numBuckets", value = "60000"),
        // 该属性用来设置在执行过程中每个"桶"中保留的最大执行次数。如果在滚动时间窗内发生超过该设定值的执行次数
        // 就从最初的位置开始重写。例如,将该值设置为100,滚动窗口为10秒,若在10秒内一个"桶"中发生了500次执行,
        // 那么该"桶"中只保留最后的100次执行的统计。另外,增加该值的大小将会增加内存量的消耗,并增加排序百分位数所需的计算时间
        @HystrixProperty(name = "metrics.rollingPercentile.bucketSize", value = "100"),
        // 该属性用来设置采集意向断路器状态的健康快照(请求的成功、错误百分比)的间隔等待时间
        @HystrixProperty(name = "metrics.healthSnapshot.intervalinMilliseconds", value = "500"),
        // 是否开启请求缓存
        @HystrixProperty(name = "requestCache.enabled", value = "true"),
        // HystrixCommand 的执行和事件是否打印日志到 HystrixRequestLog 中
        @HystrixProperty(name = "requestLog.enabled", value = "true")
    },
    threadPoolProperties = {
        // 该参数用来设置执行命令线程池的核心线程数,该值也就是命令执行的最大并发量
        @HystrixProperty(name = "coreSize", value = "10"),
        // 该参数用来设置线程池的最大队列大小。当设置为 -1 时,线程池将使用 SynchronousQueue 实现的队列,否则将使用 LinkedBlockingQueue 实现的队列
        @HystrixProperty(name = "maxQueueSize", value = "-1"),
        // 该参数用来为队列设置拒绝阈值。通过该参数,即使队列没有达到最大值也能拒绝请求。该参数主要是对 LinkedBlockingQueue 队列的补充,因为LinkedBlockingQueue
        // 队列不能动态修改它的对象大小,而通过该属性就可以调整拒绝请求的队列大小了
        @HystrixProperty(name = "queueSizeRejectionThreshold", value = "5")
    }
)