【SpringCloud(5)】Hystrix断路器:服务雪崩概念;服务降级、服务熔断和服务限流概念;使用Hystrix完成服务降级与服务熔断

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,182元/月
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
云原生网关 MSE Higress,422元/月
简介: 多个微服务之间的调用,结社微服务A调用微服务B和微服务C,微服务B和微服务C有调用其他的微服务,这就是所谓的“扇出”如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所以的 “雪崩效应”

1. Hystrix 是什么?

分布式系统面临的问题:

复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败

1.1 服务雪崩

多个微服务之间的调用,结社微服务A调用微服务B和微服务C,微服务B和微服务C有调用其他的微服务,这就是所谓的“扇出”如果扇出的链路上某个微服务的调用响应时间过长或者不可用对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所以的 “雪崩效应”

对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败糟糕的是,这些应用程序还可能导致服务之间延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理以便单个依赖关系的失败,不能取消整个应用程序或系统

所以,通常当发现一个模块下的某个实例失败后,这时候这个模块依然会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩

1.2 Hystrix

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等。

Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

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

2. Hystrix 重要概念

2.1 服务降级

  • 服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示
  • 哪些情况会触发降级?
    1. 程序运行异常
    2. 超时
    3. 服务熔断触发服务降级
    4. 线程池/信号量打满也会导致服务降级

2.2 服务熔断

  • 类比保险丝。达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示
  • 整体步骤:服务的降级》进而熔断》恢复调用链路

2.3 服务限流

  • 秒杀高并发操作,严禁一窝蜂的拥挤,大家排队,一秒钟N个,有序进行

3. Hystrix 使用

使用hystrix已经可以代替原有的provider和order了

所以两个都可以新建一个模块

在原有基础上添加上Hystrix的jar包

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.10.RELEASE</version>
</dependency>

由于Hystrix已经停更,2.2.10是最后的一个版本

3.1 服务降级

3.1.1 Provider-payment8001

主启动类上需要添加@EnableHystrix注解

@SpringBootApplication(exclude= {
   DataSourceAutoConfiguration.class})
@EnableEurekaClient
@EnableHystrix // 必须开启
public class PaymentHystrixMain8001 {
   
    public static void main(String[] args) {
   
        SpringApplication.run(PaymentHystrixMain8001.class,args);
    }
}

这里可以以service服务实现类来做 服务降级

但结构简单了点,直接用了Impl类

@Service
public class PaymentService {
   
    public String paymentInfo_OK(Integer id){
   
        return "线程池:"+Thread.currentThread().getName()+"——id:"+id;
    }

    /**
     * @HystrixCommand 若是出错、超时等异常情况,返回一个兜底方法
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "peymentInfo_ERROR_Handler",commandKey = "commandKey01")
    public String paymentInfo_ERROR(Integer id){
   
//        int i = 10/0;// 直接异常

        // 超时异常
        try {
   
            TimeUnit.SECONDS.sleep(3000);
        } catch (InterruptedException e) {
   
            e.printStackTrace();
        }
        return "ERROR - 线程池:"+Thread.currentThread().getName()+"——id:"+id;
    }
    /**
        异常回调函数
    */
    public String peymentInfo_ERROR_Handler(Integer id){
   
        return "ERROR - 兜底监听方法 - 线程池:"+Thread.currentThread().getName()+"——id:"+id;
    }
}

@HystrixCommand(fallbackMethod = "peymentInfo_ERROR_Handler",commandKey = "commandKey01")

fallbackMethod 参数值直接是兜底方法的方法名

在需要使用异常回调方法的方法上添加上@HystixCommand注解,即可开启服务降级

@HystrixCommand(fallbackMethod = "peymentInfo_ERROR_Handler",commandKey = "commandKey01")
  • 参数一:fallbackMethod
    • 绑定返回回调函数的名称
  • 参数二:commandKey
    • 绑定该方法的key值

实际上,服务降级光光在provider上使用注解也可以达到服务降级的操作。

而我们也可以在添加order80后,有了转发,也可以在order80中添加服务降级,比provider要更先一步获得异常并捕获

当要设置超时时间时,需要在yaml配置文件中配置时间。老版本中在注解中设置已经无用

## hystrix 设置兜底请求兜底方法的最多超时时间
hystrix:
  command:
    HystrixCommandKey:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1500

3.1.2 order80

在主启动类上,一样要添加@EnableHystrix注解

@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class OrderHystrixMain80 {
   
    public static void main(String[] args) {
   
        SpringApplication.run(OrderHystrixMain80.class,args);
    }

}

一样的转发接口

@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService  {
   
    @GetMapping("/payment/hystrix/ok/{id}")
    public String peymentInfo_OK(@PathVariable("id") Integer id);

    @GetMapping("/payment/hystrix/error/{id}")
    public String peymentInfo_ERROR(@PathVariable("id") Integer id);
}

