Hystrix 工作流程

Hystrix是如何处理请求,在官网有详细介绍:https://github.com/Netflix/Hystrix/wiki/How-it-Works, 本文重点围绕下方流程图介绍一下主要的流程;

Hystrix是将我们的系统间调用包装成一个个Comman来执行,举个简单的例子:

public class TestCommand extends HystrixCommand<Integer> {

    private TestServiceA serviceA;

    private int index;

    private static HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter()
                                                                                    //至少有10个请求,熔断器才进行错误率的计算
                                                                                    .withCircuitBreakerRequestVolumeThreshold(3)
                                                                                    //熔断器中断请求5秒后会进入半打开状态,放部分流量过去重试
                                                                                    .withCircuitBreakerSleepWindowInMilliseconds(5000)
                                                                                    //错误率达到50开启熔断保护
//                                                                                    .withCircuitBreakerErrorThresholdPercentage(30)
                                                                                    .withExecutionIsolationSemaphoreMaxConcurrentRequests(2)
                                                                                    .withExecutionTimeoutEnabled(true)
                                                                                    .withExecutionTimeoutInMilliseconds(1000);

    protected TestCommand(TestServiceA serviceA, int index) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("testGroupKey"))
                    .andCommandKey(HystrixCommandKey.Factory.asKey("testCommandKey"))
                    .andCommandPropertiesDefaults(setter)
                    .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(10)));
        this.serviceA = serviceA;
        this.index = index;
    }

    @Override
    protected Integer run() throws Exception {
        return serviceA.service(index);
    }

    @Override
    protected Integer getFallback() {
        // if service execute fail, do sth
        return -1;
    }

}

// execute
TestCommand testCommand = new TestCommand(new TestServiceA(), i);
testCommand.execute();

 我们只需要用一个Command来包装我们的RPC/RMI调用,上面就使用 TestCommand 包装了一个TestService 方法;

 下面解释流程图中具体逻辑;

1、包装请求:

 可以使用继承HystrixCommand或HystrixObservableCommand来包装业务方法;

2、发起请求:

 使用调用Command的execute来执行一个业务方法调用;

 Hystrix除了提供了execute方法,另外还提供了3种方来,所有的请求入口:

  

K             value   = command.execute();
Future<K>     fValue  = command.queue();
Observable<K> ohValue = command.observe();         //hot observable
Observable<K> ocValue = command.toObservable();    //cold observable

  如上图所示:

  执行同步调用execute方法,会调用queue().get()方法,queue()又会调用toObservable().toBlocking().toFuture();

  所以,所有的方法调用都依赖Observable的方法调用,只是取决于是需要同步还是异步调用;

3、缓存处理:

  当请求来到后,会判断请求是否启用了缓存(默认是启用的),再判断当前请求是否携带了缓存Key;

  如果命中缓存就直接返回;否则进入剩下的逻辑;

4、判断断路器是否打开(熔断):

  断路器是Hystrix的设计核心,断路器是实现快速失败的重要手段(断路器打开就直接返回失败);

  可以设置断路器打开一定时间后,可以进行尝试进行业务请求(默认是5000毫秒);

5、判断是否进行业务请求(请求是否需要隔离或降级):

  是否进行业务请求之前还会根据当前服务处理质量,判断是否需要去请求业务服务;

  如果当前服务质量较低(线程池/队列/信号量已满),那么也会直接失败;

  线程池或信号量的选择(默认是线程池):

    线程池主要优势是客户端隔离和超时设置,但是如果是海量低延迟请求时,频繁的线程切换带来的损耗也是很可观的,这种情况我们就可以使用信号量的策略;

    信号量的主要缺点就是不能处理超时,请求发送到客户端后,如果被客户端pending住,那么就需要一直等待;

6、执行业务请求:

  当前服务质量较好,那么就会提交请求到业务服务器去;

  HystrixObservableCommand.construct() or HystrixCommand.run()

7、健康监测:

  根据历史的业务方法执行结果,来统计当前的服务健康指标,为断路器是否熔断等动作作为依据;  

8/9、响应失败或成功的处理结果

posted @ 2019-08-17 21:19  lion_eagle  阅读(1917)  评论(0编辑  收藏  举报