@EnableHystrix或者@EnableCircuitBreaker-开启熔断器

开启

@EnableDiscoveryClient
@SpringBootApplication
//@EnableHystrix 开启 Hystrix
@EnableCircuitBreaker // 开启熔断器
public class AutodeliverApplication8091 {

配置方法上


 //HystrixCommand进行熔断控制 HystrixCommandProperties
    @HystrixCommand(
            commandProperties ={
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value ="3000" )
            }
            ,fallbackMethod ="myFallBack" //回退方法
    )
    @GetMapping("/ribbonTimeout/{userId}")
    public Integer findRibbonResumeOpenStateTimeout(@PathVariable Long userId) {

        String requestUrl = "http://edu-service-resume/resume/openstate/"+userId;
        System.out.println("获取服务实现 拼接的url : "+requestUrl);
        Integer forObject = restTemplate.getForObject(requestUrl , Integer.class);

        return forObject;
    }
    public Integer myFallBack(Long userId){
        return -1;
    }

HystrixProperty中的name值都在HystrixCommandProperties类中


   // known that we're using deprecated HystrixPropertiesChainedServoProperty until ChainedDynamicProperty exists in Archaius
    protected HystrixCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder, String propertyPrefix) {
        this.key = key;
        this.circuitBreakerEnabled = getProperty(propertyPrefix, key, "circuitBreaker.enabled", builder.getCircuitBreakerEnabled(), default_circuitBreakerEnabled);
        this.circuitBreakerRequestVolumeThreshold = getProperty(propertyPrefix, key, "circuitBreaker.requestVolumeThreshold", builder.getCircuitBreakerRequestVolumeThreshold(), default_circuitBreakerRequestVolumeThreshold);
        this.circuitBreakerSleepWindowInMilliseconds = getProperty(propertyPrefix, key, "circuitBreaker.sleepWindowInMilliseconds", builder.getCircuitBreakerSleepWindowInMilliseconds(), default_circuitBreakerSleepWindowInMilliseconds);
        this.circuitBreakerErrorThresholdPercentage = getProperty(propertyPrefix, key, "circuitBreaker.errorThresholdPercentage", builder.getCircuitBreakerErrorThresholdPercentage(), default_circuitBreakerErrorThresholdPercentage);
        this.circuitBreakerForceOpen = getProperty(propertyPrefix, key, "circuitBreaker.forceOpen", builder.getCircuitBreakerForceOpen(), default_circuitBreakerForceOpen);
        this.circuitBreakerForceClosed = getProperty(propertyPrefix, key, "circuitBreaker.forceClosed", builder.getCircuitBreakerForceClosed(), default_circuitBreakerForceClosed);
        this.executionIsolationStrategy = getProperty(propertyPrefix, key, "execution.isolation.strategy", builder.getExecutionIsolationStrategy(), default_executionIsolationStrategy);
        //this property name is now misleading.  //TODO figure out a good way to deprecate this property name
        this.executionTimeoutInMilliseconds = getProperty(propertyPrefix, key, "execution.isolation.thread.timeoutInMilliseconds", builder.getExecutionIsolationThreadTimeoutInMilliseconds(), default_executionTimeoutInMilliseconds);
        this.executionTimeoutEnabled = getProperty(propertyPrefix, key, "execution.timeout.enabled", builder.getExecutionTimeoutEnabled(), default_executionTimeoutEnabled);
        this.executionIsolationThreadInterruptOnTimeout = getProperty(propertyPrefix, key, "execution.isolation.thread.interruptOnTimeout", builder.getExecutionIsolationThreadInterruptOnTimeout(), default_executionIsolationThreadInterruptOnTimeout);
        this.executionIsolationThreadInterruptOnFutureCancel = getProperty(propertyPrefix, key, "execution.isolation.thread.interruptOnFutureCancel", builder.getExecutionIsolationThreadInterruptOnFutureCancel(), default_executionIsolationThreadInterruptOnFutureCancel);
        this.executionIsolationSemaphoreMaxConcurrentRequests = getProperty(propertyPrefix, key, "execution.isolation.semaphore.maxConcurrentRequests", builder.getExecutionIsolationSemaphoreMaxConcurrentRequests(), default_executionIsolationSemaphoreMaxConcurrentRequests);
        this.fallbackIsolationSemaphoreMaxConcurrentRequests = getProperty(propertyPrefix, key, "fallback.isolation.semaphore.maxConcurrentRequests", builder.getFallbackIsolationSemaphoreMaxConcurrentRequests(), default_fallbackIsolationSemaphoreMaxConcurrentRequests);
        this.fallbackEnabled = getProperty(propertyPrefix, key, "fallback.enabled", builder.getFallbackEnabled(), default_fallbackEnabled);
        this.metricsRollingStatisticalWindowInMilliseconds = getProperty(propertyPrefix, key, "metrics.rollingStats.timeInMilliseconds", builder.getMetricsRollingStatisticalWindowInMilliseconds(), default_metricsRollingStatisticalWindow);
        this.metricsRollingStatisticalWindowBuckets = getProperty(propertyPrefix, key, "metrics.rollingStats.numBuckets", builder.getMetricsRollingStatisticalWindowBuckets(), default_metricsRollingStatisticalWindowBuckets);
        this.metricsRollingPercentileEnabled = getProperty(propertyPrefix, key, "metrics.rollingPercentile.enabled", builder.getMetricsRollingPercentileEnabled(), default_metricsRollingPercentileEnabled);
        this.metricsRollingPercentileWindowInMilliseconds = getProperty(propertyPrefix, key, "metrics.rollingPercentile.timeInMilliseconds", builder.getMetricsRollingPercentileWindowInMilliseconds(), default_metricsRollingPercentileWindow);
        this.metricsRollingPercentileWindowBuckets = getProperty(propertyPrefix, key, "metrics.rollingPercentile.numBuckets", builder.getMetricsRollingPercentileWindowBuckets(), default_metricsRollingPercentileWindowBuckets);
        this.metricsRollingPercentileBucketSize = getProperty(propertyPrefix, key, "metrics.rollingPercentile.bucketSize", builder.getMetricsRollingPercentileBucketSize(), default_metricsRollingPercentileBucketSize);
        this.metricsHealthSnapshotIntervalInMilliseconds = getProperty(propertyPrefix, key, "metrics.healthSnapshot.intervalInMilliseconds", builder.getMetricsHealthSnapshotIntervalInMilliseconds(), default_metricsHealthSnapshotIntervalInMilliseconds);
        this.requestCacheEnabled = getProperty(propertyPrefix, key, "requestCache.enabled", builder.getRequestCacheEnabled(), default_requestCacheEnabled);
        this.requestLogEnabled = getProperty(propertyPrefix, key, "requestLog.enabled", builder.getRequestLogEnabled(), default_requestLogEnabled);

        // threadpool doesn't have a global override, only instance level makes sense
        this.executionIsolationThreadPoolKeyOverride = forString().add(propertyPrefix + ".command." + key.name() + ".threadPoolKeyOverride", null).build();
    }