在控制器内,若是想要开启该控制器内的全部函数都有一个异常回调方法,

那么需要在开启的方法上添加没有参数的@hystrixCommand注解,其二就是在控制器上添加@DefaultProperties(defaultFallback = "paymentDefaultFallBackMethod")注解。

@DefaultProperties注解的参数就是默认的回调函数

@Slf4j
@RestController
@DefaultProperties(defaultFallback = "paymentDefaultFallBackMethod")
public class OrderHystrixController {
   
    @Resource
    private PaymentHystrixService paymentHystrixService;


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

//    @HystrixCommand(fallbackMethod = "peymentInfo_ERROR_Handler_80",commandKey = "commandKey_80")
    @HystrixCommand
    @GetMapping("/consumer/payment/hystrix/error/{id}")
    public String peymentInfo_ERROR(@PathVariable("id") Integer id){
   
        String s = paymentHystrixService.peymentInfo_ERROR(id);
        return s;
    }
    public String peymentInfo_ERROR_Handler_80(@PathVariable("id") Integer id){
   
        return "消费者80的监听兜底方法出现了!!!";
    }

    /**
     * 全局fallback方法
     * @return
     */
    public String paymentDefaultFallBackMethod(){
   
        return "控制器内存在方法或运行异常,执行了默认fallback方法!!";
    }

}

若是还不够,那么可以在转发接口上做点文章。可以在接口类的@FeignClient注解上设置第二个参数:fallback;

@Component
/**
 * fallback = PaymentHystrixFallbackService.class
 *      ———————— 设定该接口只要调用的方法中存在错误异常,都会使用该实现类中的兜底方法
 */
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentHystrixFallbackService.class)
public interface PaymentHystrixService  {
   

    @GetMapping("/payment/hystrix/ok/{id}")
    public String peymentInfo_OK(@PathVariable("id") Integer id);

    @GetMapping("/payment/hystrix/error/{id}")
    public String peymentInfo_ERROR(@PathVariable("id") Integer id);
}

这个参数我们需要一个实现该接口类的service类,来作为我们的异常调用方法

@Component
public class PaymentHystrixFallbackService implements PaymentHystrixService{
   

    @Override
    public String peymentInfo_OK(Integer id) {
   
        return "peymentInfo_OK ______ 执行fallback";
    }

    @Override
    public String peymentInfo_ERROR(Integer id) {
   
        return "peymentInfo_ERROR _______ 执行fallback";
    }
}

这样在接口转发回调时就会被触发

3.2 服务熔断

我们在provider的控制器中,再次添加一个方法

// ============= 服务熔断
@HystrixCommand(fallbackMethod = "paymentCirecuitBreakerFallback",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"),// 失败率达到多少后跳闸
})
public String paymentCirecuitBreaker(@PathVariable("id") Integer id){
   
    if (id<0){
   
        throw new RuntimeException("###########id,不能是负数");
    }
    return Thread.currentThread().getName()+"\t"+"调用成功,流水号"+System.currentTimeMillis();
}
public String paymentCirecuitBreakerFallback(@PathVariable("id") Integer id){
   
    return "id不能是负数————————触发fallback"+id;
}

具体看注解。注解中的commandProperties参数就是配置和熔断的各类内容

3.2.1 熔断总结

@HystrixCommand(fallbackMethod = "paymentCirecuitBreakerFallback",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"),// 失败率达到多少后跳闸
})
public String paymentCirecuitBreaker(@PathVariable("id") Integer id){
   }

设计到断路器的三个重要参数:快照时间窗、请求总数阈值、错误百分比阈值

  1. 快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒
  2. 请求总数阈值:在快照时间内,必须满足请求总数阈值才有资格熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开
  3. 错误百分比阈值:当请求总数在快照时间内超过了阈值,比如发生了30调用,如果在这30次调用中,有15此发生了超时异常,也就是超过了50%的错误百分比,在默认设定50%阈值情况下,这时候就会将断路器打开。

4. Hystrix图形化Dashboard搭建:

Hystrix(图形化)已过时,对应的jar包也已经找不到了。

<!-- 未找到依赖,去maven的jar包仓库中也未找到 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    <version>2.2.10.RELEASE</version>
</dependency>

🥸🏏SpringCloud微服务专栏

  1. 【SpringCloud(1)】初识微服务架构:创建一个简单的微服务;java与Spring与微服务;初入RestTemplate
  2. 【SpringCloud(2)】微服务注册中心:Eureka、Zookeeper;CAP分析;服务注册与服务发现;单机/集群部署Eureka;连接注册中心
  3. 【SpringCloud(3)】Ribbon负载均衡:IRule原理轮询算法;LB负载均衡;loadbalancer和IRule组件;Ribbon和Ngin负载均衡的区别
  4. 【SpringCloud(4)】OpenFeign客户端:OpenFeign服务绑定;调用服务接口;Feign和OpenFeign

