Hystrix使用及原理概述

一、背景

1. 当前问题

一个系统,所有请求共用同一个APP容器(Tomcat/jetty/等),共用一个用户线程池,依赖多个不同的远程服务。

当系统健康时,处理请求的延时较低,服务正常运行;当某个后端依赖项变得延迟,会导致处理该请求的用户线程长时间阻塞。在流量较低时,只会影响请求本身;在高流量的情况下,单个后端依赖项的延迟可能会导致服务的所有用户线程都在阻塞等待。

这个问题不仅导致与该后端依赖项有关的请求没办法被正常处理,还会导致其他请求拿不到所需资源而出现异常,从而导致整个系统都没办法正常运行。

对于上述问题,需要通过手段对故障、延迟进行隔离和管理,以便单个失败的依赖项不会导致整个应用程序或系统崩溃。
soa-1-original.png

soa-2-original.png

soa-3-original.png

2. Hystrix简介

Hystrix是Netflix开源的容错库,旨在处理分布式系统中的故障和延迟。它通过实现断路器模式、请求缓存、请求合并等功能,提供了弹性和可靠的解决方案。Hystrix能够在服务之间进行隔离,当一个服务出现故障时,它可以防止故障的扩散,提高系统的可用性和稳定性。在微服务架构中,一个请求需要调用多个服务是非常常见的,较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阈值(Hystrix是5秒20次)断路器将会被打开。断路打开后,可以避免连锁故障,通过fallback方法快速返回一个值。

3. Hystrix的目标

Hystrix旨在实现以下目标:

  • 保护并控制通过第三方客户端库访问(通常是通过网络)的依赖项的延迟和故障。
  • 阻止复杂分布式系统中的级联故障。
  • 快速失败并快速恢复。
  • 在可能的情况下回退并优雅降级。
  • 启用近乎实时的监控、警报和操作控制。

4. Hystrix的功能

为了实现上述目标,Hystrix提供了以下功能:

  • HystrixCommandHystrixObservableCommand对象包装对所有外部系统(或“依赖项”)的调用,通常在单独的线程中执行
  • 自定义调用依赖项的超时时间
  • 为每个依赖项维护一个小的线程池(或信号量);如果它变满,将要发送到该依赖项的请求立即被拒绝,而不是排队等待
  • 统计成功、失败(客户端抛出的异常)、超时和线程拒绝的数量
  • 可通过手动或自动的方式,开启断路器以停止一段时间内对特定服务的所有请求;当统计的失败率超过阈值,断路器会自动开启
  • 在请求失败、被拒绝、超时或短路时执行fallback逻辑
  • 近实时地监控指标和配置更改

soa-4-isolation-original.png

二、原理介绍

1. Hystrix执行流程

下图展示了通过Hystrix请求远程服务的流程

hystrix-command-flow-chart.png

1.1 创建HystrixCommand/HystrixObservableCommand对象

第1步,创建一个HystrixCommandHystrixObservableCommand包装远程调用依赖的过程。HystrixCommandHystrixObservableCommand的区别后续介绍。

1.2 执行Command

第2步,执行第一步创建的命令Command,可以使用以下四种方式:execute()queue()observe()toObservable(),区别后续介绍

1.3 判断是否有请求缓存

第3步,判断是否有请求缓存,若存在请求缓存则直接将缓存的值返回,请求缓存的用法后续介绍。

1.4 判断是否开启断路

第4步,判断断路器是否开启,开启则不能执行远程调用的操作,直接到第8步;若未开启,则到第5步。第4步的断路器开启与否,是通过第7步的断路器健康值判断的。

1.5 判断线程池/信号量是否已满

第5步,如果与命令关联的线程池和队列(或信号量)已满,那么Hystrix将不会执行该命令,而是立即将流量路由到(8)获取Fallback。第5步的结果会反馈到第7步的断路器健康值中。

1.6 执行远程调用

第6步,执行远程调用的方法。在第1步构造的HystrixCommandHystrixObservableCommand中,会重写HystrixCommand.run()HystrixObservableCommand.construct(),里面执行远程调用过程。

