SpringCloud(三):Hystrix服务降级与熔断

前言

上期SpringCloud(二):服务调用和负载均衡通过Eureka注册中心构建一个简单微服务,并通过RestTemplate进行远程调用。当系统中微服务较多,某些微服务会不可避免出现异常。

雪崩效应

在微服务架构中,服务与服务之间存在相互调用关系。一旦某个微服务发生故障,则依赖该微服务的所有服务都会发生故障,最终导致整个系统瘫痪。

雪崩效应

Hystrix简介

Hystrix实现了断路器,当服务发生故障后会返回给调用者一个响应,而不是长时间等待导致进程一直被占用,减少了故障的蔓延。熔断器工作逻辑如下

在这里插入图片描述

Closed:熔断器开始处于关闭状态,服务正常处理。

Open:检测到一定比例异常时熔断器打开。

Half Open:经过reset timeout时间进入半开状态,此时会尝试放行一部分请求,如果成功处理进入关闭状态。

Hystrix已经不在处于开发状态,但是仍处于维护状态。

Hystrix官网

创建一个Hystrix模块

修改之前创建的cloud-provider-payment模块,使其支持服务降级与熔断。修改pom文件,引入hystirx依赖。

<!--hystrix-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.10.RELEASE</version>
</dependency>

在主启动类上加入@EnableHystrix注解。

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
public class PaymentMainApplication {

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

服务降级、熔断演示

PaymentController中加入用于测试服务降级的方法。

/**
 * 演示服务降级
 * @param id 传入id
 * @return String
 */
@GetMapping("/provider/testFallback/{id}")
public String testFallback(@PathVariable("id") Integer id){
    return paymentService.testFallback(id);
}

新建一个PaymentService接口,定义测试方式,并新建该接口实现类,实现测试方法。

public interface PaymentService {

    String testFallback(Integer id);
}

接口实现如下

@Service
public class PaymentServiceImpl implements PaymentService {

    @Override
    public String testFallback(Integer id) {
        int a = 10 / id;
        return "输入id为:" + id + " 计算结果为:" + a;
    }
}

当业务逻辑出现异常时服务降级会返回一个可以接受的错误结果,阻止异常蔓延。因此要实现服务降级需要定义一个备选方法,用以返回一个可以接受的错误结果。

PaymentService中加入@HystrixCommand注解,定义降级调用方法如下。

@Service
public class PaymentServiceImpl implements PaymentService {

    @Override
    @HystrixCommand(fallbackMethod = "getDefaultResult")
    public String testFallback(Integer id) {
        int a = 10 / id;
        return "输入id为:" + id + " 计算结果为:" + a;
    }

    private String getDefaultResult(Integer id) {
        return "输入id为:" + id + "非法!无法计算结果!";
    }
}

启动 Eureka Server和 cloud-provider-payment。

首先访问其中一个注册中心http://localhost:7001/,可以看到注册中心集群启动,并且payment服务已经注册。

中心
根据定义的逻辑,如果传入id不为0就不会发生异常。首先访问正常地址http://localhost:8001/provider/testFallback/1

正常情况
如果传入id为0会抛出算术异常,这时就会调用服务降级方法。访问错误地址http://localhost:8001/provider/testFallback/0

错误信息

这里显示的是事先定义的服务降级的返回值。

@HystrixCommand注解

该注解常用参数

  • fallbackMethod:指定服务降级处理方法。
  • ignoreExceptions:忽略某些异常,不发生服务降级。
  • commandKey:命令名称,用于区分不同的命令。
  • groupKey:分组名称,Hystrix会根据不同的分组来统计命令的告警及仪表盘信息。
  • threadPoolKey:线程池名称,用于划分线程池。

对于上述案例,如果想要放行算术异常,可以使用ignoreExceptions配置。

@Override
    @HystrixCommand(fallbackMethod = "getDefaultResult",
            ignoreExceptions = ArithmeticException.class)
    public String testFallback(Integer id) {
        int a = 10 / id;
        return "输入id为:" + id + " 计算结果为:" + a;
    }

重启服务后访问http://localhost:8001/provider/testFallback/0

在这里插入图片描述
此时未采用服务降级,而是直接报出内部服务错误异常。

上述例子只能笼统处理一些运行时服务的服务降级,如果想要更细粒度进行服务降级就要配置@HystrixCommand注解的commandProperties属性。要配置该属性需要用到@HystrixProperty注解。

例如如果一个服务运行时间过长,则就算在正常进行我们也对其进行降级。controller层测试接口如下。

/**
 * 演示超时服务降级
 * @return String
 */
@GetMapping("/provider/testTimeout")
public String testTimeout(){
    return paymentService.testTimeout();
}

对应service层处理如下,假设一个服务因为业务繁忙需要处理一秒,但是我们只能等待0.5s,则对该服务进行降级处理,防止该服务长时间占用线程。

@Override
@HystrixCommand(fallbackMethod = "handleTimeout",commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500")
})
public String testTimeout() {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "程序处理完毕!";
}

