【问题标题】:Non-blocking vs blocking Java server with JDBC calls使用 JDBC 调用的非阻塞与阻塞 Java 服务器
【发布时间】:2022-12-09 17:10:01
【问题描述】:

我们的 gRPC 需要处理 1000 QPS,每个请求都需要一个列表顺序操作发生,包括一个是使用 JDBC 从数据库中读取数据。处理单个请求最多需要 50 毫秒。

我们的应用程序可以用两种方式编写:

  • 选项 1 - 每个请求一个经典的阻塞线程:我们可以创建一个大线程池(~200)并简单地为每个请求分配一个线程,并在等待数据库时让该线程阻塞。
  • 选项 2 - 以真正非阻塞的方式处理每个请求:.这将需要我们使用一个非阻塞的 MySQL 客户端,我不知道它是否存在,但现在让我们假设它存在。

我的理解是非阻塞方法具有以下优点和缺点:

  • 优点:允许减少所需的线程数,从而减少内存占用
  • 优点:节省操作系统的一些开销,因为它不需要为等待 IO 的线程提供 CPU 时间
  • 缺点:对于大型应用程序(其中每个任务都订阅对前一个任务的回调),它需要将单个请求拆分到多个线程,从而产生不同类型的开销。如果同一请求在多个物理内核上执行,则可能会增加开销,因为数据可能在 L1/L2 内核缓存中不可用。

问题一:尽管非阻塞应用程序似乎是很酷的新事物,但我的理解是,对于不受内存限制且创建更多线程不是问题的应用程序,目前尚不清楚编写非阻塞应用程序实际上是否更有效CPU 效率高于编写阻塞应用程序。有任何理由不相信吗?

问题2:我的理解也是,如果我们使用 JDBC,连接实际上是阻塞的,即使我们让应用程序的其余部分成为非阻塞的,由于 JDBC 客户端,我们失去了所有的好处,在这种情况下,选项 1 是最可能更好?

【问题讨论】:

    标签: java asynchronous jdbc nonblocking


    【解决方案1】:

    对于问题 1,你是对的——非阻塞并不是天生就更好(随着 Virtual Threads 的到来,与良好的旧线程请求相比,它将会变得更糟)。充其量,您可以查看正在使用的工具,并使用小规模示例进行一些性能测试。但坦率地说,这取决于工具,而不是策略(至少,在虚拟线程出现之前)。

    对于问题 2,我强烈建议您选择最适合您的工具/框架的解决方案。待在您的生态系统内将使您能够在需要优化时采取更灵活的行动。

    但在所有条件相同的情况下,我强烈建议您坚持使用 thread-per-request,因为您使用的是 Java。忽略虚拟线程,thread-per-request 允许您使用和管理简单的、阻塞的、同步的代码。您不必处理回调或通过混乱和零碎的日志来跟踪逻辑。简单地为每个请求创建一个线程,让它在它阻塞的地方阻塞,然后让你的调度程序在任何给定时间处理哪个线程应该拥有 CPU 核心。

    【讨论】: