是时候考虑Spring非阻塞编程模式

开发 架构
Spring框架中,同时存在WebFlux和R2DBC这样的响应式模块,也存在Web MVC和JDBC这样的阻塞框架。应该在什么情况下使用不同技术栈,可能会困扰很多技术人。本文作者对这两种技术栈做了详细的对比和压力测试,为技术选型提供支持。

 [[325186]]

导读:Spring框架中,同时存在WebFlux和R2DBC这样的响应式模块,也存在Web MVC和JDBC这样的阻塞框架。应该在什么情况下使用不同技术栈,可能会困扰很多技术人。本文作者对这两种技术栈做了详细的对比和压力测试,为技术选型提供支持。

2017年9月发布的Spring Framework 5中,引入了Spring WebFlux。WebFlux是完全响应式的技术栈。2019年12月发布了Spring Data R2DBC,这是一个使用响应式的数据库驱动。在本文中,我将证明在高并发下,WebFlux和R2DBC表现更好。该组合的响应时间和吞吐量都更好。并且在处理每个请求时使用更少的内存和CPU,而且你的Fat JAR会变得更小。在高并发的时候,使用WebFlux和R2DBC(如果你不需要JPA的话)是个好主意。

测试方法

本文中,我们尝试了如下四种组合:

  • Spring Web MVC + JDBC 数据库驱动
  • Spring Web MVC + R2DBC 数据库驱动
  • Spring WebFlux + JDBC 数据库驱动
  • Spring WebFlux + R2DBC 数据库驱动

我已经将并行请求数以50个为单位从4增加到500,分别为负载生成器和服务分配4个核心(我的笔记本有12个核心)。我将所有的连接池都配置为100。为什么要固定核数和连接池的大小?因为在之前对JDBC和R2DBC的测试中,改变这些因素并没有提供更多的数据,所以我决定在这个测试中保持固定的变量,以减少测试需要运行的时间。

我在服务上模拟一个GET请求。该服务从数据库中获取了10条记录,并以JSON形式返回。首先,我对服务进行了2秒预热。接下来,我开始了1分钟的基准测试。我把每个场景运行5次(依次运行,而非5次之后再运行其他测试),并计算结果的平均值。我只统计了那些没有错误的测试。当我将并发数增加到1000以上时,所有的实现都无一例外地有失败。

我使用了Postgres(12.2)作为数据库。并且使用wrk来进行基准测试。我用下面的方法解析wrk的输出。主要测量:

  • 响应时间—来自Wrk测试报告
  • 吞吐量(请求数)— 来自Wrk测试报告
  • 进程CPU的使用情况—用户和内核时间(基于/proc/PID/Stat)
  • 内存使用量—私有和共享进程内存(基于/proc/PID/maps)

你可以在这里查看所使用的测试脚本[1]。你可以在这里查看所使用的代码[2]。

测试结果

你可以在这里查看我在图表中使用的原始数据[3]。

响应时间

很显然在高并发下,Spring Web MVC + JDBC可能不是你的最佳选择。显然在更高的并发下,R2DBC可以提供更好的响应时间。Spring Web MVC和Spring WebFlux也有类似的趋势。

吞吐量

与响应时间类似,使用JDBC+Spring Web MVC在高并发下表现得更差。同样的,R2DBC显然表现的更胜一筹。如果你的后端仍然使用JDBC,那么从Spring Web MVC转移到Spring WebFlux也并不是一个好主意。在低并发时,Spring Web MVC + JDBC 表现最好。

CPU

CPU是指整个运行过程中的CPU时间,即进程用户和内核时间之和。

使用JDBC+Web MVC的方案在高并发时消耗的CPU最高。JDBC+WebFlux的方案使用的CPU时间最少,但吞吐量也最低。当你查看平均每请求所使用的CPU时,你就可以衡量各种方式的CPU使用效率。

与JDBC相比,R2DBC平均每个请求使用的CPU更少。使用JDBC+WebFlux似乎不是一个好主意。JDBC+Web MVC在高并发量的情况下更加糟糕,而其他至少有一个非阻塞组件的实现更稳定。然而在低并发时,Web MVC + JDBC可以最有效地利用CPU。

内存

我们测量在运行结束时进程私有内存作为内存消耗量。内存使用情况取决于垃圾回收。我们使用JDK 11.0.6和G1GC。Xms 设置为 0.5 Gb (默认是我可用内存32 Gb 的 1/64)。Xmx 设置为 8 Gb (默认是我可用内存 32 Gb 的 1/4)。

与Web MVC相比,WebFlux的内存使用量似乎更稳定,而WebMVC在高并发时的内存使用量更大。当使用WebFlux+R2DBC时,在高并发情况下,内存使用量最少。在低并发时,Web MVC + JDBC内存使用较低,但在高并发时,WebFlux + R2DB平均每个请求处理中使用的内存最少。

Fat Jar大小

下图中JPA占用了大头。如果你使用R2DBC的情况下不使用它,那么Fat JAR大小就会下降到15Mb左右!

总结

  • R2DBC+WebFlux是高并发时的好主意!
  • 在高并发时,使用R2DBC代替JDBC和使WebFlux代替Web MVC的好处显而易见。
  • 处理单个请求所需的CPU更少。
  • 处理单个请求所需的内存更少。
  • 高并发时的响应时间更低。
  • 高并发时的吞吐量更好
  • Fat JAR较小(不使用JPA)。
  • 当只使用阻塞组件时,在高并发时,内存和CPU的使用效率会降低。
  • JDBC+WebFlux似乎不是一个好主意。R2DBC+Web MVC在高并发时比JDBC+Web MVC效果更好。
  • 你不需要使用完全无阻塞的堆栈来获得使用R2DBC的优势。但是,如果是使用Spring,最好将其与WebFlux结合起来。
  • 在低并发量(200个并发请求以下)时,使用Web MVC和JDBC可能会有更好的效果。通过测试来确定平衡点。

使用R2DBC时的一些挑战

  • JPA无法处理像Spring Data R2DBC提供响应式功能。这意味着在使用R2DBC时,你将不得不手动做更多工作。
  • 还有其他响应式驱动,例如Quarkus Reactive Postgres客户端(使用Vert.x)。他们不使用R2DBC,并且有不同的性能特性。
  • 有限的可用性
  • 不是所有的关系型数据库都有响应式的驱动程序。例如,Oracle还没有R2DBC实现。
  • 应用服务器仍然依赖于JDBC。在这个Kubernetes时代,人们还在使用那些上古功能吗?
  • 当Java Fibers推出的时候(Project Loom,可能是Java 15),数据库驱动的格局可能会再次发生变化,R2DBC可能不会成为JDBC的继任者。

原文地址:

https://technology.amis.nl/2020/04/10/spring-blocking-vs-non-blocking-r2dbc-vs-jdbc-and-webflux-vs-web-mvc/

文中链接:

[1]https://github.com/MaartenSmeets/db_perftest/blob/r2dbc/test_scripts/run_test.py

[2]https://github.com/MaartenSmeets/db_perftest/tree/r2dbc/test_apps

[3]https://github.com/MaartenSmeets/db_perftest/blob/r2dbc/test_scripts/restotal.txt

本文转载自微信公众号「高可用架构」,可以通过以下二维码关注。转载本文请联系高可用架构公众号。

 

责任编辑:武晓燕 来源: 高可用架构
相关推荐

2021-02-04 10:50:11

网络安全非阻塞模Winsock编程

2011-12-07 17:17:02

JavaNIO

2017-03-07 15:07:23

叶脊网络架构

2021-02-27 16:08:17

Java异步非阻塞

2022-06-22 08:16:29

异步非阻塞框架

2021-06-04 18:14:15

阻塞非阻塞tcp

2014-04-08 15:27:57

Windows Ser

2015-07-03 10:12:04

编程同步非阻塞

2023-10-26 16:06:50

BuildpackDocker

2020-08-26 10:23:24

物联网数据IOT

2015-04-07 10:51:05

2017-03-01 16:40:12

Linux驱动技术设备阻塞

2019-07-23 11:01:57

Python同步异步

2022-09-22 10:51:32

服务端开发者异步非阻塞编程

2012-10-10 10:00:27

同步异步开发Java

2013-07-18 14:18:19

机器智商

2012-02-22 21:15:41

unixIO阻塞

2018-03-28 08:52:53

阻塞非阻塞I

2023-02-14 14:32:39

2023-12-06 07:28:47

阻塞IO异步IO
点赞
收藏

51CTO技术栈公众号