当在后台使用Netty vs Tomcat时,春季webFlux有所不同

gst*_*low 2 java tomcat nonblocking netty spring-webflux

我是springwebflux的学习者,并且阅读了以下系列文章(第一第二第三篇

在第三条中,我面对以下案文:

请记住,相同的应用程序代码可以在Tomcat,Jetty或Netty上运行。当前,在Servlet 3.1异步处理的基础上提供了Tomcat和Jetty支持,因此,每个线程只能有一个请求。当相同的代码在Netty服务器平台上运行时,约束解除,服务器可以同情地向Web客户端分发请求。只要客户不阻拦,每个人都会很高兴。Netty服务器和客户端的性能指标可能显示相似的特征,但是Netty服务器不限于每个线程处理单个请求,因此它不使用大型线程池,并且我们可能希望看到资源利用率方面的一些差异。在本系列的另一篇文章中,我们将回到后面。

首先,我看不到该系列的新文章,尽管该文章写于2016年。对我来说,很明显,tomcat默认具有100个线程来处理请求,一个线程同时处理一个请求,但我没有理解短语,它限制为每个线程一个请求是什么意思?

我也想知道Netty如何在具体情况下工作(我想了解与Tomcat的区别)。每个线程可以处理2个请求吗?

pat*_*ckf 30

目前有 2 个基本概念来处理对 Web 服务器的并行访问,它们具有各种优点和缺点:

  1. 阻塞
  2. 非阻塞

阻止 Web 服务器

阻塞的第一个概念,多线程服务器在池中具有有限数量的线程。每个请求都将被分配给特定的线程,并且该线程将被分配,直到请求被完全服务。这与超级市场中结账队列的工作方式基本相同,一次一个顾客可能有平行线。在大多数情况下,Web 服务器中的请求在处理请求时的大部分时间将处于 cpu-idle 状态。这是因为它必须等待 I/O:读取套接字,写入数据库(基本上也是 IO)并读取结果并写入套接字。此外,使用/创建一堆线程很慢(上下文切换)并且需要大量内存。因此,这个概念通常不会非常有效地使用它所拥有的硬件资源,并且对可以并行服务的客户端数量有严格的限制。慢loris,一种攻击,通常单个客户端可以毫不费力地对大型多线程Web服务器进行DOS攻击。

概括

  • (+) 更简单的代码
  • (-) 并行客户端的硬限制
  • (-) 需要更多内存
  • (-) 通常网络服务器工作的硬件使用效率低下
  • (-) 易于DOS

大多数“传统”网络服务器都以这种方式工作,例如较旧的 tomcat、Apache Webserver 以及Servlet早于 3 或 3.1 的所有内容等。

非阻塞 Web 服务器

相比之下,非阻塞 Web 服务器可以只用一个线程为多个客户端提供服务。那是因为它使用了非阻塞内核 I/O 特性。这些只是内核调用,当可以写入或读取某些内容时,它们会立即返回并回调,从而使 cpu 可以自由地做其他工作。再次使用我们的超市比喻,这就像,当收银员需要他的主管解决问题时,他不会等待并阻塞整个车道,而是开始结账,直到主管到达并解决第一个问题顾客。

这通常在事件循环或更高的抽象中完成,如green-threadsFibers。本质上,这样的服务器不能真正并发地处理任何事情(当然你可以有多个非阻塞线程),但它们能够并行地为数千个客户端提供服务,因为内存消耗不会像多线程那样急剧扩展概念(阅读:最大并行客户端没有硬性限制)。也没有线程上下文切换。缺点是,非阻塞代码读取和写入通常更复杂(例如callback-hell),并且在请求执行大量 CPU 昂贵的工作的情况下不能很好地执行。

概括

  • (-) 更复杂的代码
  • (-) CPU 密集型任务的性能更差
  • (+) 作为网络服务器更有效地使用资源
  • (+) 更多没有硬性限制的并行客户端(最大内存除外)

大多数现代“快速”网络服务器和框架都促进了非阻塞概念:Netty、Vert.x、Webflux、nginx、servlet 3.1+、Node、Go Webservers。

作为旁注,查看此基准测试页面,您将看到大多数最快的网络服务器通常是非阻塞的:https : //www.techempower.com/benchmarks/


也可以看看

  • **请记住,相同的应用程序代码在 Tomcat、Jetty 或 Netty 上运行。目前,Tomcat 和 Jetty 支持是在 Servlet 3.1 异步处理之上提供的,因此它仅限于每个线程一个请求。** 我创建该主题是因为我不理解该短语 (2认同)
  • 据我所知,tomcat 8.5+支持servlet 3.1,因此它支持异步+非阻塞 (2认同)

Bri*_*zel 5

使用Servlet 2.5时,Servlet容器会将请求分配给线程,直到该请求已被完全处理。

使用Servlet 3.0异步处理时,服务器可以在应用程序处理请求时在单独的线程池中分派请求处理。但是,当涉及到I / O时,工作总是在服务器线程上进行,并且总是阻塞。这意味着“慢速客户端”可以垄断服务器线程,因为服务器在通过不良网络连接读取/写入该客户端时被阻塞。

使用Servlet 3.1,允许异步I / O,在这种情况下,不再使用“一个请求/线程”模型。任何时候都可以在服务器管理的不同线程上安排位请求处理。

Servlet 3.1+容器通过Servlet API提供了所有这些可能性。应用程序可以利用异步处理或非阻塞I / O。在非阻塞I / O的情况下,范式更改非常重要,使用起来确实具有挑战性。

使用Spring WebFlux-Tomcat,Jetty和Netty没有完全相同的运行时模型,但是它们都支持反应性背压和非阻塞I / O。

  • 我没有任何方便的示例,但此演示文稿 https://www.youtube.com/watch?v=uGXsnB2S_vc 和我们的反应式适配器 https://github.com/spring-projects/spring-framework/blob/master /spring-web/src/main/java/org/springframework/http/server/reactive/ServletHttpHandlerAdapter.java 应该可以让您了解所涉及的复杂性。 (2认同)