如果执行失败/超时,则会路由到第8步执行fallback方法。

值得注意的是,执行超时时,线程隔离策略下定时器会抛出超时异常,并且通知执行任务的线程中断;信号量隔离策略下,定时器会抛出超时异常,但是执行任务的线程会执行到任务结束。

1.7 计算断路器的健康度

第7步,Hystrix向断路器报告成功、失败、拒绝和超时,断路器维护一组滚动计数器来计算统计数据。

它使用这些统计数据来确定何时应该断路,此时它会拒绝任何后续请求,直到恢复期过去,然后它会让会进入半开状态。在此状态下,下一个请求将尝试调用后端服务。如果该请求成功,断路器会认为服务已经恢复并转回 关闭 状态;如果请求仍然失败,断路器会再次回到 打开 状态,继续进行短路操作。

1.8 获取并执行fallback

第8步,当第4步发现断路器打开、第5步线程池/信号量已满、第6步执行异常/超时,Hystrix就会尝试获取Command中自定义的备用方法getFallback()。建议该方法不依赖任何网络连接,而是从内存缓存或其他静态逻辑中获取。

如果fallback执行异常或者没有重写getFallback()方法,则会抛出异常。

1.9 返回成功的响应

如果执行成功,则会将远程调用的结果返回给调用者。

2. 断路器工作流程

下图展示了HystrixCommand和断路器的交互流程以及断路器的工作流程:

  1. 当执行HystrixCommand时,会调用断路器查询是否允许请求。断路器会查询断路器是否开启,若没开启,直接返回允许请求;若断路器已开启,会判断恢复时间是否已过,已过允许1个请求,未过返回不允许请求。(对应2.1的第4步)
  2. 判断断路器是否开启的方式时,计算时间范围内错误百分比是否超过阈值,如果超过阈值,则返回已开启。
  3. 当执行HystrixCommand之后,会将结果反馈给断路器,以更新断路器的健康度。

circuit-breaker-original.png

3、 隔离策略

Hystrix 使用舱壁模式来隔离依赖关系,并限制对任何单一依赖关系的并发访问。

soa-5-isolation-focused-original.png

3.1 线程池隔离(THREAD)

在此策略中,每个服务调用都在独立的线程中执行。线程隔离可以防止服务调用时间过长,导致其他服务调用受到影响。当一个服务调用超时或发生故障时,它不会影响到其他服务调用。线程隔离可以确保服务之间的独立性,提高系统的稳定性。

request-example-with-latency-640.png

isolation-options-640.png

3.1.1 优势
  • 该应用程序完全不受失控客户端库的影响。给定依赖库的池可以填满,而不会影响应用程序的其余部分。
  • 支持任务排队
  • 支持超时中断
  • 支持异步调用
3.1.2 劣势
  • 线程调用会产生额外的开销
3.1.3 适用场景
  • 对于可能耗时较长、网络延迟较高的外部服务调用。
  • 当需要确保每个命令在独立的线程上运行以防止阻塞主线程。
  • 为了防止故障传播和资源耗尽,需要对每个命令进行严格的资源限制。
  • 能够承受一定的线程创建和销毁的开销,以换取更稳定的系统行为。
  • 适用于处理高负载和突发流量的情况,因为线程池可以帮助稳定系统的整体性能。

3.2 信号量隔离(SEMAPHORE)

信号量隔离是一种基于计数器的轻量级隔离方法,它不创建新的线程。相反,Hystrix 使用一个指定大小的信号量来控制并发访问的数量。一旦达到最大值,任何额外的请求都将被拒绝并触发降级策略。

3.2.1 优势
  • 轻量,无额外开销
3.2.2 劣势
  • 不支持任务排队
  • 不支持超时中断。执行超时,执行线程会继续阻塞,直到底层的网络调用超时
  • 不支持异步调用。实际上还是所有请求共用用户线程,没办法完全隔离。
