为了账号安全,请及时绑定邮箱和手机立即绑定

在后台使用 Netty 与 Tomcat 时 Spring webFlux 的差异

在后台使用 Netty 与 Tomcat 时 Spring webFlux 的差异

富国沪深 2023-02-23 14:25:11
我正在学习 spring webflux 并且我已经阅读了以下系列文章(第一,第二,第三)在第三篇文章中,我遇到了以下文本:请记住,相同的应用程序代码在 Tomcat、Jetty 或 Netty 上运行。目前,Tomcat 和 Jetty 支持是在 Servlet 3.1 异步处理之上提供的,因此每个线程仅限于一个请求。当相同的代码在 Netty 服务器平台上运行时,该限制被解除,并且服务器可以同情地将请求分派给 Web 客户端。只要客户端不阻塞,大家都很高兴。Netty 服务器和客户端的性能指标可能显示出相似的特征,但 Netty 服务器并不局限于每个线程处理单个请求,因此它不使用大型线程池,我们可能会看到资源利用方面的一些差异。我们稍后将在本系列的另一篇文章中回过头来讨论这一点。首先,我没有看到该系列中的更新文章,尽管它是在 2016 年写的。我很清楚 tomcat 默认有 100 个线程来处理请求,一个线程同时处理一个请求,但我没有理解这句话it is limited to one request per thread是什么意思?我也想知道 Netty 如何处理那个具体案例(我想了解与 Tomcat 的区别)。每个线程可以处理 2 个请求吗?
查看完整描述

2 回答

?
青春有我

TA贡献1784条经验 获得超8个赞

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

  1. 阻塞

  2. 非阻塞

阻止网络服务器

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

概括

  • (+) 更简单的代码

  • (-) 并行客户端的硬限制

  • (-) 需要更多内存

  • (-) 通常的网络服务器工作硬件使用效率低下

  • (-) 易于 DOS

大多数“传统”网络服务器都是这样工作的,例如旧的 tomcat、Apache 网络服务器以及所有Servlet早于 3 或 3.1 的东西等等。

非阻塞网络服务器

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

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

概括

  • (-) 更复杂的代码

  • (-) cpu 密集型任务的性能更差

  • (+) 作为 Web 服务器更有效地使用资源

  • (+) 更多没有硬限制的并行客户端(最大内存除外)

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

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


查看完整回答
反对 回复 2023-02-23
?
慕村9548890

TA贡献1884条经验 获得超4个赞

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


查看完整回答
反对 回复 2023-02-23
  • 2 回答
  • 0 关注
  • 321 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信