探讨断路器模式

依赖隔离,Docker实现进程隔离,使得容器之间互不影响,而Hystrix,使用的是该模式线程池的隔离,

会为每个HystrixCommand,创建一个独立的线程池,这样就算某个HystrixCommand,都装下了依赖服务,

出现延迟过高的情况,也只是对着该依赖服务的调用产生影响,并不会拖慢其他服务,使用了HystrixCommand,

还将某个函数包装成某个命令时,Hystrix框架就会自动的实现依赖隔离,所以依赖隔离,服务降级,在使用的时候,

都是一体化实现的,这样利用Hystrix来实现,服务容错保护,在编程模型上,非常方便了,除了依赖隔离,服务降级之外,

Hystrix还有一个重要元素,服务熔断

我们先来看看服务的熔断,超时配置我先注释掉,接下来就是熔断了,熔断依旧是使用这个注解,

里面也是Command,commandProperties,这里面怎么配置呢,我们继续打开这个HystrixCommandProperties

com.netflix.hystrix.HystrixCommandProperties

熔断主要是用到这四个

this.circuitBreakerEnabled = getProperty(propertyPrefix, key, "circuitBreaker.enabled", 
builder.getCircuitBreakerEnabled(), default_circuitBreakerEnabled);

this.circuitBreakerRequestVolumeThreshold = getProperty(propertyPrefix, key, 
"circuitBreaker.requestVolumeThreshold", 
builder.getCircuitBreakerRequestVolumeThreshold(), 
default_circuitBreakerRequestVolumeThreshold);

this.circuitBreakerSleepWindowInMilliseconds = getProperty(propertyPrefix, key, 
"circuitBreaker.sleepWindowInMilliseconds", 
builder.getCircuitBreakerSleepWindowInMilliseconds(), 
default_circuitBreakerSleepWindowInMilliseconds);

this.circuitBreakerErrorThresholdPercentage = getProperty(propertyPrefix, key, 
"circuitBreaker.errorThresholdPercentage", 
builder.getCircuitBreakerErrorThresholdPercentage(), 
default_circuitBreakerErrorThresholdPercentage);

这四行的配置,比如第一行好了,我们来看一下他的英文的注释,我们来找到这个circuitBreakerEnabled,这个是他定义的字段

// Whether circuit breaker should be enabled.
private final HystrixProperty<Boolean> circuitBreakerEnabled; 

点进去,这就有了,其实就是这四个

// number of requests that must be made within a statisticalWindow before 
// open/close decisions are made using stats
private final HystrixProperty<Integer> circuitBreakerRequestVolumeThreshold; 

// milliseconds after tripping circuit before allowing retry
private final HystrixProperty<Integer> circuitBreakerSleepWindowInMilliseconds; 

// Whether circuit breaker should be enabled.
private final HystrixProperty<Boolean> circuitBreakerEnabled; 

// % of 'marks' that must be failed to trip the circuit
private final HystrixProperty<Integer> circuitBreakerErrorThresholdPercentage; 

前面四个,我们需要的是前面四个,我们来设置一下

@HystrixCommand(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")
})

第一个我们刚刚也说了,设置熔断,下面三个参数的具体含义,等一下我们细讲,我先设置好,大家可以先观察现象,

这四个我已经设置好了,我们再来试一下

http://localhost:8010/getProductInfoList

已经启动,我们再来访问一下,他一直都是提示太拥挤了,一直都是访问错误,这个我们要怎么来测试呢

@RestController
@DefaultProperties(defaultFallback = "defaultFallback")
public class HystrixController {
 
//    3.
    @HystrixCommand(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")
    })
    @GetMapping("/getProductInfoList")
    public  String getProductInfoList(){
        RestTemplate restTemplate = new RestTemplate();
       return restTemplate.postForObject("http://127.0.0.1:7900/product/listForOrder", 
	   Arrays.asList("157875196366160022"),String.class); 
    } 
	
    private String fallback(){
        return "太拥挤了,请稍后再试~~";
    } 
 
    private String defaultFallback(){
        return "默认提示:太拥挤了,请稍后再试~~";
    }
}

我们不妨这样子来测试它的熔断,这里传一个参数,就叫number,如果他是偶数的话他就去请求,就去请求product的

服务,如果是偶数我们就直接返回成功,否则他就会请求product服务,他一旦请求的话,如果走到这里的话肯定会触发

fallback

return restTemplate.postForObject("http://127.0.0.1:7900/product/listForOrder", 
				    Arrays.asList("157875196366160022"),String.class);
					
因为这是要两秒的等待时间,而我们这边没有设置超时时间,所以这边的超时时间是一秒,重启一下,

http://localhost:8010/getProductInfoList?number=1

再开一个

http://localhost:8010/getProductInfoList?number=2

这个是number等于2,等待他启动好,先来访问一下1,等于1就会触发降级,等于2就是success

这个是success,这个就是一直太拥挤了,我们来让他来产生以下熔断,我不停的刷新这个窗口,我让他错误率达到

60%,那我现在来访问一下这个,神奇吧,你看我继续访问,他就变成success了,你看我再来一次,不停的刷,隔一会就好了,

看一下我们刚才观察的现象,这是我们刚才用到的三个配置,这三个配置你可以看到