Hystrix舱壁模式(线程池隔离策略)

@HystrixCommand
如果不进⾏任何设置,所有熔断⽅法使⽤⼀个Hystrix线程池(10个线程),那么这样的话会导致问
题,这个问题并不是扇出链路微服务不可⽤导致的,⽽是我们的线程机制导致的,如果⽅法A的请求把
10个线程都⽤了,⽅法2请求处理的时候压根都没法去访问B,因为没有线程可⽤,并不是B服务不可
⽤。


    @HystrixCommand(
            commandProperties ={
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value ="3000" )
            }
            ,fallbackMethod ="myFallBack" //回退方法
            //线程池标识,要标识为唯一
            ,threadPoolKey = "findRibbonResumeOpenStateTimeout"
            //线程池属性
            ,threadPoolProperties = {
                    //核心纯种
                    @HystrixProperty(name = "coreSize",value ="1" ),
            //最大等待队列长度
            @HystrixProperty(name = "maxQueueSize",value ="20" )
    }
    )

一些配置

    @HystrixCommand(
            commandProperties ={
                    //请求超时时间
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value ="3000" ),
                    //统计窗口内的定义
                    @HystrixProperty(name =
                            "metrics.rollingStats.timeInMilliseconds",value = "8000"),
                    //最小请求数
                    @HystrixProperty(name =
                            "circuitBreaker.requestVolumeThreshold",value = "2"),
                    //错误的请求比例
                    @HystrixProperty(name =
                            "circuitBreaker.errorThresholdPercentage",value = "50"),
                    //自我修复的活窗口时长
                    @HystrixProperty(name =
                            "circuitBreaker.sleepWindowInMilliseconds",value = "3000")
            }
            ,fallbackMethod ="myFallBack" //回退方法
            //线程池标识,要标识为唯一
            ,threadPoolKey = "findRibbonResumeOpenStateTimeout"
            //线程池属性
            ,threadPoolProperties = {
                    //核心纯种
                    @HystrixProperty(name = "coreSize",value ="1" ),
            //最大等待队列长度
            @HystrixProperty(name = "maxQueueSize",value ="20" )
    }
    )
  • 配置文件

# 配置熔断策略:
hystrix:
command:
default:
circuitBreaker:
# 强制打开熔断器,如果该属性设置为true,强制断路器进⼊打开状态,将会拒绝所有的请
求。 默认false关闭的
forceOpen: false
# 触发熔断错误⽐例阈值,默认值50%
errorThresholdPercentage: 50
# 熔断后休眠时⻓,默认值5秒
sleepWindowInMilliseconds: 3000
# 熔断触发最⼩请求次数,默认值是20
requestVolumeThreshold: 2
execution:
isolation:
thread:
# 熔断超时设置,默认为1秒
timeoutInMilliseconds: 2000

开启健康检查


management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: always
  • 健康检查
    跳闸状态
"hystrix": {
            "status": "CIRCUIT_OPEN",
            "details": {
                "openCircuitBreakers": [
                    "AutodeliverController::findRibbonResumeOpenStateTimeout"
                ]
            }
        }

正常


@EnableHystrixDashboard

启用仪表盘

  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>

聚合监控

<!--hystrix turbine聚合监控-->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eurekaclient</artifactId>
</dependency>
</dependencies>
  • 配置

server:
  port: 9001
spring:
  application:
    name: edu-service-hystrix-turbine


# 注册到eureka注册中
eureka:
  client:
    service-url:
      # 使用逗号分隔 多个实例,
      defaultZone: http://EduCloudEurekaServerB:8762/eureka,http://EduCloudEurekaServerA:8761/eureka
  instance:
    prefer-ip-address: true #服务实例中显示ip,而不是显示主机名(兼容老的eureka版本)
    # 实例名称: 192.168.1.103:lagou-service-resume:8080,我们可以自定义它
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
    # 自定义元数据
#    metadata-map:
#      cluster: cl1
#      region: rn1
management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: always
turbine:
  appConfig: edu-service-autodeliver
  clusterNameExpression: "'default'"


动类上添加注解@EnableTurbine

@EnableDiscoveryClient
@EnableTurbine
@SpringBootApplication
public class TurbineApplication9001 {
    public static void main(String[] args) {
        SpringApplication.run(TurbineApplication9001.class,args);
    }
}

访问
http://localhost:9001/turbine.stream
在这里插入图片描述

再访问仪表盘项目

http://localhost:9000/hystrix
在这里插入图片描述
在这里插入图片描述

Hystrix核⼼源码

分析⼊⼝: @EnableCircuitBreaker注解激活了熔断功能

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//1 导入了一个选择器
@Import(EnableCircuitBreakerImportSelector.class)
public @interface EnableCircuitBreaker {

}

    1. EnableCircuitBreakerImportSelector

/**
 * Imports a single circuit breaker implementation configuration.
 * @author Spencer Gibb
 */
@Order(Ordered.LOWEST_PRECEDENCE - 100)
//2  .这里没什么要看 父类SpringFactoryImportSelector
public class EnableCircuitBreakerImportSelector extends
		SpringFactoryImportSelector<EnableCircuitBreaker> {

	@Override
	protected boolean isEnabled() {
	//获取断路由开关,默认true  
		return getEnvironment().getProperty(
				"spring.cloud.circuit.breaker.enabled", Boolean.class, Boolean.TRUE);
	}

}

  • 2.SpringFactoryImportSelector
/**
 * Selects configurations to load, defined by the generic type T. Loads implementations
 * using {@link SpringFactoriesLoader}.
 *
 * @author Spencer Gibb
 * @author Dave Syer
 */
