最近cat埋点因为hystrix的异步执行走了好大的坑,所以希望把hystrix的线程模型摸摸清楚
先讲个大概,然后再看代码
如果feign启用hystrix就会用hystrix的client来访问
feign:
hystrix:
enabled: true # 启用熔断
hystrix的client会启动一个线程 来执行hystrixcommend 这个runable会放入HystrixContextScheduler 的线程池当中执行
然后SynchronousMethodHandler 会对返回值的结果进行判断
AbstractCommand.executeCommandAndObserve 则会对异常进行判断
如果超时会进入fall方法 如果是hystrixbadrequest方法就不会进入fall方法
那么hystrix为什么要做线程隔离呢
比如我们现在有3个业务调用分别是查询订单、查询商品、查询用户,且这三个业务请求都是依赖第三方服务-订单服务、商品服务、用户服务。三个服务均是通过RPC调用。当查询订单服务,假如线程阻塞了,这个时候后续有大量的查询订单请求过来,那么容器中的线程数量则会持续增加直致CPU资源耗尽到100%,整个服务对外不可用,集群环境下就是雪崩。
但是如果我控制了对服务的线程 那么服务的线程就不容易快速增加 防止雪崩
但是首先来看下这个feign是怎么启用hystrix的话
大概流程是 在开启hystrix配置 那么spring会在bean加载时通过FactoryBean增强加载方法,为每个@feginClient 注解的类 增强配置 然后在远程调用发生是 通过切面拦截 增强调用的方法
第一步
FeignClientsConfiguration
feign的配置类 如果配置文件里面指定了feign.hystrix.enabled 那么会使用hystrix的hystrixfeign
HystrixTargeter 的target 是干嘛的后面说
第二步
主类上声明@EnableFeignClients 代表使用声明式feign调用, 然后去找所有@feign的bean然后读取属性和配置 然后注册FeignClientFactoryBean 注意这个是factoryBean 是spring的拓展点
第三步
有了factoryBean就要知道他是如何getObject()的 拓展了什么
也就是我们在@Autowired完了之后在做什么
然后其实就是spring的依赖加载过程
还是要看看FeignClientFactoryBean 在做什么 (这个类不仅做了下面的时候还装饰了编码器等等)
因为是factorybean所以看直接看getObject 看看拓展了什么
getobject里就一个方法getTarget
<T> T getTarget() {
FeignContext context = this.applicationContext.getBean(FeignContext.class);
Feign.Builder builder = feign(context); //先取上下文 利用上下文构造一个feign builder
if (!StringUtils.hasText(this.url)) {
if (!this.name.startsWith("http")) {
this.url = "http://" + this.name;
}
else {
this.url = this.name;
}
this.url += cleanPath();//希望把url拼装为即将调用的服务名
return (T) loadBalance(builder, context,
new HardCodedTarget<>(this.type, this.name, this.url)); //上进入loadbalance方法
}
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.url;
}
String url = this.url + cleanPath();
Client client = getOptional(context, Client.class);
if (client != null) {
if (client instanceof LoadBalancerFeignClient) {
// not load balancing because we have a url,
// but ribbon is on the classpath, so unwrap
client = ((LoadBalancerFeignClient) client).getDelegate();
}
builder.client(client);
}
Targeter targeter = get(context, Targeter.class);
return (T) targeter.target(this, builder, context,
new HardCodedTarget<>(this.type, this.name, url));
}
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) {
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context, target);//可以看到主要还是这里,HystrixTargeter 实现了targeter.target的接口 所以会走到hystrix
}
throw new IllegalStateException(
"No Feign Client for loadBalancing defin