3.2.3 适用场景
  • 对性能敏感或低延迟要求的应用。
  • 当调用的服务通常是快速响应的,例如查询缓存服务或者内部服务间通信。
  • 调用的依赖服务不需要消耗大量的 CPU 或者 IO 资源。
  • 需要严格控制并发请求的数量,但又不希望引入额外的线程开销。
  • 在某些情况下,可以用于轻量级的微服务之间的一致性保证。

三. 使用介绍

本章节将介绍hystrix提供的原始API、Spring Cloud集成Hystrix的使用

1. Hystrix使用

1.1 依赖

<!-- https://mvnrepository.com/artifact/com.netflix.hystrix/hystrix-core -->
<dependency><groupId>com.netflix.hystrix</groupId><artifactId>hystrix-core</artifactId><version>1.5.18</version>
</dependency>

1.2 Hello World

下面是创建一个HystrixCommand的方式,继承HystrixCommand,泛型为远程调用响应的类型。

构造方法中指定了该命令所属的分组key,Hystrix会基于分组key用于报告、告警、仪表盘、权限控制等,并且在不指定线程池的情况下,会根据这个key命名线程池。(也就是说,相同key共用同一个线程池)

run()方法中,是真正执行远程调用的位置。

public class CommandHelloWorld extends HystrixCommand<String> {private final String name;public CommandHelloWorld(String name) {// 指定命令分组为ExampleGroupsuper(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));this.name = name;}@Overrideprotected String run() {// 真正执行远程调用的位置return "Hello " + name + "!";}
}

执行HystrixCommand,同步等待结果

String s = new CommandHelloWorld("World").execute();

执行HystrixCommand,异步等待结果。

Future<String> fs = new CommandHelloWorld("World").queue();
String s = fs.get();

响应式执行HystrixCommandobserve()HystrixCommand转换为Observable,并通过subscribe()设置订阅者,设置当处理结果、处理异常、出现新元素时的行为。

Observable<String> ho = new CommandHelloWorld("World").observe();
ho.subscribe(new Subscriber<String>() {@Overridepublic void onCompleted() {LOGGER.info("Completed.");}@Overridepublic void onError(Throwable e) {LOGGER.error("Error ", e);}@Overridepublic void onNext(String s) {// 获取结果LOGGER.info("Next {}", s);}
});

HystrixCommand以外,还可以创建一个 HystrixObservableCommand。这是一种专门用于包装 Observables 的 HystrixCommand 版本。HystrixObservableCommand 可以包装发射(emit)多个元素的 Observable,而普通的 HystrixCommands(即使转换为 Observable)也永远不会发射(emit)超过一个元素。

1.3 Fallback

可以通过实现Fallback方法,当执行任务出现超时/异常时优雅地降级,返回一个默认值或用于表示错误的值。

对于HystrixCommand,需要实现getFallback()方法, 当出现失败、超时、线程池/信号量拒绝、断路器开启时,会执行getFallback()方法。对于调用方,最终会收到getFallback()的出参。

public class CommandHelloFailure extends HystrixCommand<String> {private final String name;public CommandHelloFailure(String name) {super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));this.name = name;}@Overrideprotected String run() {throw new RuntimeException("this command always fails");}@Overrideprotected String getFallback() {return "Hello Failure " + name + "!";}
}

在没有实现getFallback()时,HystrixCommand会抛出HystrixRuntimeException给调用方。

无论实现getFallback()与否,只要失败都会在断路器中计入失败。

值得注意的是,如果想在出现错误之后不执行getFallback(),可以抛出HystrixBadRequestException

1.4 Command Key

通过HystrixCommandKey标识HystrixCommand。当不设置是默认为类名getClass().getSimpleName();

public CommandHelloWorld(String name) {super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")).andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld")));this.name = name;
}

1.5 线程池

可以通过HystrixThreadPoolKey指定线程池的名称,否则默认使用HystrixCommandGroupKey

使用HystrixThreadPoolKey而不是单纯使用HystrixCommandGroupKey的原因可能是有一些HystrixCommand确实是在权限或者逻辑功能上是同一个组的,但是需要互相隔离。

    public CommandHelloWorld(String name) {super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")).andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld")).andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));// 指定线程池的名称为HelloWorldPoolthis.name = name;}

