本文介绍了当我们有阻塞调用时,我们应该使用像Spring Webflow这样的反应式堆栈Web框架吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道我们什么时候会使用像WebFlux这样的反应式堆栈框架。我读过的文章似乎表明,当我们有许多阻止呼叫时,我们将受益于被动方法。例如,如果我们有一个需要调用客户端服务器以使用信息更新它们的WebHook服务。

但我也在这里阅读https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html

而这似乎表明了恰恰相反的情况。我读到,如果你能将信息串流,被动反应会更有用。例如,如果您有一个前端请求一个列表和一个被动来源,它可以在信息变得可用时为您提供信息,而不是在完成时仅提供所有信息。

所以问题是,我们应该在什么时候为后端使用反应性?当我们有许多阻止呼叫时,我们应该使用它吗?例如,对我们需要等待响应的客户端的HTTP调用。或者这完全不是它的用例?

我知道还有其他考虑因素,比如代码的复杂性。我知道被动方法更难实现,但我在这里只是询问性能和可伸缩性。

推荐答案

这里很难给您任何具体的答案,因为我们不知道您的确切架构。

但如果您了解Reactive试图解决的问题,以及它是如何解决的,可能会让您更好地了解如何做出更好的决策。

Java中的大多数Web服务器使用的传统Servlet方法为每个请求分配一个线程。因此,当一个请求进入时,一个线程被分配给它,然后这个线程处理该请求。如果您的服务器随后阻止了对其他服务器的调用,则分配的线程需要等待响应返回。

这往往会导致Web服务器有数百个线程,这些线程花费大量时间只是等待。当我说等待时,我指的是等待很多。因为线程90%的时间可能仅用于等待阻塞调用。例如,Web服务器中的处理可能需要3ms,然后它执行阻塞数据库调用,线程需要等待200ms(不要引用我的数字)。

仅等待就花费了大量资源。

太老了:

  • 每个请求一个线程
  • 如果有300个请求,我们就有300个线程
  • 内存使用率高(每个线程都需要内存)
  • CPU等待时间很长

Reactive通过使用称为事件循环的东西来解决此问题,然后使用一个小型线程池来调度事件循环中的工作。

我练习可以看到,一个事件循环,然后可能是10个线程,所有线程都在调度工作,事件循环一直在工作,调度器只调度一长串工作,让事件循环完成。因此,所有线程始终100%忙碌。

在WebFlux应用程序中,事件循环的数量通常取决于硬件中的核心数量。

但这意味着我们需要100%无阻塞。假设我们在此方案中有一个阻塞调用,那么整个事件循环将停止,所有计划的作业也将停止,并且整个计算机将冻结,直到我们解除阻塞。

如此被动:

  • 事件循环完成所有工作
  • 调度工作的小线程池
  • 阻止非常糟糕,可能会冻结整个应用程序
  • 由于线程更少,内存占用量更小
  • 更高的CPU使用率
  • 可能更高的吞吐量

因此,我们基本上是在用内存换取CPU能力。

那么什么是阻塞调用?嗯,大多数呼叫都被阻止了,就像你呼叫另一项服务,你需要等待。但这就是反应式的闪光点,因为它还有一个特点。

因为每个请求没有一个特定的线程,所以任何线程都可以发出请求,但问题是,任何线程都可以处理响应,它不必是同一个线程。

我们是所谓的线程不可知论者。

我们的非阻塞服务可以对其他服务执行大量阻塞调用,并且仍然保持完全非阻塞。因为当我说非阻塞时,我的意思是我们在自己的应用程序内部是非阻塞的。

那么什么是糟糕的阻塞调用呢?当你在调用依赖于线程的东西时。这意味着您正在调用依赖于进行该调用的同一线程来处理响应的某个对象,那么我们需要阻止该线程并等待响应。

如果我们需要进行调用,则阻塞以等待响应,然后处理响应,因为我们需要相同的线程,因此不能使用反应性,因为这样可能会阻塞事件循环,这将停止整个应用程序。

例如,在被动世界中,使用ThreadLocal的所有内容都是不好的,这就是主要问题之一。JDBC(数据库驱动程序规范)本身就是块编写的。因为它依赖于本地线程来跟踪事务以便能够回滚。这意味着所有使用JDBC的数据库调用在非阻塞反应式应用程序中都是不可用的,这意味着您必须使用使用R2DBC规范的数据库驱动程序。

但REST调用不是阻塞的,因为它不是线程相关的,除非您使用线程相关的功能,比如Spring WebClient不使用的ThreadLocal。

那么你的引语说的是什么?Spring Reader有一种机制,这样您就可以将旧方法(每个请求一个线程)和新方法(线程无关)混合在一起。这意味着,如果您有一个硬阻塞调用(使用JDBC驱动程序调用一个旧数据库),您可以显式地告诉框架,对此数据库的所有调用都应该放在它自己的线程池中,因此,您在某种程度上是在告诉框架,对于该特定调用使用旧的方式(通过为该请求分配一个独占线程)。但请记住,这样做会失去被动反应的所有好处。

因此,如果您的服务只调用许多硬阻塞服务(如旧数据库),您将不得不不断地选择退出反应式框架,因此您基本上只需要使用反应式框架构建一个旧的传统Servlet Web服务,这是一种反模式。因此,我不建议这样做。

我在这里所写的都是计算机常识、线程如何工作、REST调用如何工作、数据库驱动程序如何工作。我无法解释计算机如何在单个堆栈溢出帖子中工作。

Reactor reference中说明了这一点以及更多内容,我建议您做更多的研究。

如果你有一条多弯不直的路,如果你必须不断减速,一直做很多弯道,那么买一辆F1赛车还有什么意义吗?

我把这个决定留给你。

这篇关于当我们有阻塞调用时,我们应该使用像Spring Webflow这样的反应式堆栈Web框架吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-12 18:03