Spring boot 如何在SpringBoot2中通过阻塞调用解决吞吐量慢的问题?

Spring boot 如何在SpringBoot2中通过阻塞调用解决吞吐量慢的问题?,spring-boot,asynchronous,project-reactor,throughput,Spring Boot,Asynchronous,Project Reactor,Throughput,我使用SpringBoot2和路由器功能,如果没有阻塞代码,一切都很好,但如果我阻塞了2秒钟,那就太糟糕了。我的应用程序无法访问大量并发用户,也无法提高吞吐量 Doc有一个部分,但这种方法不能解决问题 return serverRequest .bodyToMono(ValueDto.class) .doOnNext(order -> log.info("get order request " + order))

我使用SpringBoot2和路由器功能,如果没有阻塞代码,一切都很好,但如果我阻塞了2秒钟,那就太糟糕了。我的应用程序无法访问大量并发用户,也无法提高吞吐量

Doc有一个部分,但这种方法不能解决问题

    return serverRequest
            .bodyToMono(ValueDto.class)
            .doOnNext(order -> log.info("get order request " + order))
            .map(i -> {
                log.info("map 1 " + requestId);
                return i;
            })
            .map(i -> {
                log.info("map 2 " + requestId);
                return i;
            })
            .map(i -> {
                log.info("map 3 " + requestId);
                return i;
            })
            .flatMap(i -> Mono.fromCallable(() -> executeLongMethod(i, requestId))
                    .subscribeOn(Schedulers.elastic()))
            .map(v -> {
                log.info("map 5 " + requestId);
                return v;
            })
            .flatMap(req -> ServerResponse.ok().build());


private ValueDto executeLongMethod(final ValueDto dto, final String requestId) {
    final long start = System.currentTimeMillis();
    try {
        log.info("start executeLongMethod. requestId:" + requestId);


        TimeUnit.MILLISECONDS.sleep(1500);

        return dto;
    } catch (InterruptedException e) {
        e.printStackTrace();
        return dto;
    } finally {
        log.info("finish executeLongMethod requestId:" + requestId + " executed in " + (System.currentTimeMillis() - start) + "ms.");
    }
}
我创建了简单的springboot2应用程序,在其中重新创建了问题

    return serverRequest
            .bodyToMono(ValueDto.class)
            .doOnNext(order -> log.info("get order request " + order))
            .map(i -> {
                log.info("map 1 " + requestId);
                return i;
            })
            .map(i -> {
                log.info("map 2 " + requestId);
                return i;
            })
            .map(i -> {
                log.info("map 3 " + requestId);
                return i;
            })
            .flatMap(i -> Mono.fromCallable(() -> executeLongMethod(i, requestId))
                    .subscribeOn(Schedulers.elastic()))
            .map(v -> {
                log.info("map 5 " + requestId);
                return v;
            })
            .flatMap(req -> ServerResponse.ok().build());


private ValueDto executeLongMethod(final ValueDto dto, final String requestId) {
    final long start = System.currentTimeMillis();
    try {
        log.info("start executeLongMethod. requestId:" + requestId);


        TimeUnit.MILLISECONDS.sleep(1500);

        return dto;
    } catch (InterruptedException e) {
        e.printStackTrace();
        return dto;
    } finally {
        log.info("finish executeLongMethod requestId:" + requestId + " executed in " + (System.currentTimeMillis() - start) + "ms.");
    }
}
通过Jmeter执行自动负载测试。It设置:

线程组:

线程数:测试期间要运行的并发线程数:30

爬升周期:在此时间内,线性增加负载从0到目标负载:1

循环计数:永远

后请求:{ “valueA”:“假”, “valueB”:“假”, “valueC”:“假” }

结果:


可以找到代码示例

不要使用线程。睡眠。。。以非阻塞方式睡眠(使用
delayElement
)。这样,您将阻止处理和.or请求处理线程,甚至可能阻止整个反应线程,从而导致您停止。谢谢,但在本例中,
thread.sleep
-示例。我可以调用soap或其他阻塞操作。我尝试了
.flatMap(I->Mono.just(I).delayElement(Duration.ofMillis(1500))
但它并没有提高吞吐量。如果所有可用线程都被阻塞,那么当然什么也不会发生。最终,一切都将被阻止,通常采用反应式方法,您可以有较少的线程来完成相同的工作量。@M.Deinum当然,阻止API不适合此并发模型。但是当chain调用Schedulers.elastic()-时,它会在不同的线程上继续处理,因为会将处理切换到不同的线程池。我认为这可以改善情况。你们有多少个CPU?