💕👉博客专栏

目录
相关文章
|
1月前
|
算法 Java 微服务
【SpringCloud(1)】初识微服务架构:创建一个简单的微服务;java与Spring与微服务;初入RestTemplate
微服务架构是What?? 微服务架构是一种架构模式,它提出将单一应用程序划分为一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。 每个服务允许在其独立的进程中,服务于服务间采用轻量级的通信机制互相协作(通常是Http协议的RESTful API或RPC协议)。 每个服务都围绕着具体业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外应当尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据上下文,选择合适的语言、工具对其进行构建
402 126
|
1月前
|
负载均衡 算法 Java
【SpringCloud(2)】微服务注册中心:Eureka、Zookeeper;CAP分析;服务注册与服务发现;单机/集群部署Eureka;连接注册中心
1. 什么是服务治理? SpringCloud封装了Netfix开发的Eureka模块来实现服务治理 在传统pc的远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册
182 1
|
1月前
|
负载均衡 算法 Java
【SpringCloud(4)】OpenFeign客户端:OpenFeign服务绑定;调用服务接口;Feign和OpenFeign
Feign是一个WebService客户端。使用Feign能让编写WebService客户端更加简单。 它的使用方法是定义一个服务接口然后再上面添加注解。Feign也支持可拔插式的编码器和解码器。SpringCloud对Feign进行了封装,十七支持了SpringMVC标准注解和HttpMessageConverters。 Feign可用于Eureka和Ribbon组合使用以支持负载均衡
589 138
|
1月前
|
负载均衡 算法 Java
【SpringCloud(3)】Ribbon负载均衡:IRule原理轮询算法;LB负载均衡;loadbalancer和IRule组件;Ribbon和Ngin负载均衡的区别
Spring Cloud Ribbon 是基于Netflix Ribbon实现的一套客户端的负载均衡工具 简单地说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时、重试等。就在在配置文件中列出Load Balancer(LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机链接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法
326 136
|
30天前
|
机器学习/深度学习 消息中间件 人工智能
活动邀请丨2025 全球机器学习技术大会
阿里云高级技术专家周礼受邀于 10 月 17 日下午分享议题《Apache RocketMQ x AI:面向异步化 Agent 的事件驱动架构》。
127 19
|
1月前
|
人工智能 运维 Serverless
函数计算 × MSE Nacos : 轻松托管你的 MCP Server
本文将通过一个具体案例,演示如何基于 MCP Python SDK 开发一个标准的 MCP Server,并将其部署至函数计算。在不修改任何业务代码的前提下,通过控制台简单配置,即可实现该服务自动注册至 MSE Nacos 企业版,并支持后续的动态更新与统一管理。
493 40
|
30天前
|
消息中间件 人工智能 Kafka
AI 时代的数据通道:云消息队列 Kafka 的演进与实践
云消息队列 Kafka 版通过在架构创新、性能优化与生态融合等方面的突破性进展,为企业构建实时数据驱动的应用提供了坚实支撑,持续赋能客户业务创新。
286 21
|
1月前
|
存储 Java Linux
【Docker】(2)还在浏览网页寻找Docker命令?本文全面列举与使用Docker里的各个命令!想要什么命令直接从本文拿!
docker有着比VM更少的抽象层 由于Docker不需要Hypervisor实现硬件资源虚拟化,运行在Docker容器上的程序直接使用的都是实际物理机的硬件资源 因此在CPU、内存利用率上Docker将会在效率上有明显优势 docker利用的时宿主机的内核,而不需要加载操作系统OS内核 当新建一个容器时,Docker不需要和虚拟机一样重新加载一个操作系统内核 进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建过程时分钟级别的。 而Docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个Docker容器只需
307 124
|
1月前
|
人工智能 监控 Java
零代码改造 + 全链路追踪!Spring AI 最新可观测性详细解读
Spring AI Alibaba 通过集成 OpenTelemetry 实现可观测性,支持框架原生和无侵入探针两种方式。原生方案依赖 Micrometer 自动埋点,适用于快速接入;无侵入探针基于 LoongSuite 商业版,无需修改代码即可采集标准 OTLP 数据,解决了原生方案扩展性差、调用链易断链等问题。未来将开源无侵入探针方案,整合至 AgentScope Studio,并进一步增强多 Agent 场景下的观测能力。
1205 28
|
30天前
|
人工智能 安全 Serverless
再看 AI 网关:助力 AI 应用创新的关键基础设施
AI 网关作为云产品推出已有半年的时间,这半年的时间里,AI 网关从内核到外在都进行了大量的进化,本文将从 AI 网关的诞生、AI 网关的产品能力、AI 网关的开放生态,以及新推出的 Serverless 版,对其进行一个全面的介绍,期望对正在进行 AI 应用落地的朋友,在 AI 基础设施选型方面提供一些参考。
426 38

热门文章

最新文章