您的位置:首页 > 其它

Hystrix的一些应用和想法

2018-01-26 16:26 253 查看

1、简介Hystrix

  说实话,凭借hystrix的顶顶大名,关于它的简介到处都是。最准确的当然还是官方的,有兴趣的可以看一下它官方的wiki:https://github.com/Netflix/Hystrix/wiki

In a distributed environment, inevitably some of the many service dependencies will fail. Hystrix is a library that helps you control the interactions between these distributed services by adding latency tolerance and fault tolerance logic. Hystrix does this by isolating points of access between the services, stopping cascading failures across them, and providing fallback options, all of which improve your system’s overall resiliency.
简单来说就是增强一个分布式系统的容错率和错误处理逻辑。hystrix通过对依赖失败进行隔离,将整个服务的延迟都缩小到一个可控的范围内。也就是说整个服务的响应时间是可控的,不会因为某个依赖服务的延迟或错误,或者是因为高并发而使整个服务的响应时间大大增加甚至是服务雪崩。

2、Hystrix如何解决依赖隔离

Hystrix其实一套command pattern(命令模式)的封装,要明白Hystrix的工作原理首先要明白command pattern ,关于command pattern 可以看看这:http://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/command.html

一般命令模式的UML图:



Hystrix有点不同(部分UML)



它提供了抽象命令类,并将invoker和abstract合并到一起,并在command内提供了调用的命令的具体参数,它的总共提供了三种执行模式,分别是execute(同步模式),queue(异步执行),Reactive模式(Observable(立即请求),toObservable(订阅时请求))。

将所有请求外部系统(或者叫依赖服务)的逻辑封装到 HystrixCommand 或者 HystrixObservableCommand 对象中,这些逻辑将会在独立的线程中被执行

Hystrix 采取自动超时的策略(默认1000ms)。该策略默认对所有 Command 都有效,也可以通过设置 Command 的配置以自定义超时时间,所有的默认设置在HystrixCommandProperties中看到。

可以对每个服务维护一个线程池,可以选择当线程用完时是等待还是拒绝,等待的最大队列长度是多少,这个大大的提高了对依赖服务可控性和灵活性,所有的关于线程池的配置都可以在HystrixThreadPoolProperties中看到

分出成功、失败(抛出异常)、超时或者线程池占满四种请求依赖服务时可能出现的异常,所有的异常都可以通过getExecutionException()这个默认方法进行获取

引入『熔断器』机制,在依赖服务失效比例超过阈值时,手动或者自动地切断服务一段时间

请求失败执行fallback()方法,多个请求(继承HystrixCollapser)当其中一个失败,后面的请求都不会执行,而直接执行fallback

Hystrix提供监控和配置变更

3、Hystrix执行



构建HystrixCommand或者HystrixObservableCommand对象;

执行命令(execute()、queue()、observe()、toObservable());

如果请求结果缓存这个特性被启用,并且缓存命中,则缓存的回应会立即通过一个Observable对象的形式返回;

检查熔断器状态,确定请求线路是否是开路,如果请求线路是开路,Hystrix将不会执行这个命令,而是直接使用『失败回退逻辑』(即不会执行run(),直接执行getFallback());

如果和当前需要执行的命令相关联的线程池和请求队列(或者信号量,如果不使用线程池)满了,Hystrix 将不会执行这个命令,而是直接使用『失败回退逻辑』(即不会执行run(),直接执行getFallback());

执行HystrixCommand.run()或HystrixObservableCommand.construct(),如果这两个方法执行超时或者执行失败,则执行getFallback();如果正常结束,Hystrix 在添加一些日志和监控数据采集之后,直接返回回应;

Hystrix 会将请求成功,失败,被拒绝或超时信息报告给熔断器,熔断器维护一些用于统计数据用的计数器。

4、hello world

  