public abstract class SpringFactoryImportSelector<T>
		implements DeferredImportSelector, BeanClassLoaderAware, EnvironmentAware {

	private ClassLoader beanClassLoader;

	private Class<T> annotationClass;

	private Environment environment;

	private final Log log = LogFactory.getLog(SpringFactoryImportSelector.class);

	@SuppressWarnings("unchecked")
	protected SpringFactoryImportSelector() {
	//获取到子类传到父类的泛型
		this.annotationClass = (Class<T>) GenericTypeResolver
				.resolveTypeArgument(this.getClass(), SpringFactoryImportSelector.class);
	}

	@Override
	public String[] selectImports(AnnotationMetadata metadata) {
		if (!isEnabled()) {
			return new String[0];
		}
		//根据传过来的类的合路径去spring.factories文件中获取自动装配
		AnnotationAttributes attributes = AnnotationAttributes.fromMap(
				metadata.getAnnotationAttributes(this.annotationClass.getName(), true));

		Assert.notNull(attributes, "No " + getSimpleName() + " attributes found. Is "
				+ metadata.getClassName() + " annotated with @" + getSimpleName() + "?");

		// Find all possible auto configuration classes, filtering duplicates
		List<String> factories = new ArrayList<>(new LinkedHashSet<>(SpringFactoriesLoader
				.loadFactoryNames(this.annotationClass, this.beanClassLoader)));

		if (factories.isEmpty() && !hasDefaultFactory()) {
			throw new IllegalStateException("Annotation @" + getSimpleName()
					+ " found, but there are no implementations. Did you forget to include a starter?");
		}

		if (factories.size() > 1) {
			// there should only ever be one DiscoveryClient, but there might be more than
			// one factory
			log.warn("More than one implementation " + "of @" + getSimpleName()
					+ " (now relying on @Conditionals to pick one): " + factories);
		}

		return factories.toArray(new String[factories.size()]);
	}


在这里插入图片描述

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.hystrix.HystrixAutoConfiguration,\
org.springframework.cloud.netflix.hystrix.security.HystrixSecurityAutoConfiguration

org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\
org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration

会注⼊org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration

    1. HystrixCircuitBreakerConfiguration
@Configuration
public class HystrixCircuitBreakerConfiguration {
	//切面
	@Bean
	public HystrixCommandAspect hystrixCommandAspect() {
		return new HystrixCommandAspect();
	}

	//关闭时的钩子
	@Bean
	public HystrixShutdownHook hystrixShutdownHook() {
		return new HystrixShutdownHook();
	}
	
	//特性
	@Bean
	public HasFeatures hystrixFeature() {
		return HasFeatures.namedFeatures(new NamedFeature("Hystrix", HystrixCommandAspect.class));
	}

	/**
	 * {@link DisposableBean} that makes sure that Hystrix internal state is cleared when
	 * {@link ApplicationContext} shuts down.
	 */
	private class HystrixShutdownHook implements DisposableBean {

		@Override
		public void destroy() throws Exception {
			// Just call Hystrix to reset thread pool etc.
			Hystrix.reset();
		}

	}

}

    1. HystrixCommandAspect
//切面
@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;
}
    ...

GenericCommand中根据元数据信息重写了两个很核⼼的⽅法,⼀个是run⽅法封装了对原始⽬标⽅法
的调⽤,另外⼀个是getFallBack⽅法
它封装了对回退⽅法的调⽤
另外,在GenericCommand的上层类构造函数中会完成资源的初始化,⽐如线程池
GenericCommand —>AbstractHystrixCommand—>HystrixCommand—>AbstractCommand
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
进⼊execute执⾏这⾥
在这里插入图片描述

  public R execute() {
        try {
            return queue().get();
        } catch (Exception e) {
            throw Exceptions.sneakyThrow(decomposeException(e));
        }
    }

在这里插入图片描述
GenericCommand⽅法中根据元数据信息等重写了run⽅法(对⽬标⽅法的调⽤),
getFallback⽅法(对回退⽅法的调⽤),在RxJava处理过程中会完成对这两个⽅法的调⽤。
在这里插入图片描述

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值