Play Framework:如何处理内存密集型操作?

Play Framework: how to deal with memory-intensive actions?

我有一个 Play Framework 应用程序(Play 2.8、Scala 2.13 和 Java 8),它使用 Apache PDFBox 2 从上传的 PDF 文件创建 JPG 缩略图。缩略图是根据请求创建的,然后缓存在文件系统。但是,当一个用户尝试显示包含许多没有缓存缩略图的 PDF 的画廊时,会同时创建一堆缩略图,并且服务器会因 OutMemoryError 而崩溃(5 或 6 个并发任务似乎就足够了)。服务器自动重启并在几十秒后再次可用,但正在创建的缩略图已损坏,我不得不面对许多不可用问题。

PDFBox 配置为使用临时文件,但在渲染缩略图时出现内存不足。

服务器只有 2 GB 可用 RAM。每个上传的 PDF 文件大约 1 MB,生成的缩略图大约 100 KB(72 DPI;尺寸大约 500×1000 像素)。我可以在不增加堆大小的情况下解决这个问题吗?理想情况下,Play 应该能够自动对这些内存密集型请求进行排队,但我可以通过手动限制并发内存密集型任务的数量来生活,不知何故……

最简单的方法可能是使用专用 ExecutionContext 和底层固定大小的线程池来生成缩略图。

import java.nio.file.Path
import java.util.concurrent.Executors

import scala.concurrent.{ ExecutionContext, Future }

object RenderPDF {
  implicit val ec : ExecutionContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(3 /* adjust */))

  def thumbnail(pdf: Path) : Future[Path] = Future {
    ... // call PDFbox
  }
}

您可以在操作处理程序中使用它来加载缩略图的生成。

如果您正在处理上传的 PDF,预渲染缩略图可能会更好,因为这样可以避免用户打开图库时突然不得不渲染数十个 PDF 的问题。