SpringCloud-22-Hystrix全Hystrix服务熔断

8.8 Hystrix服务熔断

  • 熔断机制是对应雪崩效应的一种微服务链路保护机制。

  • 当扇出链路的某个微服务不可用或者响应时间太长时,为了保护系统的整体可用性,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。这种熔断状态不是永久的,在经历了一定的时间后,熔断器会再次检测该微服务是否恢复正常,若服务恢复正常则恢复其调用链路。

  • 熔断状态:在熔断机制中涉及了三种熔断状态:

    • 熔断关闭状态(Closed):当服务访问正常时,熔断器处于关闭状态,服务调用方可以正常地对服务进行调用。
    • 熔断开启状态(Open):默认情况下,在固定时间内接口调用出错比率达到一个阈值(例如 50%),熔断器会进入熔断开启状态。进入熔断状态后,后续对该服务的调用都会被切断,熔断器会执行本地的降级(FallBack)方法。
    • 半熔断状态(Half-Open): 在熔断开启一段时间之后,熔断器会进入半熔断状态。在半熔断状态下,熔断器会尝试恢复服务调用方对服务的调用,允许部分请求调用该服务,并监控其调用成功率。如果成功率达到预期,则说明服务已恢复正常,熔断器进入关闭状态;如果成功率仍旧很低,则重新进入熔断开启状态。
  • 三种熔断状态之间的转化关系如下图:SpringCloud-22-Hystrix全Hystrix服务熔断_第1张图片

  • Hystrix实现熔断机制:在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。

  • Hystrix 实现服务熔断的步骤如下:

    1. 当服务的调用出错率达到或超过 Hystix 规定的比率(默认为 50%)后,熔断器进入熔断开启状态。
    2. 熔断器进入熔断开启状态后,Hystrix 会启动一个休眠时间窗,在这个时间窗内,该服务的降级逻辑会临时充当业务主逻辑,而原来的业务主逻辑不可用。
    3. 当有请求再次调用该服务时,会直接调用降级逻辑快速地返回失败响应,以避免系统雪崩。
    4. 当休眠时间窗到期后,Hystrix 会进入半熔断转态,允许部分请求对服务原来的主业务逻辑进行调用,并监控其调用成功率。
    5. 如果调用成功率达到预期,则说明服务已恢复正常,Hystrix 进入熔断关闭状态,服务原来的主业务逻辑恢复;否则 Hystrix 重新进入熔断开启状态,休眠时间窗口重新计时,继续重复第 2 到第 5 步。
  • 验证下 Hystrix 是如何实现熔断机制的,在microservice-cloud-provider-dept-hystrix-8004 中的 DeptService 接口中添加一个 deptCircuitBreaker() 方法,代码如下。

package com.example.service;

/**
 * @author CNCLUKZK
 * @create 2022/9/20-13:24
 */
public interface DeptService {

    // hystrix 熔断器示例 ok
    String dept_200(Integer id);

    //hystrix 熔断器超时案例
    String dept_timeout_500(Integer id);

    // Hystrix 熔断机制案例
    String deptCircuitBreaker(Integer num);
}
  • 在 DeptService接口的实现类 DeptServiceImpl 添加 deptCircuitBreaker() 的方法实现及其回退方法,代码如下。
package com.example.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.apache.commons.codec.digest.Md5Crypt;
import org.springframework.cloud.commons.util.IdUtils;
import org.springframework.stereotype.Service;
import sun.security.provider.MD5;
import sun.security.rsa.RSASignature;

import java.util.concurrent.TimeUnit;

/**
 * @author CNCLUKZK
 * @create 2022/9/20-13:26
 */
@Service("deptService")
public class DeptServiceImpl implements DeptService{
    @Override
    public String dept_200(Integer id) {
        return "服务端当前线程:"+Thread.currentThread().getName()+"请求处理成功200。ID+"+id;
    }
    //一旦该方法失败并抛出了异常信息后,会自动调用  @HystrixCommand 注解标注的 fallbackMethod 指定的方法
    @HystrixCommand(fallbackMethod = "dept_timeout_handler",
            规定 5 秒钟以内就不报错,正常运行,超过 5 秒就报错,调用指定的方法
            commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000")})
    @Override
    public String dept_timeout_500(Integer id) {
        try {
            //Thread.sleep(6000);
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "服务端当前线程:"+Thread.currentThread().getName()+"请求超时500。ID+"+id;
    }

    //Hystrix 熔断机制案例
    @HystrixCommand(fallbackMethod = "circuitBreakerFallbackMethod",
            规定 5 秒钟以内就不报错,正常运行,超过 5 秒就报错,调用指定的方法
            commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),  //是否开启熔断器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //统计时间窗内请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //休眠时间窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),//在统计时间窗口期以内,请求失败率达到 50% 时进入熔断状态
            @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "1000"),//统计时间窗
    })
    @Override
    public String deptCircuitBreaker(Integer num) {
        if(String.valueOf(num).length() < 6){
            //当传入的 num 位数< 6时,抛出异常,调用降级方法
            throw new RuntimeException("服务端提示,num位数不能少于6位!");
        }
        String apr1 = Md5Crypt.apr1Crypt(String.valueOf(num));
        return Thread.currentThread().getName()+"加密前参数为:"+num+"   加密后值为:"+apr1;
    }

    // 当服务出现故障后,调用该方法给出友好提示
    public String dept_timeout_handler(Integer id){
        return "服务端因当前请求超时,服务降级,返回提示信息!当前线程:"+Thread.currentThread().getName()+"请求超时500。ID+"+id;
    }

    //熔断案例降级方法
    public String circuitBreakerFallbackMethod(Integer num) {
        return "服务端提示,num位数不能少于6位!请稍后重试。num:"+num;
    }
}
  • 在以上代码中,共涉及到了 4 个与 Hystrix 熔断机制相关的重要参数,这 4 个参数的含义如下表。