public String handleTimeout(){
    return "程序长时间无响应,请稍后再试!";
}

访问测试地址http://localhost:8001/provider/testTimeout,看到如下界面

超时
Command属性主要用来控制HystrixCommand命令的行为,它主要分下面的类别:

1、Execution:用来控制HystrixCommand.run()的执行

  • execution.isolation.strategy:该属性用来设置HystrixCommand.run()执行的隔离策略。默认为THREAD。
  • execution.isolation.thread.timeoutInMilliseconds:该属性用来配置HystrixCommand执行的超时时间,单位为毫秒。
  • execution.timeout.enabled:该属性用来配置HystrixCommand.run()的执行是否启用超时时间。默认为true。
  • execution.isolation.thread.interruptOnTimeout:该属性用来配置当HystrixCommand.run()执行超时的时候是否要它中断。
  • execution.isolation.thread.interruptOnCancel:该属性用来配置当HystrixCommand.run()执行取消时是否要它中断。
  • execution.isolation.semaphore.maxConcurrentRequests:当HystrixCommand命令的隔离策略使用信号量时,该属性用来配置信号量的大小。当最大并发请求达到该设置值时,后续的请求将被拒绝。

2、Fallback:用来控制HystrixCommand.getFallback()的执行

  • fallback.isolation.semaphore.maxConcurrentRequests:该属性用来设置从调用线程中允许HystrixCommand.getFallback()方法执行的最大并发请求数。当达到最大并发请求时,后续的请求将会被拒绝并抛出异常。
  • fallback.enabled:该属性用来设置服务降级策略是否启用,默认是true。如果设置为false,当请求失败或者拒绝发生时,将不会调用HystrixCommand.getFallback()来执行服务降级逻辑。

3、Circuit Breaker:用来控制HystrixCircuitBreaker的行为。

  • circuitBreaker.enabled:确定当服务请求命令失败时,是否使用断路器来跟踪其健康指标和熔断请求。默认为true。
  • circuitBreaker.requestVolumeThreshold:用来设置在滚动时间窗中,断路器熔断的最小请求数。例如,默认该值为20的时候,如果滚动时间窗(默认10秒)内仅收到19个请求,即使这19个请求都失败了,断路器也不会打开。
  • circuitBreaker.sleepWindowInMilliseconds:用来设置当断路器打开之后的休眠时间窗。休眠时间窗结束之后,会将断路器设置为“半开”状态,尝试熔断的请求命令,如果依然失败就将断路器继续设置为“打开”状态,如果成功,就设置为“关闭”状态。
  • circuitBreaker.errorThresholdPercentage:该属性用来设置断路器打开的错误百分比条件。默认值为50,表示在滚动时间窗中,在请求值超过requestVolumeThreshold阈值的前提下,如果错误请求数百分比超过50,就把断路器设置为“打开”状态,否则就设置为“关闭”状态。
  • circuitBreaker.forceOpen:该属性默认为false。如果该属性设置为true,断路器将强制进入“打开”状态,它会拒绝所有请求。该属性优于forceClosed属性。
  • circuitBreaker.forceClosed:该属性默认为false。如果该属性设置为true,断路器强制进入“关闭”状态,它会接收所有请求。如果forceOpen属性为true,该属性不生效。

