参加要求
序文
今日は一部のHystrix要求をマージ荒れた海で釣りを続け、要求がキャッシュのように詳細な分析ではないかもしれないが、私は原則の発現を達成するのに十分な感じ。
本論文では、合併を切断し、分析し、それがあるし、比較的単純なユースケース要求選んだのCommandCollapserGetValueForKey
ではなく、ObservableCollapserGetWordForNumber
原則は同じですが、ObservableCollapserGetWordForNumber
事業実施のためのより豊かなインターフェースを提供します。
併用要求
以下からCommandCollapserGetValueForKey
の例が見て、ちょうど次の三つのことを行う、合併は、要求を満たすことができるようになります。
1、相続HystrixCollapser <BatchReturnType、ResponseType、RequestArgumentType> 。それぞれ3つの方法が、書き換え2、 、
getRequestArgument
、。createCommand
mapResponseToRequests
図3に示すように、書き込みBatchCommand
、即ち、組み合わせ要求HystrixCommand
。
次は、この3ステップの操作を通じて達成するために合併を要求するために、どのように、ソースコードレベルから見ることができます。
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
:RequestBatch
で、Nの関係:1:1に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、アトミック変数。。。
リファレンス
- github.com/Netflix/Hys...
- 同時に実行するコマンド - Hystrixは、ソースコードを解析します