1.5 隔离策略

通过以下的方式可以指定隔离策略

protected CommandIsolationStrategy(String name) {super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")).andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD))//.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)));this.name = name;
}

其他参数配置与上述方式基本一致,在此不再赘述

1.6 配置

每个配置参数,有四个优先级,越往后的优先级越高。

1.6.1 代码全局默认值

Hystrix自带的配置参数的默认值

1.6.2 动态配置全局默认值

可修改Java系统参数修改默认值。通过代码设置或者在启动服务时指定

System.setProperty("hystrix.command.default.execution.isolation.strategy", "SEMAPHORE");
java -Dhystrix.command.default.execution.isolation.strategy=SEMAPHORE ...

其中,default 说明是全局默认值

1.6.3 代码设置单体值

即上述几个小节在创建HystrixCommand的设置方式

1.6.4 动态配置单体值

与3.1.7.2一样,通过修改系统参数实现。

System.setProperty("hystrix.command.HystrixCommandKey.execution.isolation.strategy", "THREAD");
java -Dhystrix.command.HystrixCommandKey.execution.isolation.strategy=THREAD ...

其中,HystrixCommandKey修改为HystrixCommand的对应值

更多参数有关的内容,见第4章

2. Spring Cloud使用

本小节将介绍Hystrix在Spring Cloud中如何使用。主要介绍两种方式,Spring Cloud OpenFeign 集成Hystrix、Spring Cloud Netflix Hystrix

2.1 Spring Cloud OpenFeign集成Hystrix

本小节仅介绍简单的使用,若想了解OpenFeign集成Hystrix的原理,可参考源码feign.hystrix.HystrixInvocationHandler(从源码中可以看到,其实就是通过动态代理的方式,用HystrixCommand将FeignClient远程调用的方法包装起来)

2.1.1 依赖

只需引入spring-cloud-starter-openfeign即可。

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

我们点击进spring-cloud-starter-openfeign的pom文件中可以看到它已引入feign-hystrix,它将Hystrix集成到Feign中。

    <dependency><groupId>io.github.openfeign</groupId><artifactId>feign-hystrix</artifactId><version>10.10.1</version><scope>compile</scope></dependency>

(这个依赖不需要单独引)

2.1.2 配置

首先,划重点,配置必须开启feign-hystrix,否则hystrix默认是不开启的。详见OpenFeign源码org.springframework.cloud.openfeign.FeignClientsConfiguration.HystrixFeignConfiguration

feign:hystrix:enabled: true

其次,如果需要修改Hystrix的配置参数,可通过修改配置实现。比如,修改默认隔离策略:

hystrix:command:default:execution:isolation:strategy: THREAD

key和value与Hystrix原生的保持一致,详见第4章。

需要说明的是,feignClient的每一个方法都是一个HystrixCommand,HystrixCommandKey为简单类名#方法名(字段类型...)

比如说下面的FeignClientrunsWell的HystrixCommandKey为HystrixService#runsWell(Integer)runs的HystrixCommandKey为HystrixService#runs()

因此,根据第4章介绍的配置方法,如果想细粒度地修改指定的HystrixCommand的配置,需要指定对应的HystrixCommandKey。

hystrix:command:HystrixService#runsWell(Integer):execution:isolation:strategy: SEMAPHOREHystrixService#runs():execution:isolation:strategy: THREAD
@FeignClient(value = "HystrixCommandGroupKey")
public interface ExampleApi {@GetMapping("/hystrix/ok/{id}")String runsWell(@PathVariable("id") Integer id);@GetMapping("/hystrix/ok")String runs();
}

另外,还有一个点值得提一下,@FeignClient上可以通过name/value指定远程RPC的服务,同时会将它作为HystrixCommandGroupKey,也就是说在不特殊配置的情况下,无论创建多少个相同服务的FeignClient,它们都会在同一个分组下,并且会使用相同的线程池。

2.1.3 Fallback

