首页 > 其他分享 >熔断、限流、降级 —— SpringCloud Hystrix

熔断、限流、降级 —— SpringCloud Hystrix

时间:2024-09-05 15:26:27浏览次数:9  
标签:降级 调用 服务 String Hystrix SpringCloud 限流 public

概述

Hystrix 为 微服务架构提供了一整套服务隔离、服务熔断和服务降级的解决方案。它是熔断器的一种实现,主要用于解决微服务架构的高可用及服务雪崩等问题

Hystrix 的特性如下:

  • 服务熔断:Hystrix 熔断器就像家中的安全阀一样,一旦某个服务不可用,熔断器就会直接切断该链路上的请求,避免大量的无效请求影响系统稳定,并且熔断器有自我检测和恢复的功能,在服务状态恢复正常后会自动关闭
  • 服务降级:Hystrix 通过 falback 实现服务降级,在需要进行服务降级的类中定义一个 falback 方法,当请求的远程服务出现异常时,可以直接使用 fallback 方法返回异常信息,而不调用远程服务
  • 依赖隔离:Hyslrix 通过线程池和信号量两种方式实现服务之间的依赖隔离,这样即使其中一个服务出现异常,资源迟迟不能释放,也不会影响其他业务线程的正常运行
    • 线程池的隔离策略:Hystrix 线程池的资源隔离为每个依赖的服务都分配一个线程池,每个线程池都处理特定的服务,多个服务之间的线程资源互不影响,以达到资源隔离的目标。当某个依赖服务异常时,只会阻塞这个依赖服务的线程资源,不影响其他依赖服务
    • 信号量的隔离策略:Hystrix 信号量的隔离策略是为每个依赣的服务都分配一个信号量(原子计数器),当请求某个依赖服务时,先判断该服务的信号量值是否超过最大值。如果超过,则直接丢弃并返回错误提示,如果不超过,则在处理请求前执行“信号量+1”的操作,在请求返回后执行“信号量-1”的操作
  • 请求缓存:Hystrix 按照请求参数把请求结果缓存起来,当后面有相同的请求时不会再走完整的调用链流程,而是把上次缓存的结果直接返回,以达到服务快速响应和性能优化的目的。同时,缓存可作为服务降级的数据源,当远程服务不可用时,直接返回缓存数据,对于消费者来说,只是可能获取了过期的数据,这样就优雅地处理了系统异常
  • 请求合井:当微服务需要调用多个远程服务做结果的汇总时,需要使用请求合并。Hystrix 采用异步消息订阅的方式进行请求合并,当应用程序需要请求多个接口时,采用异步调用的方式提交请求,然后订阅返回值,应用程序的业务可以接着执行其他任务而不用阻塞等待,当所有请求都返回时,应用程序会得到一个通知,取出返回值合并即可

Hystrix 服务降级流程

  1. 当有服务请求时,首先会根据注解创建一个 HystrixCommand 指令对象,该对象设置了服务调用失败的场景和调用失败后服务降级的业务逻辑方法
  2. 熔斯器判断状态,当熔断器处于开路状态时,直接调用服务降级的业务逻辑方法返回调用失败的反馈信息
  3. 当熔断器处于半开路或者闭路状态时,服务会进行线程池和信号量等检查如果有可用资源,有则调用正常业务逻辑。如果调用正常业务逻辑成功,则返回成功后的息,如果失败,则调用降级的业务逻辑,进行服务降级
  4. 当熔断器处于半开路或者闭路状态时,如果在当前服务线程池和信号量中无可用资源,则执行服务降级的业务逻辑,返回调用失败的信息
  5. 当熔断器处于半开路状态并且本次服务执行失败时,熔断器会进入开路状态
  6. 当正常业务逻辑处理超时或者出现错误时,HystrixCommand 会执行服务降缓的业务逐辑,返回调用失败的信息
  7. 线程池和信号量的资源检查及正常业务逻辑会将自己的状态和调用结果反馈给监控,监控将服务状态反馈给熔断器,以便熔断器判断熔断状态

Hystrix 应用

Hystrix 的使用主要分为服务熔断、服务降级和服务监控三个方面

