publicQueryOrderIdCommand(OrderServiceProvider orderServiceProvider){super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey( "orderService")).andCommandKey(HystrixCommandKey.Factory.asKey( "queryByOrderId")).andCommandPropertiesDefaults(HystrixCommandProperties.Setter.withCircuitBreakerRequestVolumeThreshold( 10) //至少有10个请求,熔断器才进行错误率的计算.withCircuitBreakerSleepWindowInMilliseconds( 5000) //熔断器中断请求5秒后会进入半打开状态,放部分流量过去重试.withCircuitBreakerErrorThresholdPercentage( 50) //错误率达到50开启熔断保护.withExecutionTimeoutEnabled( true)).andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter.withCoreSize( 10)));this.orderServiceProvider = orderServiceProvider;}
@OverrideprotectedInteger run{returnorderServiceProvider.queryByOrderId;}
@OverrideprotectedInteger getFallback{return- 1;}}
第二步,调用HystrixCommand的执行方法发起实际请求。
@TestpublicvoidtestQueryByOrderIdCommand{Integer r = newQueryOrderIdCommand(orderServiceProvider).execute;logger.info( "result:{}", r);}
Hystrix处理流程
Hystrix流程图如下:
Hystrix整个工作流如下:
构造一个 HystrixCommand或HystrixObservableCommand对象,用于封装请求,并在构造方法配置请求被执行需要的参数;
执行命令,Hystrix提供了4种执行命令的方法,后面详述;
判断是否使用缓存响应请求,若启用了缓存,且缓存可用,直接使用缓存响应请求。Hystrix支持请求缓存,但需要用户自定义启动;
判断熔断器是否打开,如果打开,跳到第8步;
判断线程池/队列/信号量是否已满,已满则跳到第8步;
执行HystrixObservableCommand.construct或HystrixCommand.run,如果执行失败或者超时,跳到第8步;否则,跳到第9步;
统计熔断器监控指标;
走Fallback备用逻辑
返回请求响应
从流程图上可知道,第5步线程池/队列/信号量已满时,还会执行第7步逻辑,更新熔断器统计信息,而第6步无论成功与否,都会更新熔断器统计信息。
执行命令的几种方法
Hystrix提供了4种执行命令的方法,execute和queue 适用于HystrixCommand对象,而observe和toObservable适用于HystrixObservableCommand对象。
execute
以同步堵塞方式执行run,只支持接收一个值对象。hystrix会从线程池中取一个线程来执行run,并等待返回值。
queue
以异步非阻塞方式执行run,只支持接收一个值对象。调用queue就直接返回一个Future对象。可通过 Future.get拿到run的返回结果,但Future.get是阻塞执行的。若执行成功,Future.get返回单个返回值。当执行失败时,如果没有重写fallback,Future.get抛出异常。
observe
如果继承的是HystrixCommand,hystrix会从线程池中取一个线程以非阻塞方式执行run;如果继承的是HystrixObservableCommand,将以调用线程阻塞执行construct。
observe使用方法:
调用observe会返回一个Observable对象
调用这个Observable对象的subscribe方法完成事件注册,从而获取结果toObservable
如果继承的是HystrixCommand,hystrix会从线程池中取一个线程以非阻塞方式执行run,调用线程不必等待run;如果继承的是HystrixObservableCommand,将以调用线程堵塞执行construct,调用线程需等待construct执行完才能继续往下走。
toObservable使用方法:
调用observe会返回一个Observable对象
调用这个Observable对象的subscribe方法完成事件注册,从而获取结果
需注意的是,HystrixCommand也支持toObservable和observe,但是即使将HystrixCommand转换成Observable,它也只能发射一个值对象。只有HystrixObservableCommand才支持发射多个值对象。
几种方法的关系
image
execute实际是调用了queue.get
queue实际调用了toObservable.toBlocking.toFuture
Hystrix总是以Observable的形式作为响应返回,不同执行命令的方法只是进行了相应的转换。
Hystrix容错
Hystrix的容错主要是通过添加容许延迟和容错方法,帮助控制这些分布式服务之间的交互。还通过隔离服务之间的访问点,阻止它们之间的级联故障以及提供回退选项来实现这一点,从而提高系统的整体弹性。Hystrix主要提供了以下几种容错方法:
资源隔离
熔断
降级
下面我们详细谈谈这几种容错机制。
资源隔离
资源隔离主要指对线程的隔离。Hystrix提供了两种线程隔离方式:线程池和信号量。
线程隔离-线程池
Hystrix通过命令模式对发送请求的对象和执行请求的对象进行解耦,将不同类型的业务请求封装为对应的命令请求。如订单服务查询商品,查询商品请求->商品Command;商品服务查询库存,查询库存请求->库存Command。并且为每个类型的Command配置一个线程池,当第一次创建Command时,根据配置创建一个线程池,并放入ConcurrentHashMap,如商品Command:
final staticConcurrentHashMap< String, HystrixThreadPool> threadPools = newConcurre