Fallback比较简单,在@FeignClient上指定fallbackFactory,并且实现一个FallbackFactory即可。

@FeignClient(name = "base-cloud-for-biz", url = "${base-cloud.url}",fallbackFactory = BaseCloudClientForBizFallbackFactory.class)
public interface BaseCloudClientForBiz {@PostMapping(path="/api/v2/internal/sendSMSWithoutRegister",produces = MediaType.APPLICATION_JSON_VALUE,consumes = MediaType.APPLICATION_JSON_VALUE)ApiResult sendSmsWithoutRegister(SendSmsWithoutRegisterDto dto);
}
@Slf4j
@Component
public class BaseCloudClientForBizFallbackFactory implements FallbackFactory<BaseCloudClientForBiz> {private static final String ERROR_LOG = "internal service api is unavailable, api = {}, request data : {}.";@Overridepublic BaseCloudClientForBiz create(Throwable throwable) {return new BaseCloudClientForBiz() {@Overridepublic ApiResult sendSmsWithoutRegister(SendSmsWithoutRegisterDto dto) {log.warn(ERROR_LOG, "sendSmsWithoutRegister", dto);return ApiResult.SYSTEM_INTERNAL_ERROR;}};}
}

2.2 Spring Cloud Netflix Hystrix

除了OpenFeign之外,可能还会有其他调用远程依赖的方法,我们可以通过spring-cloud-starter-netflix-hystrix 引入Hystrix。它支持我们通过注解的方式实现HystrixCommand的创建、配置。实现原理可参考com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect(简单来说就是通过AOP包装远程调用的方法)

2.2.1 依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.2.2 启动

需要在配置类上加上注解EnableHystrix

@EnableHystrix
public class Application {
}
2.2.3 使用及配置

