0

在我的 Quarkus 服务中,我需要从外部服务获取结果列表,我发现有两种方法可以实现相同的目标:

第一种方法基于Uni.combine().all()

List<Uni<Result>> results = new ArrayList();
for (Parameter p : parameters) {
  // callService returns Uni<Result>
  results.add(callService(p));
}
// collect all the results
Uni<List<Result>> combined = Uni.combine().all().unis(results)...

第二种方法基于Multi..onItem().transformToMultiAndConcatenate().collect()

Multi.createFrom().iterable(parameters)
.onItem()
.transformToMultiAndConcatenate(p -> callService(p))
.collect().asList()

一开始,我认为这两种方法之间没有任何真正的区别,因为Uni它们是懒惰地评估的,或者Uni.combineMulti.collect我来说就像语法糖一样。但是我还是想问一下有没有区别?特别是性能方面的差异。

使用第一种方法,我正在调试一个错误,当大小parameters超过 25 时它开始给出错误但低于 25 就可以了。因此,我怀疑第一种方法会导致非常高的 QPS 淹没外部服务。但是,我怀疑第二种方法也有助于节流。

4

1 回答 1

6

Uni组合之间的并发模型(Uni.combine().all().uni(...)),transformToMultiAndConcatenate并且transformToMultiAndMerge是不同的。

Uni 组合同时运行所有通过的 Uni。所以如果你通过了,比如说 100 个 unis,所有 100 个 unis 都将同时执行。在您的情况下,这意味着发送 100 个请求。所以,是的,最好确保远程服务优雅地处理并发请求。组合函数以与组合 unis 相同的顺序接收结果列表。因此结合 UniA 和 UniB 将产生一个包含 ResponseForA、ResponseForB 的列表。

transformToMultiAndConcatenate并发transformToUniAndConcatenate级别为 1。基本上,它分别从上游获取每个项目,调用您的服务,完成后切换到下一个项目。所以,这里没有太多的并发。但是,它保证响应与上游项目的顺序相同。因此,如果您将 [A, B, C] 作为上游项目,则生成的 multi 将是 [对 A 的响应,对 B 的响应,对 C 的响应]。

transformToMultiAndMerge并将transformToUniAndMerge同时执行一些请求。默认并发为 128。因此,它将消耗来自上游的 128 个项目并调用您的远程服务。响应可能没有顺序。一旦收到一个响应,就会消耗另一个项目。所以 [A, B, C] 可能会产生 [对 B 的响应,对 C 的响应,对 A 的响应]。

使用合并时,可以使用以下方式配置并发:multi.onItem().transformToMulti(mapper).merge(concurrency)

供参考:

于 2021-05-12T08:34:14.743 回答