原创不易,如若转载 请标明来源!java
欢迎关注本人微信公众号:壹枝花算不算浪漫
更多内容也可查看本人博客:一枝花算不算浪漫git
上一个系列文章讲解了Feign的源码,主要是Feign动态代理实现的原理,及配合Ribbon实现负载均衡的机制。github
这里咱们讲解一个新的组件Hystrix,也是和Feign进行融合的。spring
这一讲开始讲解Hystrix相关代码,固然仍是基于上一个组件Feign的基础上开始讲解的,这里默认你对Feign已经有了大体的了解。编程
使用过spring cloud的小伙伴对这个组件都不会陌生,Hystrix是保证系统高可用一个很重要的组件,主要提供一下几个功能:缓存
目录以下:微信
将全部请求外部系统(或者叫依赖服务)的逻辑封装到 HystrixCommand 或者 HystrixObservableCommand 对象中。网络
Run()方法为实现业务逻辑,这些逻辑将会在独立的线程中被执行当请求依赖服务时出现拒绝服务、超时或者短路(多个依赖服务顺序请求,前面的依赖服务请求失败,则后面的请求不会发出)时,执行该依赖服务的失败回退逻辑(Fallback)。并发
Hystrix 为每一个依赖项维护一个小线程池(或信号量);若是它们达到设定值(触发隔离),则发往该依赖项的请求将当即被拒绝,执行失败回退逻辑(Fallback),而不是排队。app
隔离策略分线程隔离和信号隔离。
线程隔离
第三方客户端(执行Hystrix的run()方法)会在单独的线程执行,会与调用的该任务的线程进行隔离,以此来防止调用者调用依赖所消耗的时间过长而阻塞调用者的线程。
使用线程隔离的好处:
线程池的缺点
线程最主要的缺点就是增长了CPU的计算开销,每一个command都会在单独的线程上执行,这样的执行方式会涉及到命令的排队、调度和上下文切换。
Netflix在设计这个系统时,决定接受这个开销的代价,来换取它所提供的好处,而且认为这个开销是足够小的,不会有重大的成本或者是性能影响。
信号隔离
信号隔离是经过限制依赖服务的并发请求数,来控制隔离开关。信号隔离方式下,业务请求线程和执行依赖服务的线程是同一个线程(例如Tomcat容器线程)。
熔断机制是一种保护性机制,当系统中某个服务失败率太高时,将开启熔断器,对该服务的后续调用,直接拒绝,进行Fallback操做。
熔断所依靠的数据便是Metrics中的HealthCount所统计的错误率。
如何判断是否应该开启熔断器?
必须同时知足两个条件:
当construct()或run()执行失败时,Hystrix调用fallback执行回退逻辑,回退逻辑包含了通用的响应信息,这些响应从内存缓存中或者其余固定逻辑中获得,而不该有任何的网络依赖。
若是必定要在失败回退逻辑中包含网络请求,必须将这些网络请求包装在另外一个 HystrixCommand 或 HystrixObservableCommand 中,即屡次降级。
失败降级也有频率限时,若是同一fallback短期请求过大,则会抛出拒绝异常。
同一对象的不一样HystrixCommand实例,只执行一次底层的run()方法,并将第一个响应结果缓存起来,其后的请求都会从缓存返回相同的数据。
因为请求缓存位于construct()或run()方法调用以前,因此,它减小了线程的执行,消除了线程、上下文等开销。
用一张简单地流程图总结:
Demo工程仍是使用以前的项目,git地址:https://github.com/barrywangmeng/spring-cloud-learn
eureka-server:注册中心
serviceA: 提供对外接口
serviceB: 经过feign调用serviceA接口
在serviceB项目中添加hystrix相关pom依赖及配置,这里就不列出来了,小伙伴们能够直接下载这个项目看一下。
接着就是改造对serviceA调用的FeignClient:
咱们能够调整serviceB中feign调用超时时间配置类模拟触发Hystrix降级逻辑:
咱们在调试的过程当中,为了方便走正常不降级逻辑的debug调试,特意会修改feign及hystrix的超时时间。
由于hystrix中大量使用了响应式编程(rxJava),代码中包含大量的观察者模式设计,各类回调函数糅杂在一块儿,因此代码显得很难懂。
这里咱们不纠结更多的rxJava源码,为了调试,每一个回调方法都会打上断点。
关于Hystrix daboard相关的内容这里也不会讲解,实际项目中会使用其余第三方组件来作服务监控,这里不作更多研究。
以前咱们讲过,若是不配置feign.hystrix.enabled:true这个配置的话,默认用的是DefaultTargeter
, 配置了的话就改变为HystrixTargeter
。
咱们来看看HystrixTargeter.target()
方法:
class HystrixTargeter implements Targeter { @Override public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget<T> target) { if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) { return feign.target(target); } // 里面包含encoder、decoder等feign的组件信息 feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign; // factory.getName: serviceA 返回的setterFactory 是null SetterFactory setterFactory = getOptional(factory.getName(), context, SetterFactory.class); if (setterFactory != null) { builder.setterFactory(setterFactory); } // 获取设置的feignClient的fallback属性 Class<?> fallback = factory.getFallback(); if (fallback != void.class) { return targetWithFallback(factory.getName(), context, target, builder, fallback); } // 获取设置的feignClient的fallbackFactory属性 Class<?> fallbackFactory = factory.getFallbackFactory(); if (fallbackFactory != void.class) { // 配置了降级factory的话,直接进入这个逻辑 return targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory); } return feign.target(target); } private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context, Target.HardCodedTarget<T> target, HystrixFeign.Builder builder, Class<?> fallbackFactoryClass) { FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext("fallbackFactory", feignClientName, context, fallbackFactoryClass, FallbackFactory.class); // 调用咱们自定义的fallback工厂中的create方法 Object exampleFallback = fallbackFactory.create(new RuntimeException()); Assert.notNull(exampleFallback, String.format( "Incompatible fallbackFactory instance for feign client %s. Factory may not produce null!", feignClientName)); // target.type() 就是ServiceAFeignClient 这个feignClient接口的名称 这里就是作些判断 if (!target.type().isAssignableFrom(exampleFallback.getClass())) { throw new IllegalStateException( String.format( "Incompatible fallbackFactory instance for feign client %s. Factory produces instances of '%s', but should produce instances of '%s'", feignClientName, exampleFallback.getClass(), target.type())); } // 执行HystrixFeign中的target方法 return builder.target(target, fallbackFactory); } }
咱们设置的这个FallbackFactory负责在每次超时、拒绝(线程池满)、异常的时候,create()方法返回一个降级机制的对象
从服务(ServiceA)的独立的spring容器中取出来一个独立的FallbackFactory,调用每一个服务的时候,他对应的FallbackFactory都是存在于那个服务关联的独立的spring容器中的。
接着进入到Hystrix.target()
中:
public final class HystrixFeign { public static Builder builder() { return new Builder(); } public static final class Builder extends Feign.Builder { private Contract contract = new Contract.Default(); private SetterFactory setterFactory = new SetterFactory.Default(); /** * @see #target(Class, String, FallbackFactory) */ public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) { return build(fallbackFactory).newInstance(target); } Feign build(final FallbackFactory<?> nullableFallbackFactory) { super.invocationHandlerFactory(new InvocationHandlerFactory() { @Override public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) { // 设置invocationHandlerFactory为HystrixInvocationHandler return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory); } }); // 设置contact为HystrixDelegatingContract super.contract(new HystrixDelegatingContract(contract)); // 调用父类的build方法 return super.build(); } } } public class ReflectiveFeign extends Feign { public <T> T newInstance(Target<T> target) { Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target); Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>(); List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>(); for (Method method : target.type().getMethods()) { if (method.getDeclaringClass() == Object.class) { continue; } else if(Util.isDefault(method)) { DefaultMethodHandler handler = new DefaultMethodHandler(method); defaultMethodHandlers.add(handler); methodToHandler.put(method, handler); } else { methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method))); } } // 和以前同样,生成一个JDK动态代理对象 InvocationHandler handler = factory.create(target, methodToHandler); T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler); for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) { defaultMethodHandler.bindTo(proxy); } return proxy; } }
最终实际用来去处理这个请求的,实际上是InvocationHandler,他是JDK动态代理的核心,基于JDK动态代理机制,生成一个动态代理的对象以后,对这个对象全部的方法调用,都会走关联的那个InvocationHandler。
咱们这里设置的是HystrixInvocationHandler
,来看下它的构造参数:
接下来还设置了contract信息,Contract是解析第三方注解的组件,设置为了HystrixDelegatingContract,顾名思义,就是说,设置了这个组件以后,后面就能够解析你在各个接口上hystrix相关的一些注解。
上面已经分析了Hystrix基础原理与Demo的搭建,基础原理中用一张简单地图画了Hystrix实现的流程,后面会更加详细的依据这个图进行讲解。
本文章首发自本人博客:https://www.cnblogs.com/wang-meng 和公众号:壹枝花算不算浪漫,如若转载请标明来源!
感兴趣的小伙伴可关注我的公众号:壹枝花算不算浪漫