点击下载教程项目代码:netflix_hystrix_demo.zip
@HystrixCommand 是 Netflix Hystrix 框架提供的一个注解,用于标记在 Spring Boot 应用中需要进行熔断器保护的方法。
@HystrixCommand 注解的主要作用如下:
实现熔断器:@HystrixCommand 注解可以为方法添加熔断器功能,当方法调用失败次数达到一定阈值时,熔断器会打开,后续的请求将直接失败,而不会再去调用实际的方法,从而避免了故障的扩散和系统资源的浪费。
提供降级处理:当熔断器打开或者方法执行出现异常时,可以通过指定的降级方法来返回一个默认的结果,保证系统的基本可用性。
隔离资源:可以为不同的方法配置不同的线程池或信号量,实现资源的隔离,避免某个服务的故障影响到其他服务的正常运行。
下面是 @HystrixCommand 注解的源码:
package com.netflix.hystrix.contrib.javanica.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * This annotation used to specify some methods which should be processes as hystrix commands. * 该注解用于指定一些应作为 hystrix 命令处理的方法。 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface HystrixCommand { /** * The command group key is used for grouping together commands such as for reporting, * alerting, dashboards or team/library ownership. * 命令组键用于将命令分组,例如用于报告、警报、仪表盘或团队/库所有权。 * <p/> * default => the runtime class name of annotated method * default => 被注释方法的运行时类名 * * @return group key */ String groupKey() default ""; /** * Hystrix command key. * Hystrix 命令关键字。 * <p/> * default => the name of annotated method. for example: * default => 被注释方法的名称,例如:... * <code> * ... * @HystrixCommand * public User getUserById(...) * ... * the command name will be: 'getUserById' * </code> * * @return command key */ String commandKey() default ""; /** * The thread-pool key is used to represent a * HystrixThreadPool for monitoring, metrics publishing, caching and other such uses. * 线程池关键字用于表示 HystrixThreadPool,以用于监控、指标发布、缓存和其他类似用途。 * @return thread pool key */ String threadPoolKey() default ""; /** * Specifies a method to process fallback logic. * A fallback method should be defined in the same class where is HystrixCommand. * Also a fallback method should have same signature to a method which was invoked as hystrix command. * for example: * 指定处理回退逻辑的方法。回退方法应与 HystrixCommand 定义在同一个类中。 * 此外,回退方法应与作为 hystrix 命令调用的方法具有相同的签名: * <code> * @HystrixCommand(fallbackMethod = "getByIdFallback") * public String getById(String id) {...} * * private String getByIdFallback(String id) {...} * </code> * Also a fallback method can be annotated with {@link HystrixCommand} * <p/> * default => see {@link com.netflix.hystrix.contrib.javanica.command.GenericCommand#getFallback()} * * @return method name */ String fallbackMethod() default ""; /** * Specifies command properties. 指定命令属性。 * * @return command properties */ HystrixProperty[] commandProperties() default {}; /** * Specifies thread pool properties. 指定线程属性。 * * @return thread pool properties */ HystrixProperty[] threadPoolProperties() default {}; /** * Defines exceptions which should be ignored. * Optionally these can be wrapped in HystrixRuntimeException if raiseHystrixExceptions contains RUNTIME_EXCEPTION. * 定义应忽略的异常。 * 如果 raiseHystrixExceptions 包含 RUNTIME_EXCEPTION, * 则可选择用 HystrixRuntimeException 封装这些异常。 * @return exceptions to ignore */ Class<? extends Throwable>[] ignoreExceptions() default {}; /** * Specifies the mode that should be used to execute hystrix observable command. * For more information see {@link ObservableExecutionMode}. * 指定用于执行 hystrix 可观察命令的模式。更多信息,请参阅 ObservableExecutionMode。 * @return observable execution mode */ ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER; /** * When includes RUNTIME_EXCEPTION, any exceptions that are not ignored are wrapped in HystrixRuntimeException. * 当包含 RUNTIME_EXCEPTION 时,任何未被忽略的异常都会封装在 HystrixRuntimeException 中。 * @return exceptions to wrap */ HystrixException[] raiseHystrixExceptions() default {}; /** * Specifies default fallback method for the command. If both {@link #fallbackMethod} and {@link #defaultFallback} * methods are specified then specific one is used. * note: default fallback method cannot have parameters, return type should be compatible with command return type. * 指定命令的默认回退方法。如果同时指定了 fallbackMethod 和 defaultFallback 方法,则使用特定的方法。 * 注意:默认 fallback 方法不能有参数,返回类型应与命令返回类型兼容。 * @return the name of default fallback method */ String defaultFallback() default ""; }
groupKey 主要用于对相关的命令进行分组,这些分组可以帮助在 Hystrix 仪表板等工具中更好地组织和查看相关的命令统计信息。
groupKey 的作用:
(1)资源隔离:有助于 Hystrix 实现资源隔离。Hystrix 通过将不同的命令分组,可以针对不同的组设置不同的线程池或者信号量限制。
(2)统计和监控:在 Hystrix 的监控体系中,groupKey 能够让你更方便地查看和分析相关命令的统计数据。比如在 Hystrix 仪表板上,你可以根据 groupKey 来查看某个组内所有命令的执行次数、失败率、响应时间等统计信息。
示例:
@Service public class UserService { @HystrixCommand(groupKey = "userServiceGroup") public String getUserById(String id) { // 实际调用获取用户信息的逻辑,这里可能是一个RESTful服务调用等 } @HystrixCommand(groupKey = "userServiceGroup") public void updateUser(String id, String newData) { // 实际调用更新用户信息的逻辑 } }
用于标识 Hystrix 命令的唯一键值。如果不指定,默认使用被注解方法的名称作为 commandKey。
commandKey 属性作用:
命令分组和统计:commandKey 主要用于对 Hystrix 命令进行分组和统计。例如,在 Hystrix 的监控和统计界面(如 Hystrix Dashboard)中,相同 commandKey 的命令会被归为一组进行统计分析。这有助于开发者了解特定类型的命令在系统中的执行情况,比如调用次数、成功率、响应时间等指标。
缓存关联:当使用 Hystrix 的缓存功能时,commandKey 也用于关联缓存。如果多个方法具有相同的 commandKey 并且开启了缓存,Hystrix 可以根据这个 commandKey 来缓存和检索结果,提高系统性能。
示例:
@Service public class UserService { @HystrixCommand(commandKey = "getUserByIdKey") public String getUserById() { // 这里是实际的业务逻辑,比如调用另一个微服务或者数据库操作 } }
threadPoolKey 属性用于指定 Hystrix 命令所属的线程池的唯一标识符。它在实现服务隔离等功能方面起着关键作用。
threadPoolKey的作用:
(1)资源隔离:通过为不同的 Hystrix 命令指定不同的 threadPoolKey,可以将这些命令隔离在不同的线程池中。
(2)配置灵活性:每个线程池可以有自己独立的配置。可以根据业务需求,为不同的 threadPoolKey 对应的线程池设置不同的大小(coreSize)、队列大小(maxQueueSize)等参数。
(3)监控和管理:以 threadPoolKey 为单位进行监控和管理。可以很方便地查看每个线程池的运行状态,如线程池的使用率、队列长度、执行任务的统计信息等。
示例:
@Service public class MyService { @HystrixCommand(threadPoolKey = "myServiceThreadPool", fallbackMethod = "fallback") public String callRemoteService() { // 这里是调用远程服务的逻辑,例如通过RestTemplate } public String fallback() { return "Fallback response"; } }
该属性用于指定降级处理的方法名。当被注解的方法执行失败或超时时,会调用该降级方法来返回默认结果。示例:
@Service public class UserService { @HystrixCommand(fallbackMethod = "getUserFallback") public String getUserInfo(String userId) { // } public String getUserFallback(String userId) { return "Fallback user information for " + userId; } }
该属性允许你配置与 Hystrix 命令相关的各种属性。支持如下属性:
execution.isolation.strategy 用于指定隔离策略。它有两种取值:THREAD(线程隔离)和SEMAPHORE(信号量隔离)。
THREAD:为每个命令在单独的线程池中执行,这样可以避免一个长时间运行的命令阻塞整个容器的线程池。
SEMAPHORE:基于计数器限制了同时访问某个资源的并发数。这种策略在调用比较轻量级且执行速度快的场景下比较适用,因为它避免了线程上下文切换的开销。
execution.isolation.thread.timeoutInMilliseconds 用于设置命令执行的超时时间,单位是毫秒。当一个被 @HystrixCommand 注解标记的方法执行时间超过这个设定的时间时,Hystrix 会中断该方法的执行(如果是线程隔离策略),并执行回退(fallback)逻辑。
circuitBreaker.requestVolumeThreshold 定义了在一个滚动窗口中,打开熔断器的最少请求数量。例如,设置为20,意味着在一个统计窗口内,至少要有 20 个请求才能触发熔断器的状态改变。如果请求数量过少,即使部分请求失败,也不会轻易打开熔断器,因为少量的失败可能是偶然情况。
circuitBreaker.errorThresholdPercentage 指定了在一个滚动窗口内,错误请求占总请求数的百分比阈值。当错误率超过这个阈值时,熔断器会从闭合(CLOSED)状态转换为打开(OPEN)状态。例如,设置为50%,如果在一个统计窗口内,失败请求的比例超过 50%,熔断器就会打开,后续的请求会直接执行回退逻辑,而不会真正调用被注解的方法。
circuitBreaker.sleepWindowInMilliseconds 当熔断器处于打开状态后,这个属性定义了经过多少毫秒后,Hystrix 会允许一个请求通过熔断器,去尝试调用真实的服务(此时熔断器处于半开(HALF - OPEN)状态)。
示例:
@Service public class MyService { @HystrixCommand(commandProperties = { // 设置隔离策略为线程隔离 @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"), // 设置超时时间为1500毫秒 @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500"), // 设置熔断器打开的最少请求数量为10 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 设置错误率阈值为40% @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "40"), // 设置熔断器打开后等待尝试的时间为3000毫秒 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "3000") }) public String myMethod() { // } }
threadPoolProperties 属性主要用于配置与 Hystrix 命令关联的线程池的属性。支持如下属性:
coreSize 线程池的核心线程数。核心线程数是线程池能够保持存活的线程数量,即使它们处于空闲状态。
maxQueueSize 线程池的最大队列长度。当线程池中的所有线程都在忙碌,新的任务会被放入队列等待执行。这个属性限制了队列能够容纳的任务数量。
queueSizeRejectionThreshold 这是一个动态调整队列大小的阈值。它允许你在运行时根据实际情况,在队列满之前就开始拒绝任务,以避免队列过度积压导致系统性能下降。
keepAliveTimeMinutes 当线程池中的线程数量超过核心线程数时,多余的线程在空闲状态下能够存活的时间。
示例:
@Service public class MyService { @HystrixCommand( threadPoolProperties = { @HystrixProperty(name = "coreSize", value = "20"), @HystrixProperty(name = "maxQueueSize", value = "100") } ) public String myMethod() { // 这里是实际的业务逻辑,可能是调用其他服务或者执行复杂的计算 } }
该属性用于指定在执行被注解的方法时,哪些异常应该被忽略,而不触发Hystrix的回退逻辑(fallback)。
当一个被@HystrixCommand注解的方法抛出异常时,Hystrix通常会根据配置来决定是否执行回退逻辑。如果抛出的异常在ignoreExceptions属性指定的异常列表中,Hystrix将不会触发回退,而是直接将该异常向上抛出。
示例:
@Service public class MyService { @HystrixCommand(ignoreExceptions = {CustomBusinessException.class}) public String myMethod() { // 业务逻辑代码 } }
该属性用于指定 Hystrix 命令在处理响应式类型(如 Observable 或 Flowable)时的执行模式。
Hystrix 支持两种 observableExecutionMode 执行模式:EAGER 和 LAZY。
EAGER(急切)模式:当设置为 EAGER 模式时,Hystrix 会立即订阅 Observable 或 Flowable。这意味着,一旦方法被调用,Hystrix 就会开始执行底层的逻辑,并且尝试获取数据。
LAZY(延迟)模式:与 EAGER 模式相反,LAZY 模式下 Hystrix 不会立即订阅 Observable 或Flowable。只有当有订阅者(subscriber)真正订阅了 Observable 或 Flowable 时,Hystrix 才会开始执行底层的逻辑并获取数据。
示例:
@Service public class MyService { // 这里设置为EAGER模式,也可以设置为LAZY @HystrixCommand(observableExecutionMode = EAGER) public Observable<String> getData() { // } }
该属性用于定义哪些异常应该被 Hystrix 捕获并触发回退逻辑。通常,当一个被 @HystrixCommand 注解标记的方法抛出异常时,Hystrix 可以根据 raiseHystrixExceptions 的配置来决定是否执行回退方法。
注意:raiseHystrixExceptions 属性的类型是一个 Class<? extends Throwable>[],这意味着它接受一个或多个异常类(这些异常类是 Throwable 的子类)的数组。
示例:
public class MyService { @HystrixCommand( raiseHystrixExceptions = {RemoteException.class, TimeoutException.class}, fallbackMethod = "fallbackMethod" ) public String myServiceMethod() throws RemoteException, TimeoutException { // 这里是实际的服务调用逻辑,可能会抛出RemoteException和TimeoutException } public String fallbackMethod() { // } }
上述示例中,当 myServiceMethod 方法抛出 RemoteException 或者 TimeoutException 时,Hystrix 会捕获这些异常,并触发对应的回退逻辑(如果配置了回退方法的话)。
当被标记的方法执行出现故障(例如,抛出异常、超时等)时,defaultFallback 所指定的方法会被调用,用于提供一个默认的返回值,以防止故障扩散和系统崩溃。
示例:
@Service public class MyService { @HystrixCommand(defaultFallback = "fallbackMethod") public String myServiceMethod() { // 这里可能是一个远程服务调用,比如通过RestTemplate调用其他微服务 // 为了演示,假设这里会抛出一个运行时异常 } public String fallbackMethod() { return "默认的返回值,因为服务调用出错"; } }
在上述示例中,myServiceMethod 方法使用了 @HystrixCommand 注解,并配置了 defaultFallback 属性为 fallbackMethod。当 myServiceMethod 执行过程中出现异常(这里主动抛出了一个RuntimeException)时,fallbackMethod 会被调用,返回一个默认的字符串。
注意:
方法签名要求:defaultFallback 方法的返回值类型必须与被 @HystrixCommand 注解标记的方法的返回值类型一致。
参数问题:defaultFallback 方法通常是无参数的。因为在熔断器触发时,Hystrix 框架很难将原始方法的参数传递给 defaultFallback 方法。
异常处理范围:defaultFallback 方法不会捕获 myServiceMethod 中可能出现的所有异常。例如,如果 myServiceMethod 中有 try-catch 块,并且在 catch 块中没有重新抛出异常,那么defaultFallback 方法不会被触发。