使用一些阻塞操作构建 Spring Reactive API 是不是“可以”

Posted

技术标签:

【中文标题】使用一些阻塞操作构建 Spring Reactive API 是不是“可以”【英文标题】:Is it "okay" to build a Spring Reactive API with some Blocking Operations使用一些阻塞操作构建 Spring Reactive API 是否“可以” 【发布时间】:2021-07-25 16:50:03 【问题描述】:

我刚刚开始使用 Spring,我想为我正在处理的项目构建一个 RESTful API。我的后端有很多对第三方服务的 HTTP 调用,我决定谨慎地实现响应式设计并让架构是非阻塞的。我正在使用 Retrofit,它有一个基于回调的异步 API,对我来说可以正常工作。这就是问题所在;我已经使用 Hibernate 和 JPA 实现了我的数据库和模型,它非常成熟,可以处理从迁移到验证以及介于两者之间的所有事情,我喜欢使用 JPA,但它是阻塞的,因此不适合我的架构设计。是否可以在其他任何地方都使用响应式堆栈,并在工具和框架几乎与 JPA 相当时将持久性内容迁移到响应式模型?主要问题是在启动时创建数据库模式,如果有解决方案,我很乐意使用它。

【问题讨论】:

如果还不算太晚的话,还有带有 Vert.x 客户端的 Reactive Hibernate 堆栈。 hibernate.org/reactive/documentation/1.0/reference/html_single/…。有一个 javax.persistence.create-database-schemas 属性可能是您正在寻找的东西。 @Ghokun 非常感谢!我已经查看了可用的响应式持久性选项,我想我认为唯一可用的东西是org.springframework.boot:spring-boot-starter-data-r2dbc 是理所当然的,我将研究 hibernate 响应式。再次感谢您 【参考方案1】:

从性能角度来看,在任何完全反应式的 webflux 应用程序中阻塞都是不好的。

Webflux 从很少数量的线程开始,这意味着如果您阻塞,您的应用程序(在负载下)很可能会受到线程饥饿的影响,这是因为在反应式应用程序中不会产生新线程,并且您的应用程序小线程池将被阻止等待来自您的数据库的响应。

有一种解决方法是您使用subscribeOn 运算符将所有潜在的阻塞调用放在它自己的调度程序上。这记录在reactor documentation

请记住,通过包装阻塞调用,您不会从反应式编程中获得好处,例如更小的内存占用和更高的吞吐量。但至少你不会遭受线程饥饿的痛苦。

这些调用的行为类似于对“常规 Spring Boot Web 服务器”的“常规调用”,因为这些调用将被分配一个线程,该线程将在整个执行过程中跟随调用。

【讨论】:

感谢您提供信息和解决方法。我认为我对混合和匹配这两种范式所涉及的风险有了更好的把握。我将继续阅读更多的反应器文档以捕捉更多的边缘情况。谢谢!

以上是关于使用一些阻塞操作构建 Spring Reactive API 是不是“可以”的主要内容,如果未能解决你的问题,请参考以下文章

spring boot 整合Vert.x

Spring Reactive Programming with Webflux - 多个操作作为非阻塞流

Spring.Cloud Gateway——架构分析

Spring.Cloud Gateway——架构分析

Spring.Cloud Gateway——架构分析

Spring WebFlux创建了无阻塞线程池