响应式编程比非响应式编程消耗更多的资源吗?

Ghi*_*ain 6 java reactor spring-boot spring-io project-reactor

我们目前正面临Spring webFlux的性能问题。为了确定反应式编程的好处,我们实现了Spring Boot服务,该服务从MongoDB中获取数据,并通过REST API将其返回给使用者。

该服务有两种变体:

  1. 使用Spring Boot MongoRepository的非反应式实现。该服务以列表形式返回数据
  2. 使用Spring Boot,ReactiveMongoRepository,spring-boot-starter-webflux的反应式实现。该服务将数据返回为Flux。

在这两种实现中,REST控制器都直接从存储库中获取数据,并将其作为List resp返回。作为助焊剂。不再执行任何应用程序逻辑。

我们对100个调用该服务的用户进行了小规模的负载/性能测试,我们发现非反应式实施的性能远好于反应式实施。

事实上,不仅非反应式实现具有更好的HTTP吞吐量,而且也许更有趣的是,与反应式实现相比,它消耗更少的CPU和更少的线程!这与预期特别相反,因为我们预计反应式版本会以少量线程扩展,如https://spring.io/blog/2016/07/28/reactive-programming-with-spring-5-0中所述-m1

我们需要在设置中进行一些调整吗?

有人遇到过类似的问题吗?

Apu*_*urv 7

我们使用 Spring-Data-Reactive-Cassandra 和 Spring-Webflux 针对 Spring-Data-Cassandra 和 Spring-MVC 进行了类似的测试。

我们对两台服务器进行了 10000 个请求和 100 个请求/秒并发度的基准测试。结果并不令人惊讶:-

Non Reactive Stack:-
         Concurrency Level:      100
         Time taken for tests:   22.945 seconds
         Complete requests:      10000
         Failed requests:        0
         Percentage of the requests served within a certain time (ms)
           50%    190
           66%    253
           75%    288
           80%    314
           90%    384
           95%    465
           98%    627
           99%    824
          100%   1208 (longest request)

Reactive Stack:-
         Concurrency Level:      100
         Time taken for tests:   30.061 seconds
         Complete requests:      10000
         Failed requests:        0
         Percentage of the requests served within a certain time (ms)
           50%    304
           66%    379
           75%    421
           80%    443
           90%    507
           95%    589
           98%    694
           99%    736
          100%    858 (longest request)
Run Code Online (Sandbox Code Playgroud)

在执行这些测试时,非反应式堆栈生成了 147 个线程,而反应式堆栈生成了 48 个线程。

如果比较结果,就会发现非反应式堆栈比反应式堆栈稍快一些。它在大约 23 秒内将 10,000 个对象持久保存在数据库中,而反应式堆栈则花费了大约 30 秒。但是,如果比较两个堆栈中最慢的 2% 请求,反应式堆栈几乎快了 28%。

线程数量较少的反应式堆栈具有更均匀分布的响应时间。没有一个请求被搁置。而对于非反应式堆栈,1% 的请求相对而言非常慢。

在持续一段时间内增加调用数量时,与非反应式堆栈相比,反应式堆栈将能够更好地扩展。由于与可以在服务器上打开的套接字数量相比,您可以在服务器上生成的线程数量要少得多。此外,在这些测试中,两种情况下的 CPU 利用率均低于 33%,从而证明 CPU 利用率并未限制可扩展性。

如果非反应式堆栈不受线程上下文切换和线程创建的限制,那么它可以扩展得更多。


小智 2

让我尝试解释这种行为的可能原因。反应式应用程序的运行速度并不比反应式应用程序快。如果请求队列不为空,反应式应用程序不允许系统处于空闲状态。由于您是在低负载下进行测试的,因此您没有看到反应式应用程序的优缺点,但您已经看到了性能下降。性能低于非活动应用程序的性能,因为反应式执行的开销很小。