합한 요청 버퍼 Hystrix 요청 (II) :이 요청은 가입

이 요청은 가입

머리말

오늘 요청이 캐시의 상세한 분석을하지 않을 수 있습니다, 문제가 바다에서 낚시 부분 Hystrix 요청을 병합 계속하지만 원칙의 발현을 달성하기에 충분 생각합니다.

이 논문은 즉, 합병이 절단 된 비교적 간단한 유스 케이스 요청을 선택하고 분석 CommandCollapserGetValueForKey하지, ObservableCollapserGetWordForNumber원칙은 동일하지만, ObservableCollapserGetWordForNumber비즈니스 구현을위한 풍부한 인터페이스를 제공합니다.

병용 요청

로부터 CommandCollapserGetValueForKey예를보고, 바로 다음과 같은 세 가지 일을 할, 합병 요청을 수행 할 수 있습니다.

1 상속 HystrixCollapser <BatchReturnType, ResponseType, RequestArgumentType> . 각각 세 가지 방법, 재기록 2, getRequestArgument, createCommand, mapResponseToRequests. 3, 기록 BatchCommand, 즉, 결합 된 요청 HystrixCommand.

다음으로,이 세 단계 작업을 통해 달성하기 위해 합병을 요청하는 방법 소스 코드 수준에서 볼 수 있습니다.

HystrixCollapser

  • 참고 <BatchReturnType, ResponseType, RequestArgumentType>일반적인 의미는, 코드 블록에서 해당 주석을 추가되었습니다.
**
 * 根据设定时间参数以及合并请求数,将多个HystrixCommand合并成一次的HystrixCommand,从而将短时间调用服务的次数减少。
 * <p>
 * 通常将时间窗口设为10ms左右
 * 
 * @param <BatchReturnType>
 *           合并后的HystrixCommand的返回类型,例如String变成List<String>。
 * @param <ResponseType>
 *           需要合并的HystrixCommand的返回类型。
 * @param <RequestArgumentType>
 *           需要合并的HystrixCommand的请求参数类型。
 */
public abstract class HystrixCollapser<BatchReturnType, ResponseType, RequestArgumentType> implements HystrixExecutable<ResponseType>, HystrixObservable<ResponseType> {
复制代码

요청 프로세스를 가입

  • 요청이 결합 프로세스 ,이 예로부터 알 수있는 바와 같이, 결합 BatchCommand의 매개 Collection<CollapsedRequest<String, Integer>> requests과정에 참여할 것을 요청 파라미터로부터의 하나의 요청으로 결합되어있다 Collection<CollapsedRequest<ResponseType, RequestArgumentType>>.

