Spring-cloud source code analysis-basic introduction and configuration attribute description of hystrix

A brief introduction to Hystrix


  • Hystrix is ​​a latency and fault-tolerant library designed to isolate calls to remote systems, services, and third-party libraries, stop failure propagation, and achieve resiliency in complex distributed systems where failures cannot be completely avoided

  • The main role of Hystrix

    • Isolation (thread isolation, semaphore isolation): It is mainly to limit the resources for calling distributed services, so as to avoid the impact on other services when individual services have problems

    • Fuse (fault tolerance): When the failure rate reaches a certain threshold, the fuse triggers a fast failure

    • Downgrade (timeout downgrade, fuse downgrade): When the downgrade is triggered, the callback method can be used to return the backing data

    • Caching: request caching, request merging

    • Real-time monitoring and alarm

  • Source address: https://github.com/Netflix/Hystrix

Spring cloud integrates the basic use of Hystrix


  • Introduce maven dependencies
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
  • Add the annotation @EnableCircuitBreaker or @EnableHystrix to the startup class (this annotation introduces @EnableCircuitBreaker)

  • Add annotations to the methods that need to be downgraded by fuse, and configure downgrade methods

package com.itopener.demo.hystrix.client.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.itopener.framework.ResultMap;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

@Service
public class HystrtixService {
	
	private final Logger logger = LoggerFactory.getLogger(HystrtixService.class);

	/**
	 * @description HystrixCommand注解默认超时时间是1s
	 * 		HystrixCommand注解配置属性参见 {@code HystrixCommandProperties}
	 * @author fuwei.deng
	 * @date 2018年2月8日 下午5:02:22
	 * @version 1.0.0
	 * @param id
	 * @return
	 */
	@HystrixCommand(fallbackMethod = "callFallback")
	public ResultMap call(long id){
		try {
			Thread.sleep(5000);
		} catch (Exception e){
			logger.error("sleep exception ", e);
		}
		return ResultMap.buildSuccess();
	}
	
	public ResultMap callFallback(long id){
		return ResultMap.buildFailed("hystrix fallback : " + id);
    }
}

Hystrix partial source code analysis


Spring cloud is developed based on spring boot, and you can use spring-cloud-starter-hystrix as an entry to view dependent packages

spring-cloud-starter-hystrix dependencies

Among them, the beginning of hystrix is ​​the original jar package of Hystrix, so check the spring-cloud-netflix-core package

hystrix class in spring-cloud-netflix-core

There are two main configuration classes: HystrixAutoConfiguration, HystrixCircuitBreakerConfiguration. Among them, HystrixAutoConfiguration is mainly the configuration of hystrix health check, which is mainly configured in HystrixCircuitBreakerConfiguration. From the bean name loaded inside, you can see that the processing entry of Hystrix is: HystrixCommandAspect

@Bean
public HystrixCommandAspect hystrixCommandAspect() {
    return new HystrixCommandAspect();
}

The HystrixCommandAspect class uses the AOP aspect to extend the methods of the HystrixCommand and HystrixCollapser annotations. The following is the intercepted part of the code

/**
 * AspectJ aspect to process methods which annotated with {@link HystrixCommand} annotation.
 */
@Aspect
public class HystrixCommandAspect {

    private static final Map<HystrixPointcutType, MetaHolderFactory> META_HOLDER_FACTORY_MAP;

    static {
        META_HOLDER_FACTORY_MAP = ImmutableMap.<HystrixPointcutType, MetaHolderFactory>builder()
                .put(HystrixPointcutType.COMMAND, new CommandMetaHolderFactory())
                .put(HystrixPointcutType.COLLAPSER, new CollapserMetaHolderFactory())
                .build();
    }

    @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)")

    public void hystrixCommandAnnotationPointcut() {
    }

    @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)")
    public void hystrixCollapserAnnotationPointcut() {
    }

    @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()")
    public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = getMethodFromTarget(joinPoint);
        Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint);
        if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {
            throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " +
                    "annotations at the same time");
        }
        MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));
        MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
        HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
        ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
                metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();

        Object result;
        try {
            if (!metaHolder.isObservable()) {
                result = CommandExecutor.execute(invokable, executionType, metaHolder);
            } else {
                result = executeObservable(invokable, executionType, metaHolder);
            }
        } catch (HystrixBadRequestException e) {
            throw e.getCause();
        } catch (HystrixRuntimeException e) {
            throw hystrixRuntimeExceptionToThrowable(metaHolder, e);
        }
        return result;
    }
}

Here is a brief introduction to the configuration of the following two annotations

  • HystrixCommand

Method for flagging that command mode processing is required

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;