使用比较简单,在方法上添加注解@HystrixCommand即可

  @HystrixCommand(fallbackMethod = "exampleFallback",commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")})@GetMapping("/example")public String example() {return "";}public String exampleFallback() {return "";}

可以看出,字段与3.1的用法基本相同

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HystrixCommand {String groupKey() default "";String commandKey() default "";String threadPoolKey() default "";String fallbackMethod() default "";HystrixProperty[] commandProperties() default {};HystrixProperty[] threadPoolProperties() default {};Class<? extends Throwable>[] ignoreExceptions() default {};ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER;HystrixException[] raiseHystrixExceptions() default {};String defaultFallback() default "";
}

四、参数配置

1. Execution

配置参数名默认值备注
隔离策略hystrix.command.default.execution.isolation.strategy hystrix.command.HystrixCommandKey.execution.isolation.strategyTHREAD可选:THREAD, SEMAPHORE
命令执行超时时间(毫秒)hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds hystrix.command.HystrixCommandKey.execution.isolation.thread.timeoutInMilliseconds1000execution.timeout.enabled=true生效
执行超时开关hystrix.command.default.execution.timeout.enabled hystrix.command.HystrixCommandKey.execution.timeout.enabledtrue
超时中断开关hystrix.command.default.execution.isolation.thread.interruptOnTimeout hystrix.command.HystrixCommandKey.execution.isolation.thread.interruptOnTimeouttrue
信号量最高并发请求数hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests hystrix.command.HystrixCommandKey.execution.isolation.semaphore.maxConcurrentRequests10

2. Fallback

配置参数名默认值备注
fallback开关hystrix.command.default.fallback.enabled hystrix.command.HystrixCommandKey.fallback.enabledtrue

3. Circuit Breaker

配置参数名默认值备注
断路器开关hystrix.command.default.circuitBreaker.enabled hystrix.command.HystrixCommandKey.circuitBreaker.enabledtrue
断路最小阈值hystrix.command.default.circuitBreaker.requestVolumeThreshold hystrix.command.HystrixCommandKey.circuitBreaker.requestVolumeThreshold20只有滑动时间窗口内的请求数超过阈值,才会有机会触发断路
断路睡眠时间(毫秒)hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds hystrix.command.HystrixCommandKey.circuitBreaker.sleepWindowInMilliseconds5000断路之后的睡眠时长,在此时间内拒绝任何请求
断路错误率阈值hystrix.command.default.circuitBreaker.errorThresholdPercentage hystrix.command.HystrixCommandKey.circuitBreaker.errorThresholdPercentage50错误率超过阈值触发断路

4. Metrics

配置参数名默认值备注
滑动统计时间长度(毫秒)hystrix.command.default.metrics.rollingStats.timeInMilliseconds hystrix.command.HystrixCommandKey.metrics.rollingStats.timeInMilliseconds10000
滑动统计桶数量hystrix.command.default.metrics.rollingStats.numBuckets hystrix.command.HystrixCommandKey.metrics.rollingStats.numBuckets10注意:timeInMilliseconds%numBuckets必须等于0
统计延迟开关hystrix.command.default.metrics.rollingPercentile.enabled hystrix.command.HystrixCommandKey.metrics.rollingPercentile.enabledtrue若设置为false,则延迟的情况进行统计

5. Thread Pool

配置参数名默认值备注
线程池核心线程数hystrix.threadpool.default.coreSize hystrix.threadpool.HystrixThreadPoolKey.coreSize10
线程池最大线程数hystrix.threadpool.default.maximumSize hystrix.threadpool.HystrixThreadPoolKey.maximumSize10
线程池队列最大长度hystrix.threadpool.default.maxQueueSize hystrix.threadpool.HystrixThreadPoolKey.maxQueueSize-1如果设置-1,则使用SynchronousQueue队列 如果设置正数,则使用LinkedBlockingQueue队列
空闲线程存活时长(分钟)hystrix.threadpool.default.keepAliveTimeMinutes hystrix.threadpool.HystrixThreadPoolKey.keepAliveTimeMinutes1

线程池计算公式:

线程数=最高峰时每秒的请求数量 × 99%命令执行时间 + 喘息空间

thread-configuration-original.png

五、常见模式

1. Fail Fast

public class CommandThatFailsFast extends HystrixCommand<String> {private final boolean throwException;public CommandThatFailsFast(boolean throwException) {super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));this.throwException = throwException;}@Overrideprotected String run() {if (throwException) {throw new RuntimeException("failure from CommandThatFailsFast");} else {return "success";}}

2. Fail Silent

fallback-640.png

public class CommandThatFailsSilently extends HystrixCommand<String> {private final boolean throwException;public CommandThatFailsSilently(boolean throwException) {super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));this.throwException = throwException;}@Overrideprotected String run() {if (throwException) {throw new RuntimeException("failure from CommandThatFailsFast");} else {return "success";}}@Overrideprotected String getFallback() {return null;}
}

3. Fallback: Static

fallback-640.png

    @Overrideprotected Boolean getFallback() {return true;}

4. Fallback via Network

fallback-via-command-original.png

public class CommandWithFallbackViaNetwork extends HystrixCommand<String> {private final int id;protected CommandWithFallbackViaNetwork(int id) {super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceX")).andCommandKey(HystrixCommandKey.Factory.asKey("GetValueCommand")));this.id = id;}@Overrideprotected String run() {//        RemoteServiceXClient.getValue(id);throw new RuntimeException("force failure for example");}@Overrideprotected String getFallback() {return new FallbackViaNetwork(id).execute();}private static class FallbackViaNetwork extends HystrixCommand<String> {private final int id;public FallbackViaNetwork(int id) {super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceX")).andCommandKey(HystrixCommandKey.Factory.asKey("GetValueFallbackCommand"))// use a different threadpool for the fallback command// so saturating the RemoteServiceX pool won't prevent// fallbacks from executing.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("RemoteServiceXFallback")));this.id = id;}@Overrideprotected String run() {MemCacheClient.getValue(id);}@Overrideprotected String getFallback() {// the fallback also failed// so this fallback-of-a-fallback will // fail silently and return nullreturn null;}}
}

5. Primary + Secondary with Fallback

primary-secondary-example-640.png