  • 따라서에서 getRequestArgument호출 찾기 위해 시작합니다 HystrixCollapser.toObservable.

// 提交请求,直接返回结果了。。。
Observable<ResponseType> response = requestCollapser.submitRequest(getRequestArgument());

/**
     * Submit a request to a batch. If the batch maxSize is hit trigger the batch immediately.
     * 和清楚了将时间窗口内的请求提交,如果到了设定的合并阈值,触发一次合并请求
     * @param arg argument to a {@link RequestCollapser} 
     * @return Observable<ResponseType>
     * @throws IllegalStateException
     *             if submitting after shutdown
     */
    public Observable<ResponseType> submitRequest(final RequestArgumentType arg) {
        /*
         * 启动计时器,时间窗口阈值到了,则触发一次合并请求
         */
        if (!timerListenerRegistered.get() && timerListenerRegistered.compareAndSet(false, true)) {
            /* schedule the collapsing task to be executed every x milliseconds (x defined inside CollapsedTask) */
            timerListenerReference.set(timer.addListener(new CollapsedTask()));
        }

        // loop until succeed (compare-and-set spin-loop)
        // 等待-通知模型
        while (true) {
	        // 拿到RequestBatch
            final RequestBatch<BatchReturnType, ResponseType, RequestArgumentType> b = batch.get();
            if (b == null) {
                return Observable.error(new IllegalStateException("Submitting requests after collapser is shutdown"));
            }

            final Observable<ResponseType> response;
            // 添加到RequestBatch
            if (arg != null) {
                response = b.offer(arg);
            } else {
                response = b.offer( (RequestArgumentType) NULL_SENTINEL);
            }
            // it will always get an Observable unless we hit the max batch size
            // 添加成功,返回 Observable
            if (response != null) {
                return response;
            } else {
                // this batch can't accept requests so create a new one and set it if another thread doesn't beat us
                // 添加失败,执行 RequestBatch ,并创建新的 RequestBatch
                createNewBatchAndExecutePreviousIfNeeded(b);
            }
        }
    }
复制代码
  • offer방법
 public Observable<ResponseType>  offer(RequestArgumentType arg) {
 2:     // 执行已经开始,添加失败
 3:     /* short-cut - if the batch is started we reject the offer */
 4:     if (batchStarted.get()) {
 5:         return null;
 6:     }
 7: 
 8:     /*
 9:      * The 'read' just means non-exclusive even though we are writing.
10:      */
11:     if (batchLock.readLock().tryLock()) {
12:         try {
13:             // 执行已经开始,添加失败
14:             /* double-check now that we have the lock - if the batch is started we reject the offer */
15:             if (batchStarted.get()) {
16:                 return null;
17:             }
18: 
19:             // 超过队列最大长度,添加失败
20:             if (argumentMap.size() >= maxBatchSize) {
21:                 return null;
22:             } else {
23:                 // 创建 CollapsedRequestSubject ,并添加到队列
24:                 CollapsedRequestSubject<ResponseType, RequestArgumentType> collapsedRequest = new CollapsedRequestSubject<ResponseType, RequestArgumentType>(arg, this);
25:                 final CollapsedRequestSubject<ResponseType, RequestArgumentType> existing = (CollapsedRequestSubject<ResponseType, RequestArgumentType>) argumentMap.putIfAbsent(arg, collapsedRequest);
26:                 /**
27:                  * If the argument already exists in the batch, then there are 2 options:
28:                  * A) If request caching is ON (the default): only keep 1 argument in the batch and let all responses
29:                  * be hooked up to that argument
30:                  * B) If request caching is OFF: return an error to all duplicate argument requests
31:                  *
32:                  * This maintains the invariant that each batch has no duplicate arguments.  This prevents the impossible
33:                  * logic (in a user-provided mapResponseToRequests for HystrixCollapser and the internals of HystrixObservableCollapser)
34:                  * of trying to figure out which argument of a set of duplicates should get attached to a response.
35:                  *
36:                  * See https://github.com/Netflix/Hystrix/pull/1176 for further discussion.
37:                  */
38:                 if (existing != null) {
39:                     boolean requestCachingEnabled = properties.requestCacheEnabled().get();
40:                     if (requestCachingEnabled) {
41:                         return existing.toObservable();
42:                     } else {
43:                         return Observable.error(new IllegalArgumentException("Duplicate argument in collapser batch : [" + arg + "]  This is not supported.  Please turn request-caching on for HystrixCollapser:" + commandCollapser.getCollapserKey().name() + " or prevent duplicates from making it into the batch!"));
44:                     }
45:                 } else {
46:                     return collapsedRequest.toObservable();
47:                 }
48: 
49:             }
50:         } finally {
51:             batchLock.readLock().unlock();
52:         }
53:     } else {
54:         return null;
55:     }
56: }
复制代码
  • 38 47 : 리턴 Observable. argumentMap이미 존재 arg에 해당하는 Observable시간, 캐시 (열어야 HystrixCollapserProperties.requestCachingEnabled = true) 함수를. 그 이유는,이 경우, 동일한 arg행 (43)이 달성 될 때, 상기 캐시 사용되지 않은 collapsedRequest.toObservable(), 동일 arg여러 것이다 Observable하고 실행 명령 HystrixCollapserBridge.mapResponseToRequests방법은 (실행할 수 Response받는 할당) arg해당 명령 요청 ( CollapsedRequestSubject), 참조 에 github을 .COM / 넷플릭스 / HYS ... .