在 pom.xml 文件中引入 Hystrix 依赖,其中,spring-cloud-slarter-netflix-hystrix 和 hystrix-javanica 为 Hystrix 服务熔断所需的依赖,spring-cloud-netflix-hystrix-dashboard 为 Hystrix 服务监控所需的依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-eureka</artifactId>
  <version>1.4.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  <version>1.4.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>com.netflix.hystrix</groupId>
  <artifactId>hystrix-javanica</artifactId>
  <version>RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-netflix-hystrix-dashboard</artifactId>
  <version>1.4.6.RELEASE</version>
</dependency>

通过 @EnableHystrix 注解开启对服务熔断的支持,通过 @EnableHystrixDashboard 注解开启对服务监控的支持。注意,Hystrix 一般和服务发现配合使用,这里使 @EnableEurekaClient 开启了对服务发现客户端的支持

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
@EnableHystrixDashboard
public class HystrixServiceApplication {

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

  @Bean
  public IRule ribbonRule() {
    return new RandomRule();
  }

  @Bean
  @LoadBalanced
  public RestTemplate restTemplate() {
    return new RestTemplate();
  }
}

配置 application.properties 文件

#服务名
spring.application.name=hystrix
#服务的端口
server.port=9005
#注册中心的地址
eureka.client.serviceUrl.defaultZone=http://localhost:9001/eureka/
eureka.client.registry-fetch-interval-seconds=30

服务熔断和降级,定义了一个远程调用的方法 hystrixHandler(),并通过 @HystrixCommand(fallbackMethod="exceptionHandler") 在方法上定义了一个服务降级的命令,当远程方法调用失败时,Hystrix 会自动调用 fallbackMethod 来完成服务熔断和降级,这里会调用 exceptionHandler 方法

@Autowired
private RestTemplate restTemplate;

//定义服务降级命令
@HystrixCommand(fallbackMethod = "exceptionHandler")
@RequestMapping(value = "/service/hystrix", method = RequestMethod.GET)
public String hystrixHandler() {
  return restTemplate.getForEntity("http://EUREKA-CLIENT/serviceProducer", String.class).getBody();
}

public String exceptionHandler() {
  return "提供者服务挂了";
}

异步处理

上节中的远程调用请求必须等到网络请求返回结果后,才会执行后面的代码,即阻塞运行。而在实际使用过程中,应用程序常常希望使用非阻塞 IO 来更优雅地实现功能.Hyslrix 为非阻塞 IO 提供了两种实现方式,分别是表示将来式的 Future 和表示回调式的 Callable

1. Future

定义 HystrixCommand

public class CommandFuture extends HystrixCommand<String> {

  private String name;

  private RestTemplate restTemplate;

  public CommandFuture(String name, RestTemplate restTemplate) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
                //1:通过 HystrixCommandKey 工厂定义依赖的名称
                .andCommandKey(HystrixComnandKey.Factory.asKey("HelloWorld"))
                //2:通过 HystrixThreadPoolKey 工厂定义线程池的名称
                .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
    this.name = name;
    this.restTemplate = restTemplate;
  }

  //3:定义远程调用的方法体
  @Override
  protected String run() {
    String result = restTemplate.getForEntity("http://EUREKA-CLIENT/serviceProducer", String.class).getBody();
    return result;
  }

  //4:服务降级的处理逻辑
  @Override
  protected String getFallback() {
    return "远程服务异常";
  }
}

以上代码通过继承 HystrixCommand 定义了一个 CommandFuture 来实现异步请求,其中,正常业务执行的逻辑在覆写的 run() 方法体中被执行,服务降级的方法在 getFallback() 中被执行。需要注意的是,这里使用 andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld")) 实现了使用 HystrixCommandKey 工厂定义依赖的名称,每个 CommandKey 都代表一个依赖抽象,相同的依赖要使用相同的 CommandKey 名称。依赖隔离的本质敦是对相同
CommandKey 的依赖进行离,使用 andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")) 实现了基于 HystrixThreadPoolKey 工厂定义线程池的名称。当对同一业务的依赖进行资源隔离时,使用 CommandGroup 进行区分,但是当对同一依赖进行不同的远程调用时(例如,一个是 Redis 服务,一个是 HTTP 服务),则可以使用 HystrixThreadPoolKey 进行隔离区分

使用 HystrixCommand