有一个共同的词circuitBreaker,英文直译过来,就是断路开关,断路器,断路器本身是电路上的一种开关装置,

我小时候还玩过保险丝,当然不是插着电的时候去玩,不然牛逼就吹大了,当然是取下来之后玩的,电流过大的

时候,还会烧坏保险丝,这个时候你还得手动的去拉一下闸,其实就是跳闸了,我上学那会印象特别深刻,就是在

寝室里面,有同学还在用电脑看片,另外一个同学又是烧水啊,用电吹风什么的,结果电吹风一开呢,好了,整一层

都被他搞跳闸了,人家看片也没法看了,特别扫兴,话有说回来,我们说到电路,对电路本身也是一种保护,你想想

他如果不跳闸的话,那么电流过大,还可能会烧坏电器,所以断路器的作用呢,是及时的切断故障电路,放到Hystrix

里面也是类似的,当某个服务单元,发生故障,类似电器发生短路之后,通过断路器的故障监控,这里就类似于熔断的

保险丝,直接切断原来的主逻辑调用,写过一篇关于断路器的文章,这是链接

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

微服务和分布式里面,容错是必须要考虑的,通常的做法有两种,一种是重试机制,对于预期的短暂的问题,可以使用重试

是可以解决的,第一次不成功我再重试一次,他就成功了,但是对于更长时间解决的问题,你不断尝试也是没有太大意义的,

这个时候你就可以使用断路器模式了,断路器模式是将受保护的服务,封装在一个断路器对象里面,当故障达到一定的值,

断路器将会跳闸,断路器对象返回错误,刚才那篇文章里面就描述了这幅图

非常关键,这幅图描述了断路器状态,状态机有三种状态,close,open,还有half open,close是关闭器的

关闭状态,调用失败次数累计,到了一定的阈值,或者说一定的比例,就会启动熔断机制,open是熔断器打开

状态,此时对服务直接返回错误,但设计了一个时钟选项,默认的时钟,到了这个时间之后,就会进入半熔断

状态,也就是half open,允许定量的服务请求,如果调用都成功,或者一定的比例,则认为恢复了,他就会关闭

熔断器,否则就会认为还没好,又回到熔断器打开状态,这三个参数就是控制熔断器的关键参数

我刚刚特别强调了,设计了一个时钟选项,默认的时钟达到了一定的时间,进入半熔断状态,

那sleepWindow,这个参数,这里面的window,是什么意思呢,很多地方会翻译成时间窗口,断路器是否需要

打开统计一下,请求和错误数据的时候,他其实是有一个范围的,这个时间范围就被称为时间窗口,当断路器打开,

对主逻辑进行熔断之后,Hystrix会启动一个休眠时间窗,在这个时间窗内,降级逻辑临时的成为主逻辑,当休眠时间

窗到期,断路器将进入半开状态,释放到一定的请求到原来的主逻辑上,如果此次正常返回,主逻辑继续闭合,主逻辑恢复,

如果这次请求依然有问题,断路器将继续进入打开状态,休眠时间窗重新计时,我们看第一个参数,这个参数我们设置的

是1万毫秒,也就是10秒,这个休眠时间窗,结束之后,会将断路器设置为half open,尝试熔断请求命令,如果依然失败,

就将断路器依旧设置为打开状态,如果成功就设置为关闭状态,我们再来看第二个参数,这个参数好理解,设置在滚动时间

窗口中,断路器的最少请求数,我们这里设置的是10,最后一个参数,设置断路器打开,错误百分比条件,这里设置的是60,表示在

滚动时间窗口中,如果发生了10次调用,在这10次调用中,有7次发生了异常,那就70%了,那你70%就超过了我的60%了,这个时候

断路器会设置为打开状态,否则就会设置为关闭状态,现在大家明白这三个参数的含义,再回想我们刚才的现象,是不是很容易理解了

呢,其实这里关键就是多了一个半开状态,如果你还是觉得不直观,后续我们会将Hystrix和dashboard面板的使用,被HsytrixCommand

接口调用的情况,会被Hystrix记录下来,然后我们可以在一个dashboard上,在一个可视化的界面上,观察到,因此大家可以记住

熔断三个状态的转换,和这些参数,后续我们到Hystrix的面板上,能更直观的观察到
package com.learn.controller;

import java.util.Arrays;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;

@RestController
@DefaultProperties(defaultFallback = "defaultFallback")
public class HystrixController {
 
    //@HystrixCommand(fallbackMethod = "fallback")
    //2、超时设置
//    @HystrixCommand(commandProperties = {
//            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000") //超时时间设置为3秒
//    })
//    3.
    @HystrixCommand(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")
    })
//    @HystrixCommand
    @GetMapping("/getProductInfoList")
    public  String getProductInfoList(@RequestParam("number") Integer number){
//    public  String getProductInfoList(){
        if(number % 2 == 0){
            return  "success";
        }
        RestTemplate restTemplate = new RestTemplate();
       return restTemplate.postForObject("http://127.0.0.1:7900/product/listForOrder", Arrays.asList("157875196366160022"),String.class);
 
    }
 
    private String fallback(){
        return "太拥挤了,请稍后再试~~";
    }
 
 
    private String defaultFallback(){
        return "默认提示:太拥挤了,请稍后再试~~";
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值