  • 다시 찾는 HystrixCollapser#toObservable()방법 코드를, 또한 캐시 기능이 있습니다 그것을 반복하지? argumentMap지시는 RequestBatch레벨 캐시 HystrixCollapser: RequestCollapser: RequestBatch1 : 1 : N의 관계에 의해 HystrixCollapser#toObservable()캐시의 처리 로직을 보장하기 위하여 RequestBatch전환 한 후, 여전히 캐시있다.

  • CollapsedTask윈도우 합병 트리거 시간 내에 요청을 처리에 대한 책임, 사실, 키하다 createNewBatchAndExecutePreviousIfNeeded, 또한라고 executeBatchIfNotAlreadyStarted.

/**
     * Executed on each Timer interval execute the current batch if it has requests in it.
     */
    private class CollapsedTask implements TimerListener {
		        ...
                @Override
                public Void call() throws Exception {
                    try {
                        // we fetch current so that when multiple threads race
                        // we can do compareAndSet with the expected/new to ensure only one happens
                        // 拿到合并请求
                        RequestBatch<BatchReturnType, ResponseType, RequestArgumentType> currentBatch = batch.get();
                        // 1) it can be null if it got shutdown
                        // 2) we don't execute this batch if it has no requests and let it wait until next tick to be executed
                        // 处理合并请求
                        if (currentBatch != null && currentBatch.getSize() > 0) {
                            // do execution within context of wrapped Callable
                            createNewBatchAndExecutePreviousIfNeeded(currentBatch);
                        }
                    } catch (Throwable t) {
                        logger.error("Error occurred trying to execute the batch.", t);
                        t.printStackTrace();
                        // ignore error so we don't kill the Timer mainLoop and prevent further items from being scheduled
                    }
                    return null;
                }

            });
        }
复制代码
  • executeBatchIfNotAlreadyStarted요청 합병 및 실행에! ! !

도 1에서, 통화 HystrixCollapserBridge.shardRequests방법, 명령 요청 []의 N 슬라이스를 복수의 명령 요청 복수. 디폴트의 구현으로 분열되지 않습니다. 2 N [] 명령 요청의 복수의 사이클. (3)는 호출 HystrixCollapserBridge.createObservableCommand에있어서, 병합 명령 요청 복수하는 HystrixCommand를 생성한다. 코드를 볼 수있는 링크를 클릭하십시오.

		...
  // shard batches
                Collection<Collection<CollapsedRequest<ResponseType, RequestArgumentType>>> shards = commandCollapser.shardRequests(argumentMap.values());
                // for each shard execute its requests 
                for (final Collection<CollapsedRequest<ResponseType, RequestArgumentType>> shardRequests : shards) {
                        try {
                        // create a new command to handle this batch of requests
                        Observable<BatchReturnType> o = commandCollapser.createObservableCommand(shardRequests);
           commandCollapser.mapResponseToRequests(o, shardRequests).doOnError(new Action1<Throwable>() {
           ...
复制代码
  • 마지막으로, 구현이 매우 간단합니다, 재정의 된 호출 mapResponseToRequests방법은 것 HystrixCommand다시 해당 요청 그들에게 매핑 명령의 결과.

개요

  • 간단하게 "큐"로, 특정 시간 창 내 요청에 대해 이야기하는 것입니다 넣어 작업이 주기적으로 요청의 요청 ( "큐"에서 것이다 "큐"를 트리거 할 수있다는 또한 "요청 큐를 세분화 될 가능성이 수집 "그 컬렉션 <컬렉션 <>>) 자신을 통해 달성 BatchCommand실행, 합병 전 재 매핑의 최종 결과 HystrixCommand반환 결과.

PS : 나는 많이 보았다 concurrentHashMap, CAS, 원자 변수를. . .

참조

추천

출처juejin.im/post/5da595245188256ab73dcce6