@RequeatMapping(value = "/service/hystrix/future", method = RequestMethod.GET)
public String hystrixFutureHandler() throws ExecutionException, InterruptedException {
  //定义基于Future的异步调用,请求会以队列的形式在线程池中被执行
  Future<String> future = new CommandFuture("future", restTemplate).queue();
  return future.get();
}

2. Callable

预定义一个回调任务,Callable 在发出请求后,主线程继续执行,在请求执行完成并返回结果后,Callable 会自动调用回调任务

定义 HystrixObservableCommand

public class CommandObservable extends HystrixObservabCommand<String> {

  private String name;
  private RestTemplate restTemplate;

  public CommandObservable(String nane, RestTemplate restTemplate) {
    
    super(HystrixConmandGroupKey.Factory.asKey("ExampleGroup"));
    this.nane = name;
    this.restTemplate = restTemplate;
  }

  //基于观察者模式的请求发布
  @Override
  protected Observable<String> construct () {
    return Observable.create(new Observable.OnSubscribe<String>() {
      @Override
      public void call(Subscriber<? super String> subscriber) {
        try {
          //执行远程过程调用
          if(!subscriber.isUnsubscribed()) {
            String result = restTemplate.getForEntity("http://EUREKA-CLIENT/serviceProducer", String.class).getBody();
            //将调用结果传递下去
            subscriber.onNext(result):
            subscriber.onCompleted();
          }
        } catch(Exception e) {
          e.printStackTrace();
          subscriber.onError(e);
        }
      }
    }
  } 

  //服务降级的处理逻辑
  @Override
  protected Observable<String> resumeWithFallback() {
    return Observable.create(new Observable.OnSubscribe<String>() {
      @Override
      public void call(Subscriber<? super String> subscriber) {
        try {
          if(!subscriber.isUnsubscribed()) {
            subscriber.onNext("远程服务异常”);
            subscriber.onCompleted();
        } catch (Exception e) {
            subscriber.onError(e);        
        }
      }
    }
  }
}

以上代码定义了名为 CommandObservable 的类,该类继承自 HystrixObservableCommand 接口,并通过覆写 HystrixObservableCommand 接口中的 construct() 实现观察者模式。具体实现为通过 Obsenvable.create() 创建并返回一个 Observable 对象,在创建对象时,通过 new Observable.OnSubscribe() 实现消息的监听和处理。其中,call 方法用于消息的接收和业务的处理,在消息处理完成后通过 subscriber.onNext(result) 将调用结果传递下去,当所有任务都执行完成时通过 subscriber.onCompleted() 将总体执行结果发布出去。resumeWithFallback 方法是服务降级的处理逻辑,当服务出现异常时,通过 subscriber.onNext("远程服务异常") 进行服务熔断和异常消息的发布,实现服务降级处理

使用 HystrixObservableCommand

public String hystrixCallableHandler() throws ExecutionException, InterruptedException {

  List<String> list = new ArrayList<>();

  //定义基于消息订间的异步调用,请求结果会以事件的方式通知
  Observable<String> observable = new CommandObservable("observer", restTemplate).observe();
  //基于观察者模式的清求结果订阅
  observable.subscribe(new Observer<String>() {
    //onCompleted方法在所有请求完成后执行@
    @Override
    public void onCompleted() {
      System.out.println("所有请求已经完成...”);
    }
    @Override
    public void one rror(Throwable throwable) {
      throwable.printStackTrace();
    }
    //订阅调用事件,请求结果汇聚的地方,用集合将返回的结果收集起来
    @Override
    public void onNext(String s) {
      System.out.printin("结果来了...");
      list.add(s);
      return list.toString();
    }
  }
}

以上代码通过 new CommandObservable("observer", restTemplate).observe() 定义了一个实现服务发布的命令。通过调用 abservabe.subscribe() 来实现基于观察者模式的请求结果订阅,其中,订阅的数据结果在 onNext() 中被通知,总体调用结果在 onCompleted() 中被通知。服务处理异常结果在 one rror() 中被通知


Hystrix Dashboard

HystrixDashboard 主要用于实时监控 Hystrix 的各项运行指标。通过 HystrixDashboard 可以查询 Hystrix 的实时信息,用于快速定位和发现问题。Hystrix Dashboard 的使用简单、方便,首先在 pom.xml 文件中加入 spring-cloud-netfix-hystrix-dashboard 依赖,然后使用 @EnableHystrixDashboard 注解开启 Dashboard 功能即可。在服务启动后,在浏览器地址栏中输人 http://127.0.0.1:9005/hystrix,就可以看到监控界面

标签:降级,调用,服务,String,Hystrix,SpringCloud,限流,public
From: https://www.cnblogs.com/Yee-Q/p/18398174

相关文章

  • Nginx中的 限流和屏敝版本号
    server{location/{#应用请求频率限制配置limit_req模块用于限制客户端请求的频率,以防止单一客户端占用过多服务器资源,提升稳定性。#zone=one引用名为"one"的共享内存区域#burst=10允许短时间内突发最多10个请求#nodela......
  • Java中的限流策略:防止系统过载
    Java中的限流策略:防止系统过载大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在高并发的系统中,限流是一个非常重要的策略,它可以帮助我们保护系统不被过多的请求压垮,从而保证系统的稳定性和可用性。在Java中,有多种限流策略可以实现,本文将介绍几种常用......
  • springboot环境+redis实现分布式限流
    分布式限流,依赖redis实现1个按秒限流的限流器,知识点:自定义注解,切面,注解的使用源码1.创建自定义注解RateLimit首先,我们定义一个自定义注解RateLimit,它包含code和limit属性。importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;import......
  • Dubbo学习圣经:从入门到精通 Dubbo3.0 + SpringCloud Alibaba 微服务基础框架
    文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免费赠送:《尼恩Java面试宝典》持续更新+史上最全+面试必备2000页+面试必备+大厂必备+涨薪必备免费赠送:《尼恩技术圣经+高并发系列PDF》,帮你实现技术自由,完成职业升级,薪......
  • SpringCloud-搭建XXL-JOB任务调度平台
    本教程提供了从XXL-JOB平台介绍到具体搭建流程的详细说明,旨在帮助开发者和系统管理员快速理解和部署XXL-JOB任务调度平台。通过SpringCloud集成XXL-JOB任务调度平台,可以使微服务环境中的任务调度更加灵活和高效。整个过程中,调度中心和执行器的正确配置是关键。此外,通过XXL-JOB提供......
  • 使用Redis调用Lua脚本的方式对SpringBoot接口进行限流
    使用Redis调用Lua脚本的方式对SpringBoot接口进行限流使用Redis调用Lua脚本的方式对SpringBoot接口进行限流前言一、步骤1、自定义限流注解Limit.java,用于标注在需要限流的接口上2、编写限流类型枚举类LimitType.java3、编写限流具体实现类LimitAspect.java,通过AOP方式......
  • Java服务端服务限流:Sentinel与Guava RateLimiter的对比
    Java服务端服务限流:Sentinel与GuavaRateLimiter的对比大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在微服务架构中,服务限流是一种重要的保护机制,用于防止系统过载。Sentinel和GuavaRateLimiter是两种流行的限流工具,它们提供了不同的限流策略和实......
  • Java服务端服务熔断:Hystrix与Bulb的比较
    Java服务端服务熔断:Hystrix与Bulb的比较大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在微服务架构中,服务熔断是一种重要的容错机制,用于防止服务故障的蔓延。Hystrix和Bulb是两种流行的服务熔断工具,它们提供了熔断、降级、隔离等功能。本文将探讨Hy......
  • SpringCloud Gateway鉴权
    参考:https://blog.csdn.net/weixin_43296313/article/details/121126811基于从前的项目:https://www.cnblogs.com/xsj1989/p/18350213在网关项目下创建全局过滤器packagecom.xcg.filters;importcom.auth0.jwt.interfaces.Claim;importcom.auth0.jwt.interfaces.DecodedJWT;......
  • 一种优雅的方式整合限流、幂等、防盗刷
    大家在工作中肯定遇到过接口被人狂刷的经历,就算没有经历过,在接口开发的过程中,我们也需要对那些容易被刷的接口或者和会消耗公司金钱相关的接口增加防盗刷功能。例如,发送短信接口以及发送邮件等接口,我看了国内很多产品的短信登录接口,基本上都是做了防盗刷,如果不做的话,一夜之间,也许......