@Log4j
public class DemoHystrix extends HystrixCommand<Boolean>{

private DemoService demoService;

private Demo demo;

protected DemoHystrix(DemoService demoService,Demo demo) {
super((Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceX"))
.andThreadPoolPropertiesDefaults(com.netflix.hystrix.HystrixThreadPoolProperties.Setter()
.withCoreSize(10)
.withMaximumSize(100)
          //线程饱和后拒绝所有服务
.withMaxQueueSize(-1)
          //使MaximumSize生效
.withAllowMaximumSizeToDivergeFromCoreSize(true)))
          //fallback和execute用的同一个线程,这个配置可以使fallback不抢占execute的线程
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("RemoteServiceXFallback")));
this.demoService = demoService;
this.demo = demo;
}

@Override
protected Boolean run() throws Exception {
return demoService.queryDemoById(29)!=null;
}

@Override
protected Boolean getFallback() {
     //可以根据不同的异常进行处理
System.out.println("~~~~~~~~~~~~~~~~~this is fallback  "+getExecutionException().getMessage());
return false;
}

}


  这是一般脱离框架的模式(没用spring),Hystrix设计的是一个command实例只能执行一次,如果

DemoHystrix demoHystrix = new DemoHystrix(demoService,demo);
demoHystrix.execute();
demoHystrix.execute();


  会直接抛异常,所以这也就理解了为什么每个Command都必须要有个有个CommandKey,这样同一个command都在相同的线程池里执行,甚至是可以定义出一个服务组的概念。

5、hystrix在spring mvc的使用

通过上面的方式可以看出,hystrix并不依赖任何框架,它只是一个命令模式的集合,你甚至可以不把它用在服务治理上,把它用在任何你需要的场景上都是可以的,但是因为历史遗留的问题,如果要使用hystrix而不用改动太多代码的话,hystrix提供了hystrix-javanica包

使用maven引入hystrix依赖:

<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
<version>1.5.12</version>
</dependency>


少不了的spring的配置。。。

@Configuration
@Import(com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect.class)
@EnableAspectJAutoProxy
public class AppConfig extends WebMvcConfigurerAdapter {
}


 配置很简单,因为hystrix已经做好了,就是做了一个aop,对所有执行带有@HystrixCommand的方法做了切面,然后包装成

HystrixInvokable执行。


然后你就可以直接的使用hystrix了

@Component
@Slf4j
public class WrapService {

@Reference(version = "1.0.0")
private DemoService demoService;

@Reference(version = "1.0.0")
private OtherService otherService;

@Reference(version = "2.0.0")
private OtherService otherService2;

public boolean demoServiceInsert(Demo demo){
DemoHystrix demoHystrix = new DemoHystrix(demoService,demo);

return demoHystrix.execute();
}

@HystrixCommand(groupKey = "DemoCommand", fallbackMethod = "getDemoBack",
threadPoolProperties={@HystrixProperty(name = "coreSize",value = "10"),
@HystrixProperty(name = "maximumSize",value = "100"),
@HystrixProperty(name = "allowMaximumSizeToDivergeFromCoreSize",value = "true")})
public Demo getDemo(){
return demoService.queryDemoById(29);
}

private Demo getDemoBack(){
log.info("getDemoBack");
return new Demo();
}

public OtherService getOtherService(){
return otherService;
}

public OtherService getOtherService2(){
return otherService2;
}
}


  和刚才的服务一样,只是在这种情况下在fallback中就不能获得异常了,其他所有的配置都可以在注解中完成。

6、总结

Hystrix会损失一定性能在一定程度上,根据官方的文档如果设置的好的话大概能到原来的99.5%,但是这带来了对依赖服务极大的控制力和灵活度,它本身的使用很简单,不需要太多的学习成本,更可贵的是,对于以前的老系统是从同步方式转到异步或者是reactive模式提供了一个可行的方法,这是非常了不起的。

监控忘了说了,但它本身很简单,对Hystrix有兴趣的可以看看这边文章:
http://tech.lede.com/2017/06/15/rd/server/hystrix/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: