[英]Understanding the Difference Between Non-Blocking Web Service Calls vs Non-Blocking JDBC
[英]Non-blocking vs blocking Java server with JDBC calls
我们的 gRPC 需要处理 1000 QPS,每个请求都需要一系列顺序操作,包括使用 JDBC 从数据库读取数据。处理单个请求最多需要 50 毫秒。
我们的应用程序可以用两种方式编写:
我的理解是非阻塞方法具有以下优点和缺点:
问题 1:尽管非阻塞应用程序似乎是很酷的新事物,但我的理解是,对于不受 memory 限制且创建更多线程不是问题的应用程序,编写非阻塞应用程序尚不清楚实际上比编写阻塞应用程序的 CPU 效率更高。 有任何理由不相信吗?
问题 2:我的理解也是,如果我们使用 JDBC,连接实际上是阻塞的,即使我们将应用程序的 rest 设为非阻塞,由于 JDBC 客户端,我们失去了所有好处,在这种情况下,一个选项1 最有可能更好?
对于问题 1,你是对的——非阻塞并不是天生就更好(随着虚拟线程的到来,与良好的旧线程请求相比,它将会变得更糟)。 充其量,您可以查看正在使用的工具,并使用小规模示例进行一些性能测试。 但坦率地说,这取决于工具,而不是策略(至少,在虚拟线程出现之前)。
对于问题 2,我强烈建议您选择最适合您的工具/框架的解决方案。 待在您的生态系统内将使您能够在需要优化时采取更灵活的行动。
但在所有条件相同的情况下,我强烈建议您坚持使用 thread-per-request,因为您正在使用 Java。忽略虚拟线程,thread-per-request 允许您使用和管理简单的、阻塞的、同步的代码。 您不必处理回调或通过混乱和零碎的日志来跟踪逻辑。 简单地为每个请求创建一个线程,让它在它阻塞的地方阻塞,然后让你的调度程序在任何给定时间处理哪个线程应该拥有 CPU 核心。
优点:节省操作系统的一些开销,因为它不需要为等待 IO 的线程提供 CPU 时间
不仅仅是等待线程的CPU时间,还有在线程之间切换竞争CPU的开销。 当你有更多的线程时,更多的线程将在 state 中运行,并且 CPU 时间必须在它们之间分配。 这就需要大量的memory管理进行切换。
缺点:对于大型应用程序(其中每个任务都订阅对前一个任务的回调),它需要将单个请求拆分到多个线程,从而产生不同类型的开销。 如果同一请求在多个物理内核上执行,则可能会增加开销,因为数据可能在 L1/L2 内核缓存中不可用。
这也发生在“经典”方法中,因为阻塞调用将导致 CPU 切换到不同的线程,并且如前所述,CPU 甚至必须在可运行线程之间切换以随着线程数量的增加共享 CPU 时间。
问题 1 :[…] 对于不受 memory 限制且创建更多线程不是问题的应用程序
在Java的当前state中,创建更多线程总是会在某些时候成为问题。 使用 thread-per-request model,这取决于您有多少个并行请求。 1000,可能还行,10000……也许不行。
目前尚不清楚编写非阻塞应用程序实际上是否比编写阻塞应用程序的 CPU 效率更高。 有任何理由不相信吗?
这不仅仅是效率问题,还有可扩展性问题。 对于性能本身,这需要进行适当的负载测试。 您可能还想检查非阻塞 I/O 真的比多线程阻塞 I/O 快吗? 如何?
问题 2 :我的理解也是,如果我们使用 JDBC,连接实际上是阻塞的,即使我们将应用程序的 rest 设为非阻塞,由于 JDBC 客户端,我们失去了所有好处,在这种情况下,一个选项1 最有可能更好?
JDBC 确实是一个同步的 API。Oracle 作为异步等效项在 ADBA 上工作,但考虑到 Project Loom 将使它变得无关紧要,他们停止了它。 R2DBC提供了一个支持 MySQL 的替代方案。Spring 甚至支持反应式事务。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.