Play Framework 2.X 和阻塞数据库调用

2023-12-21

我有点困惑。

来自文档 http://www.playframework.com/documentation/2.1.0/ThreadPools:

播放默认线程池 - 这是默认线程池,其中 Play Framework 中的所有应用程序代码都会被执行,不包括一些 迭代器代码。它是一个 Akka 调度程序,可以通过以下方式配置 配置 Akka,如下所述。默认情况下,每个线程有一个线程 处理器。

将阻塞数据库调用包装在一个Future,调用Future本身被包裹着async控制器(返回它),以便让默认线程池处理其他用户的请求?

它只会将阻塞代码移到另一个线程内(从专用的 ExecutionContext 中),但保留Action畅通。

我碰到这个帖子 https://stackoverflow.com/questions/22421322/how-to-rewrite-synchronous-controller-to-be-asynchronous-in-play但我对给出的答案不满意。
事实上,如果我让数据库调用在默认线程池中阻塞,是否会潜在地阻止同时处理不依赖于数据库的其他用户请求?

注意:我的数据库(Neo4j)没有异步驱动程序。


有几种方法可以处理阻塞调用。我不能说哪个是最好的,因为它肯定取决于特定的用例,并且需要大量的基准测试。

默认情况下,Play 使用线程池处理请求,每个 cpu 核心有一个线程。因此,例如,如果您在四核 CPU 上运行 Play 应用程序,则它只能处理 4 个并发请求(如果这些请求使用对数据库的阻塞调用)。所以是的,所有其他传入请求都必须等待,直到其中一个线程被释放。

最简单的解决方案是增加 Play 用于处理默认线程池中请求的线程数(在 application.conf 中):

play {
   akka {
     akka.loggers = ["akka.event.slf4j.Slf4jLogger"]
     loglevel = WARNING
     actor {
        default-dispatcher = {
           fork-join-executor {
             parallelism-min = 300
             parallelism-max = 300
           }
        }
     }
   }
}

下一个选项是您在问题中提到的选项 - 将阻塞数据库调用卸载到另一个选项ExecutionContext。您可以在 application.conf 中配置单独的线程池,如下所示:

database-io {
    fork-join-executor {
       parallelism-factor = 10.0
    }
}

这将在池中为每个 cpu 核心创建 10 个线程,称为database-io,并且可以在 Play 中访问,如下所示:

val dbExecutor: ExecutionContext = Akka.system.dispatchers.lookup("database-io")

val something = Future(someBlockingCallToDb())(dbExecutor)

这将允许默认线程池在等待时处理更多请求Future去完成。第三种选择是使用Actor处理数据库调用,但这更复杂并且超出了这个问题的范围。

底线是,yes,使用更大的线程池或不同的ExecutionContext用于阻止呼叫,如您never如果可以的话,想在默认线程池中阻塞。

这一切都在播放线程池文档 http://www.playframework.com/documentation/2.3.x/ThreadPools。 (最新版本)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Play Framework 2.X 和阻塞数据库调用 的相关文章

随机推荐