봄 클라우드 댓글 (오) Hystrix 소스 코드 분석

1. @HystrixCommand

첫째, 우리는 @HystrixCommand 코멘트에서 시작

@HystrixCommand(fallbackMethod = "fallBack")
    public String hiService() {
        return restTemplate.getForObject("http://provider/zone?",String.class);
    }

@HystrixCommand,이 클래스의 주요 역할은 명령 모드 명령 패키지의 현재 방법에 대한 주석 HystrixCommand 개체입니다 만듭니다, 다음 두 가지 방법을 실행합니다 :

//用于异步请求,返回的是Future对象,包含服务执行结束时会返回的结果对象。 
public Future<R> queue() {
        /*
         * The Future returned by Observable.toBlocking().toFuture() does not implement the
         * interruption of the execution thread when the "mayInterrupt" flag of Future.cancel(boolean) is set to true;
         * thus, to comply with the contract of Future, we must wrap around it.
         */
        final Future<R> delegate = toObservable().toBlocking().toFuture();
    
        final Future<R> f = new Future<R>() {
            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                if (delegate.isCancelled()) {
                    return false;
                }
                if (HystrixCommand.this.getProperties().executionIsolationThreadInterruptOnFutureCancel().get()) {
                    interruptOnFutureCancel.compareAndSet(false, mayInterruptIfRunning);
        		}

                final boolean res = delegate.cancel(interruptOnFutureCancel.get());

                if (!isExecutionComplete() && interruptOnFutureCancel.get()) {
                    final Thread t = executionThread.get();
                    if (t != null && !t.equals(Thread.currentThread())) {
                        t.interrupt();
                    }
                }

                return res;
			}
            @Override
            public boolean isCancelled() {
                return delegate.isCancelled();
			}
            @Override
            public boolean isDone() {
                return delegate.isDone();
			}
            @Override
            public R get() throws InterruptedException, ExecutionException {
                return delegate.get();
            }
            @Override
            public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
                return delegate.get(timeout, unit);
            }
        	
        };

        /* special handling of error states that throw immediately */
        if (f.isDone()) {
            try {
                f.get();
                return f;
            } catch (Exception e) {
                Throwable t = decomposeException(e);
                if (t instanceof HystrixBadRequestException) {
                    return f;
                } else if (t instanceof HystrixRuntimeException) {
                    HystrixRuntimeException hre = (HystrixRuntimeException) t;
                    switch (hre.getFailureType()) {
					case COMMAND_EXCEPTION:
					case TIMEOUT:
						// we don't throw these types from queue() only from queue().get() as they are execution errors
						return f;
					default:
						// these are errors we throw from queue() as they as rejection type errors
						throw hre;
					}
                } else {
                    throw Exceptions.sneakyThrow(t);
                }
            }
        }

        return f;
    }
//用于同步执行,从依赖服务返回单一对象结果;调用的是queue.get
    public R execute() {
        try {
            return queue().get();
        } catch (Exception e) {
            throw Exceptions.sneakyThrow(decomposeException(e));
        }
    }

HystrixCommand,이 HystrixObservableCommand 같은 두 가지 방법의 주요 업적을 제거합니다 :

  • 는 열 관찰되는 () 관찰
  • 감기 관측이다 toObservable ()

큐, 우리는 다음을 볼 수있는 동안 사실, excute에 () 큐는 ()입니다 달성하기 위해 :

//使用了冷观察;并且转化成为Future异步对象。
final Future<R> delegate = toObservable().toBlocking().toFuture();

따라서 우리는 다음과 같이 두 가지 중요한 부분이 있습니다 Hstrix 명령을 실행 알 수 있습니다 :

  • 이벤트 소스 처리 (저온, 고온 관찰 모드)
  • 비동기 처리 (다른 일 수 있으며, 최종적으로 리턴 앞으로 원하는 결과를 얻을 수있다 비동기 비동기 처리를 사용하여 동기 귀환 기다린 미래 오브젝트)를

그림에 의해 설명 Hystrix 명령 실행에 대한 다음 이야기 :

[그림 체인 덤프 실패 외부 (IMG-nm6ix7mM-1563257116165) (C : \ 사용자 \ SAMSUNG \ 바탕 화면 \ 여름 \ 노트 \ 마이크로 서비스 아키텍처 \ Snipaste_2019-07-15_16-41-12.jpg)]

2. HystrixCircuitBreaker 차단기

Hystrix, 차단기의 핵심 개념에서, 다음의 정의는 다음과 같습니다

public interface HystrixCircuitBreaker {

    //每个Hystrix命令请求,在执行之前,都会调用这个方法,判断当前是否可以执行。
    public boolean allowRequest();
	//判断开闭状态
    public boolean isOpen();
	//当断路器处于半开状态,且命令运行成功,则用于关闭断路器
    void markSuccess();
    }
    

회로 차단기의 다수의 내부 클래스를 사용하여 구현 :

