如何使用适当的线程池调整Play Framework应用程序?

oym*_*oym 6 scala playframework-2.3

我正在使用Play Framework(Scala)2.3版.来自文档:

通过将同步IO包装在Future中,您无法神奇地将同步IO变为异步.如果您无法更改应用程序的体系结构以避免阻塞操作,那么在某些时候必须执行操作,并且该线程将阻塞.因此,除了将操作封装在Future中之外,还需要将其配置为在单独的执行上下文中运行,该上下文已配置有足够的线程来处理预期的并发性.

这让我对如何调整我的webapp有点困惑.具体来说,由于我的应用程序有大量的阻塞调用:混合使用JDBC调用,以及使用阻塞SDK调用第三方服务,配置执行上下文和确定要提供的线程数的策略是什么?我需要一个单独的执行上下文吗?为什么我不能简单地将默认池配置为具有足够数量的线程(如果我这样做,为什么还需要将调用包装在Future中?)?

我知道这最终将取决于我的应用程序的细节,但我正在寻找关于策略和方法的一些指导.游戏文档鼓励在任何地方使用非阻塞操作,但实际上典型的网络应用程序命中sql数据库有很多阻止调用,我从阅读文档中得到的印象,这种类型的应用程序将执行远远不是最佳的默认配置.

小智 6

[...]配置执行上下文和确定要提供的线程数的策略是什么

那么,这是一个棘手的部分,取决于您的个人要求.

  • 首先,您可能应该从文档中选择基本配置文件(纯异步,高度同步或许多特定的线程池)
  • 第二步是通过分析和基准测试应用程序来微调您的设置

我需要一个单独的执行上下文吗?

不必要.但是,如果要一次触发所有阻塞IO调用而不是顺序触发,则使用单独的执行上下文是有意义的(因此数据库调用B不必等到数据库调用A完成).

为什么我不能简单地将默认池配置为具有足够数量的线程(如果我这样做,为什么还需要将调用包装在Future中?)?

你可以,查看文档:

play {
  akka {
    akka.loggers = ["akka.event.slf4j.Slf4jLogger"]
    loglevel = WARNING
    actor {
      default-dispatcher = {
        fork-join-executor {
          parallelism-min = 300
          parallelism-max = 300
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

通过这种方法,您基本上将Play转变为每个请求一个线程的模型.这不是Play背后的想法,但如果您正在进行大量阻止IO调用,那么这是最简单的方法.在这种情况下,您不需要在Future中包装数据库调用.

简而言之,您基本上有三种方法:

  1. 仅使用其API调用是非阻塞和异步的(IO-)技术.这允许您使用适合Play性质的小线程池/默认执行上下文
  2. 通过大幅增加默认执行上下文,将Play转换为每个请求一个线程的框架.不需要期货,只需像往常一样调用您的阻止数据库
  3. 为阻塞IO调用创建特定的执行上下文,并对您正在执行的操作进行细粒度控制