/**
 * 用于标记使用Hystrix命令模式执行的方法
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HystrixCommand {

    /**
     * 命令模式分组key,用于将如报表,告警,仪表板或团队/库所有权分组,默认值是类名
     */
    String groupKey() default "";

    /**
     * 命令的key值,默认值是方法名
     */
    String commandKey() default "";

    /**
     * 线程池key,用于表示HystrixThreadPool,用于监视,度量标准发布,缓存和其他此类用途.
     */
    String threadPoolKey() default "";

    /**
     * 执行降级回调方法,指定的方法必须和注解方法在同一个类中,并且必须和注解方法有相同的方法签名
     */
    String fallbackMethod() default "";

    /**
     * 配置命令模式的参数,具体参数对应类:HystrixCommandProperties
     */
    HystrixProperty[] commandProperties() default {};

    /**
     * 配置线程池参数,具体参数对应类:HystrixThreadPoolProperties
     */
    HystrixProperty[] threadPoolProperties() default {};

    /**
     * 定义需要忽略的异常。如果方法抛出的异常包含RUNTIME_EXCEPTION,会被包装成HystrixRuntimeException。具体逻辑在HystrixCommandAspect的hystrixRuntimeExceptionToThrowable方法
     */
    Class<? extends Throwable>[] ignoreExceptions() default {};

    /**
     * 定义观察者命令执行方式,详细说明见ObservableExecutionMode。判断逻辑在CommandExecutor.execute方法中
     */
    ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER;

    /**
     * 如果hystrix方法抛出的异常包括RUNTIME_EXCEPTION,则会被封装HystrixRuntimeException异常。此方法定义需要抛出的异常
     */
    HystrixException[] raiseHystrixExceptions() default {};

    /**
     * 默认降级回调方法,配置的方法不能有参数,返回值需要与注解的返回值兼容
     */
    String defaultFallback() default "";
}
  • HystrixCollapser

This annotation needs to be used in conjunction with the HystrixCommand annotation. It is mainly used for request merging. You can specify that this method will be merged and executed within a certain period of time (default 10 milliseconds). There are detailed comments and examples in the source code, and the posted ones have been partially translated

