Reactor学习-五——回压和重塑请求
在 Reactor 中实现背压时,消费者压力传播回源的方式是向request上游操作员发送。当前请求的总和有时被称为当前“需求”或“待处理请求”。需求上限为Long.MAX_VALUE,代表一个无限制的请求(意思是“尽可能快地生产”——基本上是禁用背压)。
第一个请求来自订阅时的最终订阅者,但最直接的订阅方式都立即触发无限制请求Long.MAX_VALUE:
-
subscribe()以及它的大多数基于 lambda 的变体(有Consumer的除外)
-
block(),blockFirst()和blockLast()
-
迭代一个toIterable()或toStream()
自定义原始请求的最简单方法自定义Subscribier类继承自BaseSubscription重写hookOnSubscribe方法。
Flux.range(1, 10)
.doOnRequest(r -> System.out.println("request of " + r))
.subscribe(new BaseSubscriber<Integer>() {
@Override
public void hookOnSubscribe(Subscription subscription) {
request(1);
}
@Override
public void hookOnNext(Integer integer) {
System.out.println("Cancelling after having received " + integer);
cancel();
}
});
output:
request of 1
Cancelling after having received 1
在处理请求时,您必须小心为序列的推进产生足够的需求,否则您的 Flux 可能会“卡住”。这就是为什么BaseSubscriber 在hookOnSubscribe. 当覆盖这个钩子时,你通常应该至少调用request一次。
从下游改变需求的操作
要记住的一件事是,在订阅级别表达的需求可以由上游链中的每个操作重新塑造。一个教科书案例是buffer(N)运算符:如果它接收到一个request(2),它被解释为对两个完整缓冲区的需求。因此,由于缓冲区需要N将元素视为已满,因此buffer操作将请求重新整形为2 x N.
您可能还注意到,一些操作的参数变量采用int类型,称为预读(prefetch)。这是修改下游请求的另一类操作。这些通常是处理内部序列的操作,从每个传入元素衍生一个Publisher(如flatMap)。
预读是一种调整对这些内部序列发出的初始请求的方法。如果未指定,这些运算符中的大多数都以32开始.
这些操作通常还实现了优化重新装填:一旦操作完成了 75% 的预读取请求,它就会从上游重新请求 75%。这是一种启发式优化,以便这些操作主动预测即将到来的请求。
最后,有几个方法可以让您直接调整请求:limitRate和limitRequest.
limitRate(N)拆分下游请求,以便它们以较小的批次向上游传播。例如,发出的请求100最多limitRate(10)会导致10请求10被传播到上游。请注意,在这种形式中,limitRate实际上实现了前面讨论的预读优化。
操作有一个变量,还可以让您调整补充量(lowTide在变量中称为低潮 ):limitRate(highTide, lowTide)。选择a lowTide of 0会产生严格的highTide请求批次,而不是通过读取策略进一步返工的批次。
limitRequest(N),另一方面,将下游请求限制为最大总需求。它将请求加起来高达N. 如果单个请求request没有使总需求溢出N,则该特定请求将完全传播到上游。在源发出该数量后,limitRequest认为序列完成,向下游发送onComplete信号,并取消源。