如果进行单个同步调用,Webflux会发生什么?

7
我将开始学习使用Spring Boot中的Webflux进行反应式Java编程。
我遇到了一个场景,这个场景中对数据库进行反应式地调用非常困难。
如果我在Mono中进行一次阻塞式的数据库调用,会发生什么?
代码可能如下所示...
public Mono<ReturnThing> isThisAsyncOrNot() {
    //Async, non-blocking API call
    return webClient.doSomeAPIWork()
                     .flatMap(whatevers -> {
                         //Synchronous, blocking database call
                         ReturnThing returnThing= returnThingRepo.getByWhateverId(whatever.ID);
                         }
                         return returnThing;
                     });
}

现在我知道有一种反应式的简单方法来解决这个问题。但这不是我要问的问题(实际代码相当复杂)。

我真正想知道的是同步数据库调用会对我的性能产生什么影响。整个方法是否仍然是异步非阻塞的(除了进行数据库调用的部分是阻塞的)?还是这样做会破坏整个反应式范例,导致整个过程从头到尾都变成阻塞的?


我很惊讶你在flatMap()中使用的lambda方法返回了ReturnThing而不是Mono。我理解你想简化你的代码,但现在有些混淆了。你的getByWhateverId()方法返回的是Mono(但如果是这种情况,它是响应式的),还是你的意思是使用map()而不是flatMap() - Honza Zidek
2个回答

8
记住的黄金法则是,你永远无法使阻塞方法变为非阻塞方法。你可以轻而易举地反过来做,还可以采取各种方法不会完全破坏反应式范例,但没有办法使其本质上异步。
更糟糕的是,不幸的是这样做。假设它不会使应用程序崩溃,它将导致少数反应式线程之一(或者可能是唯一的反应式线程)在执行阻塞数据库调用时被阻塞。这意味着在那个阻塞的数据库调用完成之前,需要使用该线程的所有其他反应式操作(这很可能是整个应用程序)都必须等待,这对性能是一个重大打击。
处理这类情况(需要从反应链中进行阻塞调用)的可接受方式是使用有限弹性调度器,它将执行委派给后端线程池,以便不要捆绑主事件线程。

请问您能否看一下我的问题,链接在这里:https://dev59.com/1XkPtIcB2Jgan1znrN5r - Honza Zidek

8

你需要理解响应式编程的关键点,这样你就能自己回答这个问题。在响应式编程中,每个操作符逐个处理数据项。每个操作符还有一个队列,在操作符繁忙时可以将数据项排队。现在考虑以下代码:

Flux.fromIterable(Arrays.asList(1,2,3,4,5))
    .flatMap(a -> {
         Thread.sleep(2000);
         return Mono.just(a);
    }).subscribe(System.out::println);

您会看到项目每隔2秒打印一次。这是由于flatMap的线程被阻塞了2秒钟,而其余元素则排队等待。如果flatMap的线程想要从其队列中消耗项,它必须释放。

在您的情况下,您说DB调用是阻塞的。这将导致调用线程被阻塞。因此,您的方法既不是非阻塞也不是异步。但是,请尝试做类似以下的事情

Mono.just(whatever)
    .subscribeOn(Schedulers.elastic())
    .flatMap(whatever -> returnThingRepo.getByWhateverId(whatever.ID));

使用 flatMap,您的方法将变得非阻塞异步。这是因为一旦调用.subscribeOn()操作符,调用线程就会立即释放。

希望这回答了您的问题。

这并不违反响应式编程范例。在我看来,响应式编程不仅仅是指非阻塞的异步操作。除了NIO,惯用性和易于多线程处理能力也是一个很大的优势。


我意识到我来晚了,但我有一个问题。如何在测试中验证一旦调用.subscribeOn()操作符,线程就变为空闲状态?我现在已经将其添加到我的项目中,但我不确定是否使用正确。我在subscribeOn之后使用了几个操作符,例如doOnNext、collectList、flatMap,其中包含阻塞代码。 - Terje Andersen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接