本文共 4403 字,大约阅读时间需要 14 分钟。
在复杂的分布式系统架构中,每个服务都有很多的依赖服务,而每个依赖服务都可能会故障。如果服务没有和自己的依赖服务进行隔离,那么可能某一个依赖服务的故障就会拖垮当前这个服务
(1)通过HystrixCommand或者HystrixObservableCommand来封装对外部依赖的访问请求,这个访问请求一般会运行在独立的线程中,资源隔离
具体实现代码:public class CommandHelloWorld extends HystrixCommand{ private final String name; public CommandHelloWorld(String name) { super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")); this.name = name; } @Override protected String run() { //调用远程服务的逻辑代码 return "Hello " + name + "!"; }}
不要因为某一个依赖服务的故障,导致耗尽了缓存服务中的所有的线程资源去执行
public class ObservableCommandHelloWorld extends HystrixObservableCommand{ private final String name; public ObservableCommandHelloWorld(String name) { super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")); this.name = name; } @Override protected Observable construct() { return Observable.create(new Observable.OnSubscribe () { @Override public void call(Subscriber observer) { try { if (!observer.isUnsubscribed()) { //onNext的会调用执行command时的onNext方法 observer.onNext("Hello " + name + "!"); observer.onNext("Hi " + name + "!"); observer.onCompleted(); } } catch (Exception e) { observer.onError(e); } } } ).subscribeOn(Schedulers.io()); }}
上述为线程池的隔离,如果使用信号量的隔离需要修改成如下:
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")) .andCommandPropertiesDefaults(HystrixCommandProperties.Setter() .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)));
command的四种调用方式
同步:
new CommandHelloWorld(“World”).execute() new ObservableCommandHelloWorld(“World”).toBlocking().toFuture().get() 如果observable command只会返回一条数据,那么可以调用上面的模式,去同步执行,返回一条数据异步:
new CommandHelloWorld(“World”).queue() new ObservableCommandHelloWorld(“World”).toBlocking().toFuture() 对command调用queue(),仅仅将command放入线程池的一个等待队列,就立即返回,拿到一个Future对象,后面可以做一些其他的事情,然后过一段时间对future调用get()方法获取数据//这种方法会立即调用执行ObservablefWorld = new CommandHelloWorld("World").observe(); //会延迟调用执行,等到下面subscribe的时候才会执行//Observable fWorld = new ObservableCommandHelloWorld("World").toObservable();assertEquals("Hello World!", fWorld.toBlocking().single());fWorld.subscribe(new Observer () { @Override public void onCompleted() { } @Override public void onError(Throwable e) { e.printStackTrace(); } @Override public void onNext(String v) { System.out.println("onNext: " + v); }});
(2)对于超出我们设定阈值的服务调用,直接进行超时,不允许其耗费过长时间阻塞住。这个超时时间默认是99.5%的访问时间,但是一般我们可以自己设置一下
(3)为每一个依赖服务维护一个独立的线程池,或者是semaphore,当线程池已满时,直接拒绝对这个服务的调用 (4)对依赖服务的调用的成功次数,失败次数,拒绝次数,超时次数,进行统计 (5)如果对一个依赖服务的调用失败次数超过了一定的阈值,自动进行熔断,在一定时间内对该服务的调用直接降级,一段时间后再自动尝试恢复 (6)当一个服务调用出现失败,被拒绝,超时,短路等异常情况时,自动调用fallback降级机制 (7)对属性和配置的修改提供近实时的支持线程池和信号量隔离区别:
对于线程池和信号量做资源隔离、限流和容量的限制,默认的容量都是10,区别在于,线程池隔离技术是用自己的线程去执行调用的,而信号量的隔离是直接让tomcat的线程去调用依赖服务的。线程池隔离适合大多数场景,例如堆外部依赖服务的网络请求和timeout等问题;而信号量隔离适合对内部一些比较复杂的业务逻辑处理。 command threadpoll、group和key区别:设置线程池大小:
//一般来说,用这个默认的10个线程大小就够了HystrixThreadPoolProperties.Setter() .withCoreSize(int value)
//默认是5HystrixThreadPoolProperties.Setter() .withQueueSizeRejectionThreshold(int value)
//默认是10.withExecutionIsolationSemaphoreMaxConcurrentRequests(int value)
转载地址:http://dhrgi.baihongyu.com/