参数 描述
metrics.rollingStats.timeInMilliseconds 统计时间窗。
circuitBreaker.sleepWindowInMilliseconds 休眠时间窗,熔断开启状态持续一段时间后,熔断器会自动进入半熔断状态,这段时间就被称为休眠窗口期。
circuitBreaker.requestVolumeThreshold 请求总数阀值。 在统计时间窗内,请求总数必须到达一定的数量级,Hystrix 才可能会将熔断器打开进入熔断开启转态,而这个请求数量级就是 请求总数阀值。Hystrix 请求总数阈值默认为 20,这就意味着在统计时间窗内,如果服务调用次数不足 20 次,即使所有的请求都调用出错,熔断器也不会打开。
circuitBreaker.errorThresholdPercentage 错误百分比阈值。 当请求总数在统计时间窗内超过了请求总数阀值,且请求调用出错率超过一定的比例,熔断器才会打开进入熔断开启转态,而这个比例就是错误百分比阈值。错误百分比阈值设置为 50,就表示错误百分比为 50%,如果服务发生了 30 次调用,其中有 15 次发生了错误,即超过了 50% 的错误百分比,这时候将熔断器就会打开。
  • 在 DeptController 中添加一个 circuitBreakerFallbackMethod() 方法对外提供服务,代码如下。
//服务熔断
    @GetMapping("/Hystrix/circuitBreaker/{num}")
    public String circuitBreakerFallbackMethod(@PathVariable("num") Integer num){
        String info = deptService.deptCircuitBreaker(num);
        log.info("request result"+info);
        return "request result"+info;
    }
  • 重启microservice-cloud-provider-dept-hystrix-8004,使用浏览器访问http://127.0.0.1:8004/dept/Hystrix/circuitBreaker/123456,结果如下图。在这里插入图片描述
  • 在microservice-cloud-consumer-dept-openFeign的DeptHystrixService接口中补充circuitBreakerFallbackMethod并实现
@GetMapping("/dept/Hystrix/circuitBreaker/{num}")
String circuitBreakerFallbackMethod(@PathVariable("num") Integer num);
  • DeptHystrixFallBackServiceImpl类中实现
@Override
public String circuitBreakerFallbackMethod(Integer num) {
    return "客户端提示,服务熔断方法执行circuitBreakerFallbackMethod";
}
  • DeptHystrixController中添加服务方法circuitBreakerFallbackMethod
@GetMapping("/consumer/dept/Hystrix/circuitBreaker/{num}")
@HystrixCommand
String circuitBreakerFallbackMethod(@PathVariable("num") Integer num){
    String info = deptHystrixService.circuitBreakerFallbackMethod(num);
    log.info(info);
    return info;
}
  • 重启 microservice-cloud-consumer-dept-openFeign,使用浏览器访问,访问http://localhost/consumer/dept/Hystrix/circuitBreaker/123456结果如下在这里插入图片描述
  • 浏览器多次(调用次数大于请求总数阀值)访问“http://localhost/consumer/dept/Hystrix/circuitBreaker/1234”,使调用出错率大于错误百分比阀值,结果下图。SpringCloud-22-Hystrix全Hystrix服务熔断_第2张图片
  • 重新将参数修改为大于6位的数字(例如参数为 123456),使用浏览器访问“http://localhost/consumer/dept/Hystrix/circuitBreaker/123456”,会发现在熔断开启状态下,即使我们传入的参数已经是6位数,调用的依然降级逻辑。
  • 连续访问“http://localhost/consumer/dept/Hystrix/circuitBreaker/123456”,会发现当服务调用正确率上升到一定的利率后,Hystrix 进入熔断关闭状态。
    在这里插入图片描述

消费方做降级,提供方做熔断,消费方可以判断哪一部分流量大从而降级使得主要功能能运行,服务方能判断哪个服务挂了做措施,如某个时间段某个服务压力大,那么可以服务器某个不重要的服务关闭了,客户端可以执行客户端备用的降级逻辑立刻返回一个友好的提示,以保障主体业务不受影响,这样将那台服务器供应给这个压力大的服务来缓解压力。

  • 服务熔断VS服务降级

服务熔断:服务的某个服务超时或者异常,引起熔断,保险丝
服务降级:客户端从整体网站清求负载考虑,当某个服务熔断或者关闭之后,服务将不再被调用。此时在客户端,我们可以准备一个FallbackFactory或Fallback,返回一个默认的值(缺省)。这样虽然整体的服务水平下降了,但是,好歹能用比直按挂掉强。

下一篇:SpringCloud-23-Hystrix 故障监控

你可能感兴趣的:(SpringCloud,分布式,Hystrix,spring,cloud,hystrix,java)