六、总结

  1. Hystrix是一个用于分布式系统故障隔离和控制的开源库。它通过断路器模式、请求缓存、请求合并等功能,提供了弹性和可靠的解决方案。Hystrix能够保护并控制对远程服务的调用,避免级联故障,并快速失败并快速恢复。
  2. Hystrix支持两种隔离策略,线程池隔离适合远程调用耗时比较长的场景,但会有一定的性能损耗;信号量适合低耗时、对性能敏感的场景,缺点是不支持异步调用、不支持中断。
  3. 可以通过hystrix-core使用原生的Hystrix,也可以通过Spring Cloud OpenFeign或者Spring Cloud Netflix Hystrix使用。
  4. 可以根据实际情况修改Hystrix的配置,可以参考常见的几种模式使用HystrixCommand。

七、参考资料

  • Hystrix Wiki

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/226121.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大模型下开源文档解析工具总结及技术思考

1 基于文档解析工具的方法 pdf解析工具 导图一览&#xff1a; PyPDF2提取txt&#xff1a; import PyPDF2 def extract_text_from_pdf(pdf_path):with open(pdf_path, rb) as file:pdf_reader PyPDF2.PdfFileReader(file)num_pages pdf_reader.numPagestext ""f…

漏洞复现-网神SecGate3600防火墙敏感信息泄露漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…

算法leetcode|92. 反转链表 II(rust重拳出击)

文章目录 92. 反转链表 II&#xff1a;样例 1&#xff1a;样例 2&#xff1a;提示&#xff1a;进阶&#xff1a; 分析&#xff1a;题解&#xff1a;rust&#xff1a;go&#xff1a;c&#xff1a;python&#xff1a;java&#xff1a; 92. 反转链表 II&#xff1a; 给你单链表的…

迈入数据结构殿堂——时间复杂度和空间复杂度

目录 一&#xff0c;算法效率 1.如何衡量一个算法的好坏&#xff1f; 2.算法效率 二&#xff0c;时间复杂度 1.时间复杂度的概念 2.大O的渐进表示法 3.推导大O的渐进表示法 4.常见时间复杂度举例 三&#xff0c;空间复杂度 一&#xff0c;算法效率 数据结构和算法是密…

迅腾文化品牌网络推广助力企业:保持品牌稳定,发展更多消费者信任,提升品牌忠诚度

迅腾文化品牌网络推广助力企业&#xff1a;保持品牌稳定&#xff0c;发展更多消费者信任&#xff0c;提升品牌忠诚度 在当今快速发展的互联网时代&#xff0c;品牌网络推广已经成为企业发展的重要手段。迅腾文化作为专业的品牌网络推广公司&#xff0c;致力于帮助企业实现品牌…

产品经理之如何编写需求PRD文档(医疗HIS项目详细案例模板)

目录 前言 一.需求文档的含义 二.需求文档的作用及目的 三.编写前的准备 四.需求大纲 五.案例模板 前言 继上两篇的可行性分析文档和竞品分析报告&#xff0c;本篇将继续介绍如何编写PRD文档&#xff0c;并且会附上以医疗项目为例的模板 一.需求文档的含义 需求文…

【C语言(十五)】

动态内存管理 一、为什么要有动态内存分配? 我们已经掌握的内存开辟方式有&#xff1a; int val 20 ; // 在栈空间上开辟四个字节 char arr[ 10 ] { 0 }; // 在栈空间上开辟 10 个字节的连续空间 但是上述的开辟空间的方式有两个特点&#xff1a; • 空间开辟大小是固…

camera卷帘快门(Rolling Shutter)与全局快门(Global Shutter)

首先来看一下什么叫快门&#xff1a; 快门是照相机用来控制感光元件有效曝光时间的装置。可以理解为光线要想打到相机传感器上必经的一道门。如果快门关着&#xff0c;那么光线进不去&#xff0c;感光元件就无法曝光&#xff1b;门开了&#xff0c;光线进来了&#xff0c;感光元…

FlinkSQL中的窗口

