代码之家  ›  专栏  ›  技术社区  ›  Jason

在jvm中缓存tar以加快文件I/O速度?

  •  1
  • Jason  · 技术社区  · 17 年前

    我正在开发一个JavaWeb应用程序,它使用数千个小文件来构建工件以响应请求。我认为,如果我们能够将这些文件映射到内存中,而不是一直在磁盘上查找它们,那么我们的系统可以看到性能的提高。

    我听说过linux中的mmap,我对这个概念的基本理解是,当从磁盘读取文件时,文件的内容会被缓存在内存中的某个地方,以便后续更快地访问。我的想法与这个想法类似,只是我想在我的web应用程序初始化时将整个mmap-able文件集读入内存,以获得最短的请求时间响应。

    我已经找到了ApacheVFS项目,它可以从一个tar文件中读取信息,但是从他们的文档中我不确定是否可以指定诸如“另外,将整个tar读入内存并保存在那里…”之类的内容。

    我们在这里讨论的是一个多线程环境,它为工件提供服务,这些工件通常从一整套300000多个源文件中拼凑出大约100个不同的文件来做出一个响应。因此,无论虚拟文件系统解决方案是什么,它都需要线程安全且性能良好。我们这里只讨论读取文件,没有写入。

    谢谢你的意见!

    • 杰森
    8 回复  |  直到 17 年前
        1
  •  1
  •   Aaron Digulla    17 年前

    您可以尝试将所有文件放在一个JAR中,并将其放在类路径上。Java使用一些内置的技巧使JAR文件的读取速度非常快。这也将保留RAM中所有文件的目录,因此您不必访问磁盘来查找文件(在开始加载文件之前发生)。

    JVM不会一次将整个JAR加载到RAM中,而且您可能不希望这样,因为您的机器将开始交换。但它将能够很快找到片段,因为它将保持文件始终处于打开状态,因此,您在打开/关闭文件资源时不会丢失任何时间。

    最后,您可以尝试压缩JAR。虽然这听起来可能是个坏主意,但你应该试一试。如果小文件压缩得很好,那么使用当前CPU解包的时间比从磁盘读取数据的时间要少得多。如果不必将中间数据保存在任何位置,则可以将未压缩的数据流式传输到客户端,而无需写入文件(这会破坏整个想法)。这样做的缺点是,它会消耗CPU周期,如果您的CPU很忙(只需使用一些加载工具进行检查;如果超过20%,那么你就会放松),那么整个过程就会变慢。

    您可以加载非常小的文件。

        2
  •  1
  •   Simon Groenewolt    17 年前

    如果需要快速访问300000个文件,可以使用数据库,而不是关系数据库,而是简单的键值数据库,如 http://www.space4j.org/ . 这对您的启动时间没有帮助,但在运行时可能会大大加快。

        3
  •  0
  •   unwind    17 年前

    只是想澄清一下,, mmap() 在类Unix系统中,不允许您访问文件;它只是使文件的内容作为内存在内存中可用。你不能使用 open() 以进一步打开任何包含的文件。世上没有所谓的 mmap() “可编辑的文件集”。

    难道你不能添加一个初始加载所有“模板”的过程,然后根据一些简单的东西快速找到它们,比如每个模板名称上的哈希?这应该可以让你充分利用你的内存,并着手对任何模板进行O(1)访问。

        4
  •  0
  •   mat    17 年前

    mmap 在这里没有帮助,因为旧的内存/磁盘已经不存在了。如果你映射了一个文件,内核会给你一个指向某个文件的指针 虚拟内存 不 将文件加载到

    你说那些300k文件需要1.5GB到2.5GB的磁盘空间。如果有任何机会,你可以扔2(或更好,4)更多的千兆字节内存到您的服务器,你会 非常 把磁盘读取的事情留给操作系统更好,如果它有足够的RAM在一些磁盘缓存中加载文件,它会,并且从中,任何读取()都不会命中磁盘(如果您没有使用noatime挂载卷,则可以在inode中存储atime。)

    若您尝试读取()文件,将它们放入内存,并从那个里为它们提供服务,那个么您现在就有办法确定它们将始终在内存中 而不是在交换中,因为操作系统与您几次未使用的那部分内存有其他关系。

    如果您有足够的RAM让操作系统进行磁盘缓存,并且您真的希望加载文件,那么您可以始终执行一个小脚本/程序来遍历您的层次结构并读取所有文件(它会让操作系统将它们从磁盘加载到内存磁盘缓存中,但是如果操作系统需要内存,你无法知道它们会留在那里。因此,正如我之前所说的,您应该让操作系统来处理这个问题,并为它提供足够的RAM。

    varnish 的 Architect Notes phk用他自己的话告诉你,为什么你想要实现的东西更好地留给操作系统,操作系统将永远更好地了解JVM内存中有什么和没有什么。

        5
  •  0
  •   Guillaume    17 年前

    如果您需要快速访问所有这些文件,您可以将它们加载到内存中,但我不会将它们作为文件加载。我会把这些数据放在某种对象结构中(最简单的形式,就是字符串)。

    我要做的是创建一个服务,该服务将文件作为对象结构从您使用的任何参数返回。然后围绕该服务实现一些缓存机制。然后,就要调整缓存了。如果确实需要加载内存中的所有内容,请将缓存配置为使用更多内存。如果某些文件比其他文件使用得更多,那么只缓存这些文件就足够了。。。

    如果我们对您的目标有更多了解,我们可能会给您更好的答复。

        6
  •  0
  •   Aaron Digulla    17 年前

    将文件放在10个不同的服务器上,而不是直接为请求提供服务,向客户端发送带有URL的HTTP重定向(或等效重定向),在那里他们可以找到想要的文件。这样可以分散负载。服务器只响应快速请求,而(大量)下载分布在多台机器上。

        7
  •  0
  •   tcurdt    17 年前

    如果你在Linux上,我会给你一个好的 RAM disk

    正如你所说的VFS:这也有一个 RAM disk provider

        8
  •  0
  •   Saiyine    17 年前

    您需要的是将所有信息加载到 .

    使用每个文件的名称作为键,内容作为值加载每个文件,a您将能够比您想象中的设置更快、更容易地工作几个数量级。