Spring webFlux 在引擎盖下使用 Netty vs Tomcat 时的差异

我正在学习春季webflux,我已经阅读了以下系列文章(第一第二第三)

在第三条中,我面对的是以下文字:

请记住,相同的应用程序代码在Tomcat,Jetty或Netty上运行。目前,Tomcat 和 Jetty 支持是在 Servlet 3.1 异步处理之上提供的,因此每个线程只能有一个请求。当相同的代码在Netty服务器平台上运行时,约束被解除,服务器可以同情地将请求分派给Web客户端。只要客户不屏蔽,大家就高兴了。netty 服务器和客户端的性能指标可能显示相似的特征,但 Netty 服务器不限于处理每个线程的单个请求,因此它不使用大型线程池,我们可能会期望在资源利用率上看到一些差异。我们将在本系列的另一篇文章中稍后再讨论这个问题。

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

我也想知道Netty如何为这个具体案例工作(我想了解与Tomcat的区别)。它能为每个线程处理 2 个请求吗?


答案 1

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

  1. 阻塞
  2. 非阻塞

阻止网络服务器

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

总结

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

大多数“传统”Web服务器都是这样工作的,例如较旧的tomcat,Apache Web服务器以及早于3或3.1的所有内容等。Servlet

非阻塞 Web 服务器

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

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

总结

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

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

作为旁注,看看这个基准测试页面,你会发现大多数最快的Web服务器通常是非阻塞的:https://www.techempower.com/benchmarks/


另请参见


答案 2

使用 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。


推荐