【问题标题】:Play Framework: File uploads - blocking or non-blocking?播放框架:文件上传 - 阻塞还是非阻塞?
【发布时间】:2017-01-05 16:57:54
【问题描述】:

鉴于 Play 文档中的示例代码:

def upload = Action(parse.temporaryFile) { request =>
  request.body.moveTo(new File("/tmp/picture/uploaded"))
  Ok("File uploaded")
}
  1. 如何同时处理 100 个慢速上传请求(线程数)?
  2. 上传文件是在内存中缓冲还是直接流式传输到磁盘?

【问题讨论】:

    标签: scala playframework


    【解决方案1】:

    如何同时处理 100 个慢速上传请求(线程数)?

    这取决于。实际使用的线程数并不真正相关。默认情况下,Play 使用的线程数等于可用的 CPU 内核数。但这并不意味着如果你有 4 个核心,你就只能同时处理 4 个并发进程。 Play 中的 HTTP 请求在 Akka 提供的特殊内部 ExecutionContext 中异步处理。在ExecutionContext 中运行的进程可以共享线程,只要它们是非阻塞的——这已被 Akka 抽象出来。所有这些都可以通过不同的方式进行配置。见Understanding Play Thread Pools

    消耗客户端数据的Iteratee 必须进行一些阻塞才能将文件块写入磁盘,但以足够小(且快)的块完成,这不应导致其他文件上传被阻塞。

    我更担心的是服务器可以处理的磁盘 I/O 量。 100 次慢速上传可能没问题,但你不能说没有基准测试。在某些时候,当客户端输入超过服务器可以写入磁盘的速率时,您会遇到麻烦。这在分布式环境中也不起作用。我几乎总是选择完全绕过 Play 服务器,直接上传到 Amazon S3。

    将上传的文件缓存在内存中还是直接流式传输到磁盘?

    所有临时文件都流式传输到磁盘。在后台,从客户端发送到服务器的所有数据都是使用 iteratee 库异步读取的。对于分段上传,它没有什么不同。客户端数据由Iteratee 使用,它将文件块流式传输到磁盘上的临时文件。所以在使用parse.temporaryFileBodyParser时,request.body只是磁盘上临时文件的句柄,而不是存储在内存中的文件。


    值得注意的是,虽然 Play 可以以非阻塞方式处理这些请求,但一旦完成移动文件阻塞。也就是说,request.body.moveTo(...) 将阻塞控制器功能,直到移动完成。这意味着,如果 100 个上传中的几个几乎同时完成,Play 用于处理请求的内部 ExecutionContext 很快就会变得超载。 moveTo 的底层 API 在 Play 2.3 中也已弃用,因为它使用 FileInputStreamFileOutputStreamTemporaryFile 复制到永久位置。文档建议您改用 Java 7 File API,因为它效率更高。

    这可能有点粗略,但应该这样做:

    import java.io.File
    import java.nio.file.Files
    
    def upload = Action(parse.temporaryFile) { request =>
        Files.copy(request.body.file.toPath, new File("/tmp/picture/uploaded").toPath)
        Ok("File uploaded")
    }
    

    【讨论】:

    • @user882209 play-s3 库非常好。它具有为客户端创建签名上传表单的助手,并提供了一个异步服务器端 API,用于在上传后处理 S3 上的文件。
    • 这里的关键并不是akka,而是它使用netty和NIO的事实。特别是如果 moveto 使用零副本,我确信它会这样做或希望如此。
    • @AdamGent 好像是doesn't。您可能需要自己使用 nio 而不是 moveTo。但这只是在上传完成之后
    • @m-z 啊,这很不幸(我没有费心去看,因为我不使用 Play)。然而,我的观点仍然是,它不是 Akka 而是 Netty 将它抽象为你的观点:“这只是在上传之后”。你需要 Netty (NIO) 来拥有非阻塞而不是 Akka……你几乎可以在没有 Akka 作为调度程序的情况下执行完全相同的代码(即 Vert.x)。
    猜你喜欢
    • 2012-11-13
    • 2021-12-26
    • 2014-10-19
    • 1970-01-01
    • 2013-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    相关资源
    最近更新 更多