多维分析 需求&#xff1a;有一张test表&#xff0c;表的字段为&#xff1a;A, B, C, amount, 其中A, B, C为维度字段&#xff0c;求以三个维度任意组合&#xff0c;统计sum(amount) Union方案&#xff1a; A, B, C的任意组合共有8种&#xff0c;分别为&#xff08;A, B,C,AB…

C语言:指针与数组易错辨析

前言&#xff1a; 在学校学习指针和数组的联系时&#xff0c;对指针与数组的结合产生了很大的疑惑&#xff0c;后来不断查找资料&#xff0c;本人对指针与数组的综合有了一定的理解&#xff0c;现进行综合讨论辨析 数组指针&#xff1a; 数组指针&#xff0c;即为指向数组类…

机器学习中数据的特征表示

在实际应用中&#xff0c;数据的类型多种多样&#xff0c;比如文本、音频、图像、视频等。不同类型的数据&#xff0c;其原始特征的空间也不相同。比如一张灰度图像&#xff08;像素数量为 &#x1d437;&#xff09;的特征空间为 [0, 255]&#x1d437;&#xff0c;一个自然语…

深入理解 hash 和 history:网页导航的基础(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

二维差分详解

前言 上一期我们分享了一维差分的使用方法&#xff0c;这一期我们将接着上期的内容带大家了解二位差分的使用方法&#xff0c;话不多说&#xff0c;LET’S GO!&#xff08;上一期链接&#xff09; 二维差分 二维差分我们可以用于对矩阵区间进行多次操作的题。 二维差分我们还…

springAop有哪五种通知类型?可根据图标查看!

Spring AOP的通知类型有以下几种&#xff08;后面是图标变化&#xff09;&#xff1a; 1.Before通知&#xff1a; 在目标方法执行前执行。 上白下红&#xff0c;方法前执行。 2.After通知&#xff1a; 在目标方法执行后&#xff08;无论是否发生异常&#xff09;执行。 图标…

文件操作(一、fgets和fputs、fscanf和fprintf、fread 和 fwrite、fopen和fclose、fgetc和fputc)

目录 一、文件的概念 1. 什么是文件&#xff1f;​ 2. 为什么使用文件&#xff1f;​ 3.分件的分类 3.1 程序文件​ 3.2 数据文件​ 3.3磁盘文件: 3.4设备文件: 4.文件名​ 二、二进制文件和文本文件&#xff1f;​ 文本文件与二进制文件区别 三、流和标准流 3.1流…

记录一下github深度学习的错误

1.[visdom]无法正常启动服务问题解决 在Anaconda命令窗口中&#xff1a; 使用python -m visdom.server启动visdom服务时&#xff0c;卡在&#xff1a; Checking for scripts. Downloading scripts, this may take a little while 无法下载和启动服务。 ERROR&#xff1a;由…

设计模式-策略(Strategy)模式

又被称为政策&#xff08;方针&#xff09;模式策略模式(Strategy Design Pattern)&#xff1a;封装可以互换的行为&#xff0c;并使用委托来决定要使用哪一个策略模式是一种行为设计模式&#xff0c;它能让你定义一系列算法&#xff0c;并将每种算法分别放入独立的类中&#x…

[MySQL]数据库概述

目录 1.什么是数据库 2.数据库分类 2.1关系型数据库 2.2非关系型数据库 1.什么是数据库 我们知道&#xff0c;存储数据可以使用文件来存储。那么为什么我们还要大费周章的去设计和使用数据库呢&#xff1f; 因为文件保存数据有以下几个缺点&#xff1a; 1.文件的安全性不…

浅谈MapReduce

MapReduce是一个抽象的分布式计算模型&#xff0c;主要对键值对进行运算处理。用户需要提供两个自定义函数&#xff1a; map&#xff1a;用于接受输入&#xff0c;并生成中间键值对。reduce&#xff1a;接受map输出的中间键值对集合&#xff0c;进行sorting后进行合并和数据规…

clickhouse函数记录

日期函数 SELECT formatDateTime(create_time,%Y-%m-%d) AS time FROM xx.xx;