package com.netflix.hystrix.contrib.javanica.annotation;
import com.netflix.hystrix.HystrixCollapser.Scope;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 此注解用来将一些命令合并成单个后端依赖关系调用
 * 此注解需要与{@link HystrixCommand}注解一起使用
 * <p/>
 * 示例:
 * <pre>
 *    @HystrixCollapser(batchMethod = "getUserByIds"){
 *        public Future<User> getUserById(String id) {
 *        return null;
 *    }
 *    @HystrixCommand
 *    public List<User> getUserByIds(List<String> ids) {
 *        List<User> users = new ArrayList<User>();
 *        for (String id : ids) {
 *            users.add(new User(id, "name: " + id));
 *        }
 *        return users;
 *    }
 *</pre>
 *
 * 使用{@link HystrixCollapser}注解的方法可以返回任何兼容的类型,返回结果并不影响合并请求的执行,甚至可以返回{@code null}或者其他子类
 * 需要注意的是:注解的方法如果返回Future类型,那么泛型必须和命令方法返回的List泛型一致
 * 例如:
 * <pre>
 *     Future<User> - {@link HystrixCollapser}注解方法返回值
 *     List<User> - 批量命令方法返回值
 * </pre>
 * <p/>
 * 注意:批量命令方法必须用{@link HystrixCommand}注解标记
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HystrixCollapser {

    /**
     * 指定一个key,默认值是注解方法名
     */
    String collapserKey() default "";

    /**
     * 批量命令方法的名称,指定的方法必须有如下的签名
     *     java.util.List method(java.util.List)
     * 注意:指定的方法只能有一个参数
     */
    String batchMethod();

    /**
     * 指定合并请求的范围默认是{@link Scope#REQUEST}
     */
    Scope scope() default Scope.REQUEST;

    /**
     * 指定合并请求的配置,具体参见{@link HystrixCollapserProperties}
     */
    HystrixProperty[] collapserProperties() default {};

}

Configuration method and property description


The configuration of Hystrix is ​​initialized with the help of Archaius, which is used to dynamically manage property configuration and is an extension to the apache common configuration class library. You can load multiple environments and multiple configurations in advance, support regular refresh (thread safety), and get properties directly when you need them. The configuration class of Archaius is ArchaiusAutoConfiguration, which mainly introduces the meaning of some properties.

It should also be noted that the property configuration can be in the properties file or in the properties of the method annotation. The property names configured in the two places are different. The properties configured in the properties are hystrix.command.default. , Start with hystrix.threadpool.default and hystrix.collapser.default , where default represents the default value. If you need to configure the value of the specified commandKey, replace default with commandKey. If it is configured in the attribute of the method annotation, this prefix is ​​not required

  • HystrixCommandProperties
/**
 * Command execution properties.
 */
# 隔离策略,默认是线程隔离,还有信号量隔离,参见枚举:ExecutionIsolationStrategy
hystrix.command.default.execution.isolation.strategy=THREAD
# 隔离线程超时时间,默认1s
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1000
# 是否启用超时配置
hystrix.command.default.execution.timeout.enabled=true
# 超时的时候是否中断隔离线程
hystrix.command.default.execution.isolation.thread.interruptOnTimeout=true
# 隔离线程正在执行取消操作时是否中断
hystrix.command.default.execution.isolation.thread.interruptOnFutureCancel=false
# 隔离策略的最大信号量,只有使用信号量隔离策略时生效
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=10

/**
 * Command fallback properties.HystrixCommand.getFallback()
 */
# 降级方法的最大调用线程数,如果超出此信号量,会抛出异常
hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests=10
# 是否启用降级
hystrix.command.default.fallback.enabled=true

/**
 * Command circuit breaker properties.
 */
# 是否启用断路器
hystrix.command.default.circuitBreaker.enabled=true
# 请求量阈值,请求量达到该值是会开启断路器
hystrix.command.default.circuitBreaker.requestVolumeThreshold=20
# 当断路器打开后,会直接拒绝请求,此时间是配置多长时候后再次尝试处理请求
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000
# 打开断路器并走回退逻辑的错误率,默认50%
hystrix.command.default.circuitBreaker.errorThresholdPercentage=50
# 是否强制打开断路器,打开后会直接拒绝所有请求
hystrix.command.default.circuitBreaker.forceOpen=false
# 是否强制关闭断路器,关闭后会处理所有请求
hystrix.command.default.circuitBreaker.forceClosed=false

/**
 * Command metrics properties.主要用于统计执行情况
 */
# 统计的时间窗口值
hystrix.command.default.metrics.rollingStats.timeInMilliseconds=10000
# 统计时间窗口内分成的份数,需要保证timeInMilliseconds % numBuckets == 0
hystrix.command.default.metrics.rollingStats.numBuckets=10
# 是否启用百分数统计
hystrix.command.default.metrics.rollingPercentile.enabled=true
# 百分数统计的时间周期
hystrix.command.default.metrics.rollingPercentile.timeInMilliseconds=60000
# 百分数统计时间内分成的份数
hystrix.command.default.metrics.rollingPercentile.numBuckets=6
# 百分数统计每份的最大数量。每个bucket只取这个配置数量的执行数来统计
hystrix.command.default.metrics.rollingPercentile.bucketSize=100
# 记录健康快照间隔毫秒数
hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds=500

/**
 * Command CommandRequest Context properties.
 */
# 是否启用请求缓存。当HystrixCommand.getCacheKey()调用后,缓存到HystrixRequestCache
hystrix.command.default.requestCache.enabled=true
# 是否启用请求日志记录。HystrixCommand执行或者事件的日志到HystrixRequestLog
hystrix.command.default.requestLog.enabled=true
  • HystrixThreadPoolProperties
/**
 * Thread pool properties.
 */
# 是否启用maximumSize配置
hystrix.threadpool.default.allowMaximumSizeToDivergeFromCoreSize=false
# 线程数量
hystrix.threadpool.default.coreSize=10
# 最大执行线程数
hystrix.threadpool.default.maximumSize=10
# 线程存活毫秒数
hystrix.threadpool.default.keepAliveTimeMinutes=1
# 最大等待线程队列,如果-1为SynchronousQueue;其他则为LinkedBlockingQueue
hystrix.threadpool.default.maxQueueSize=-1
# 拒绝队列大小,即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝。当maxQueueSize为-1,则该属性不可用
hystrix.threadpool.default.queueSizeRejectionThreshold=5
# 线程池统计时间窗口值
hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds=10000
# 线程池统计时间窗口内分成的份数
hystrix.threadpool.default.metrics.rollingStats.numBuckets=10
  • HystrixCollapserProperties
/**
 * Collapser properties.
 */
# 批处理最大请求数,达到该值时就算没有达到时间也会触发批处理,默认值Integer.MAX_VALUE
hystrix.collapser.default.maxRequestsInBatch=0x7fffffff
# 触发批处理的延迟,在触发之前的同样请求可能会放到同一个批处理中
hystrix.collapser.default.timerDelayInMilliseconds=10
# 是否启用请求缓存
hystrix.collapser.default.requestCache.enabled=true
# 统计时间窗口值
hystrix.collapser.default.metrics.rollingStats.timeInMilliseconds=10000
# 统计时间窗口内分成的份数
hystrix.collapser.default.metrics.rollingStats.numBuckets=10
# 是否启用百分数统计
hystrix.collapser.default.metrics.rollingPercentile.enabled=true
# 百分数统计的时间周期
hystrix.collapser.default.metrics.rollingPercentile.timeInMilliseconds=60000
# 百分数统计时间内分成的份数
hystrix.collapser.default.metrics.rollingPercentile.numBuckets=6
# 百分数统计每份的最大数量。每个bucket只取这个配置数量的执行数来统计
hystrix.collapser.default.metrics.rollingPercentile.bucketSize=100

References


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325289588&siteId=291194637