//都不实现
static class NoOpCircuitBreaker implements HystrixCircuitBreaker {
        @Override
        public boolean allowRequest() {
            return true;
        }
        @Override
        public boolean isOpen() {
            return false;
        }
        @Override
        public void markSuccess() {
        }
    }
  //默认实现
  static class HystrixCircuitBreakerImpl implements HystrixCircuitBreaker {
        private final HystrixCommandProperties properties;
        private final HystrixCommandMetrics metrics;
        /* track whether this circuit is open/closed at any given point in time (default to false==closed) */
        private AtomicBoolean circuitOpen = new AtomicBoolean(false);
        /* when the circuit was marked open or was last allowed to try a 'singleTest' */
        private AtomicLong circuitOpenedOrLastTestedTime = new AtomicLong();
    //还有具体几个方法的实现。
  }

회로 차단기, 회로 차단기는 회로 차단기이 HystrixCommand 명령을 수행하거나 대체 하향 개방 및 측정 항목에 따라 차단기를 개폐를 호출할지 여부를 결정하기 위해 설정되어 있는지, 상태 자체에 기초 할 것이며, 메트릭 계수는 healthCount 의해 취득 된 오브젝트 , 10S이 시간 창 기본값을 판단 :

  • 미리 설정된 임계 값 내에서 QPS, false를 반환, 기본값은 20입니다.
  • 요청이 미리 설정된 임계 값 아래의 오류 비율 인 경우는 false를 돌려줍니다.

소스는 다음과 같습니다 :

 @Override
        public boolean isOpen() {
            if (circuitOpen.get()) {
                return true;
            }
            HealthCounts health = metrics.getHealthCounts();
            // check if we are past the statisticalWindowVolumeThreshold
            if (health.getTotalRequests() < properties.circuitBreakerRequestVolumeThreshold().get()) {
                // we are not past the minimum volume threshold for the statisticalWindow so we'll return false immediately and not calculate anything
                return false;
            }
            if (health.getErrorPercentage() < properties.circuitBreakerErrorThresholdPercentage().get()) {
                return false;
            } else {
                // our failure rate is too high, trip the circuit
                if (circuitOpen.compareAndSet(false, true)) {
                    // if the previousValue was false then we want to set the currentTime
                    circuitOpenedOrLastTestedTime.set(System.currentTimeMillis());
                    return true;
                } else {
                    return true;
                }
            }
        }

허용할지 여부를 결정합니다 :

 @Override
        public boolean allowRequest() {
          //这个地方要注意,我们看到了,强制开启的优先级大于强制关闭。
            if (properties.circuitBreakerForceOpen().get()) {
                return false;
            }
            if (properties.circuitBreakerForceClosed().get()) {
                isOpen();
                return true;
            }
          	//这里通过两个方法的结合使用,实现关闭、开启的切换
            return !isOpen() || allowSingleTest();
        }
//这个方法的功能是尝试允许命令请求;
 public boolean allowSingleTest() {
            long timeCircuitOpenedOrWasLastTested = circuitOpenedOrLastTestedTime.get();
            // 1) if the circuit is open
            // 2) and it's been longer than 'sleepWindow' since we opened the circuit
            if (circuitOpen.get() && System.currentTimeMillis() > timeCircuitOpenedOrWasLastTested + properties.circuitBreakerSleepWindowInMilliseconds().get()) {
                // We push the 'circuitOpenedTime' ahead by 'sleepWindow' since we have allowed one request to try.
                // If it succeeds the circuit will be closed, otherwise another singleTest will be allowed at the end of the 'sleepWindow'.
                if (circuitOpenedOrLastTestedTime.compareAndSet(timeCircuitOpenedOrWasLastTested, System.currentTimeMillis())) {
                  //尝试允许请求,则使得断路器处于半开状态。
                    return true;
                }
            }
            return false;
        }

위를 구현하기 위해 요청을 허용 :

  • allowSingleTest으로 액세스 요청을 허용하려고합니다.
  • 과거의 수면 시간 후에, 상기 슬립 시간을 설정하고, 회로 차단기는 "반 개방 상태",이 반 개방 상태로되어 있지만, 실제 요청은 타임 아웃을 수행하지 못할 경우, 또는 명령 실행, 그 회로 차단기를 설정하도록 인 완전 개방 상태에 위치하며, 수면 시간 후, 시도는 반 개방 상태로 계속 허용했다.

다음을 달성하기 위해 회로 차단기의 전원을 끄십시오

   public void markSuccess() {
            if (circuitOpen.get()) {
              //关闭断路器
                if (circuitOpen.compareAndSet(true, false)) {
                    //win the thread race to reset metrics
                    //Unsubscribe from the current stream to reset the health counts stream.  This only affects the health counts view,
                    //and all other metric consumers are unaffected by the reset
                  //重置统计信息
                    metrics.resetStream();
                }
            }
        }

 

 

출시 팔 개 원래 기사 · 원의 칭찬 0 · 조회수 7270

추천

출처blog.csdn.net/fedorafrog/article/details/104159205