4、Metrics:该属性与HystrixCommand和HystrixObservableCommand执行中捕获的指标相关。

  • metrics.rollingStats.timeInMilliseconds:该属性用来设置滚动时间窗的长度,单位为毫秒。该时间用于断路器判断健康度时需要收集信息的持续时间。断路器在收集指标信息时会根据设置的时间窗长度拆分成多个桶来累计各度量值,每个桶记录了一段时间的采集指标。例如,当为默认值10000毫秒时,断路器默认将其分成10个桶,每个桶记录1000毫秒内的指标信息。
  • metrics.rollingStats.numBuckets:用来设置滚动时间窗统计指标信息时划分“桶”的数量。默认值为10。
  • metrics.rollingPercentile.enabled:用来设置对命令执行延迟是否使用百分位数来跟踪和计算。默认为true,如果设置为false,那么所有的概要统计都将返回-1。
  • metrics.rollingPercentile.timeInMilliseconds:用来设置百分位统计的滚动窗口的持续时间,单位为毫秒。
  • metrics.rollingPercentile.numBuckets:用来设置百分位统计滚动窗口中使用桶的数量。
  • metrics.rollingPercentile.bucketSize:用来设置每个“桶”中保留的最大执行数。
  • metrics.healthSnapshot.intervalInMilliseconds:用来设置采集影响断路器状态的健康快照的间隔等待时间。

5、Request Context:涉及HystrixCommand使用HystrixRequestContext的设置。

  • requestCache.enabled:用来配置是否开启请求缓存。
  • requestLog.enabled:用来设置HystrixCommand的执行和事件是否打印到日志的HystrixRequestLog中。

完整的配置实例

假设某个服务要求5秒内请求次数超过5次异常概率超过60%就打开熔断器,熔断器休眠窗口为5s。建立测试接口如下

@GetMapping("/provider/testProperties/{id}")
public String testProperties(@PathVariable("id") Integer id){
    return paymentService.testProperties(id);
}

service层编码如下

@Override
@HystrixCommand(fallbackMethod = "defaultHandle", commandProperties = {
        @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), // 开始熔断器,默认开启可不写
        @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "5000"), // 时间窗口
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "5"), // 最少请求次数
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), // 异常百分比
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000") // 熔断器休眠窗口
})
public String testProperties(Integer id) {
    int a = 10 / id;
    return "输入id为:" + id + " 计算结果为:" + a;
}

private String defaultHandle(Integer id) {
    return "输入id为:" + id + "非法!无法计算结果!";
}

我们在五秒内发送至少5次请求,其中3次携带id为0造成异常,这时断路器会打开,在之后的5秒无论请求正确与否都会直接进入服务降级。

首先访问正常地址,得到正常结果。

正常
然后修改id为0,在5s内多次发送错误,打开熔断器。

多次异常

熔断器开启,将id设为正常值会发现仍然进行服务降级。

在这里插入图片描述
等待熔断器窗口期过后进入半开状态,如果处理请求仍然异常,则再次进去打开状态,继续等下一个窗口期,如果成功处理则将熔断器关闭。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud Hystrix是一个开源的熔断器框架,它能够帮助开发者有效地处理服务依赖中的延迟和故障。熔断器的主要目的是在出现故障时提供一种优雅的降级机制,以避免整个系统的崩溃。 熔断降级Hystrix中两个重要的概念。 熔断(Circuit Breaker)指的是在服务出现故障或错误率过高时,自动地切换到指定的备用服务或返回事先定义好的错误结果,起到保护系统免受故障传播的影响的作用。当服务不可用或响应时间过长时,熔断器会打开,拒绝后续请求的访问,并尝试通过执行降级逻辑来快速响应客户端。一旦后续请求不再出现故障,熔断器将会进入半开状态,允许少量的请求通过以检测服务是否恢复正常。 降级(Degradation)指的是在系统资源不足或者高访问量时,服务降级会关闭一些不重要的功能,以保证系统核心功能的可用性和稳定性。降级可以通过阻止非必要的调用、减少资源的消耗以及返回默认值或缓存结果来实现。降级需要提前定义好一些备用的逻辑,一旦系统资源紧张,就可以立即启用降级逻辑来保障系统的可用性。 总而言之,熔断降级都是为了保护系统免受故障的影响。熔断主要是针对服务故障和错误率过高的情况,通过切换到备用服务或返回错误结果来保护系统。降级主要是在系统资源紧张或高访问量的情况下,关闭一些不重要的功能来保证核心功能的可用性和稳定性。两者都是通过提前定义备用逻辑来保障系统的正常运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值