我正在开发一个java Web应用程序,它使用数千个小文件来构建工件以响应请求。我认为如果我们可以将这些文件映射到内存而不是在整个磁盘上运行以便一直找到它们,我们的系统可以看到性能改进。
我听说过linux中的mmap,我对这个概念的基本理解是,当从磁盘读取文件时,文件的内容会缓存在内存中的某个地方,以便更快地进行后续访问。我想到的是类似于这个想法,除了我想要将整个mmap-able文件集读入内存,因为我的web应用程序正在初始化以获得最少的请求时响应。
我的思想训练的一个方面是,如果它们全部被摧毁并以某种方式作为虚拟文件系统安装在JVM中,我们可能会更快地将文件放入jvm内存中。就目前而言,我们当前的实现可能需要几分钟才能遍历源文件集并找出磁盘上的所有内容。这是因为我们实际上正在为超过300,000个文件执行文件统计。
我找到了可以从tar文件中读取信息的apache VFS项目,但我不确定他们的文档中是否可以指定诸如“还可以将整个tar读入内存并将其保存在那里”。 ”。
我们在谈论一个多线程环境,这里提供的工件通常将一组300,000多个源文件中的100个不同文件拼凑在一起,以做出一个响应。因此无论虚拟文件系统解决方案是什么,它都需要线程安全且高性能。我们只谈论在这里阅读文件,没有写。
另外,我们运行64位操作系统,内存为32 gig,我们的300,000个文件占用大约1.5到2.5 GB的空间。我们肯定可以将一个2.5千兆字节的文件读入内存的速度比300千克小的几千字节大小的文件快得多。
感谢您的投入!
答案 0 :(得分:1)
您可以尝试将所有文件放在JAR中并将其放在类路径中。 Java使用一些内置技巧来非常快速地从JAR文件中读取。这也将保留RAM中所有文件的目录,因此您不必访问磁盘来查找文件(在您开始加载之前就会发生这种情况)。
JVM不会立即将整个JAR加载到RAM中,您可能不希望这样,因为您的计算机将开始交换。但它能够非常快速地找到它们,因为它会使文件保持打开状态,因此,您不会在任何时候打开/关闭文件资源。
此外,由于您一直在使用此单个文件,因此操作系统可能会在文件缓存中保留更长时间。
最后,您可以尝试压缩JAR。虽然这听起来像个坏主意,但你应该试一试。如果小文件压缩得很好,那么用当前CPU解压缩的时间远远低于从磁盘读取数据的时间。如果您不必将中间数据保存在任何位置,则可以将未压缩的数据流式传输到客户端,而无需写入文件(这会破坏整个想法)。这样做的缺点是它会占用CPU周期,如果你的CPU忙(只需检查一些加载工具;如果它超过20%,那么你就松开了),那么你将使整个过程变慢。
也就是说,当您使用HTTP协议时,您可以告诉客户端您正在发送压缩数据!这样,您不必解压缩数据和就可以加载非常小的文件。
JAR解决方案的主要缺点:只要服务器正在运行,就无法替换JAR。因此,替换文件意味着您必须重新启动服务器。
答案 1 :(得分:1)
如果您需要快速访问300,000个文件,则可以使用数据库,而不是关系数据库,而是简单的键值数据库,如http://www.space4j.org/。这对您的启动时间没有帮助,但在运行时可能会加速。
答案 2 :(得分:0)
只是澄清一下,在类Unix系统中mmap()
不允许你这样访问文件;它只是使文件内容在内存中可用,作为内存。您无法使用open()
进一步打开任何包含的文件。没有“mmap()
一组文件”。
你不能只添加一个最初加载所有“模板”的传递,然后根据简单的东西快速找到它们,比如每个名称的哈希值?这应该可以让你利用你的记忆,并获得任何模板的O(1)访问权限。
答案 3 :(得分:0)
我认为你还在考虑旧的内存/磁盘模式。
mmap
在这里没有帮助,因为旧的内存/磁盘事情早已不复存在。如果你mmap一个文件,内核会给你一个指向某个虚拟内存的指针供你自行决定使用,它会不将文件加载到真实内存,当你要求提供文件的一部分时,它会这样做,它只会加载你要求的页面。 (也就是说,一个内存页面,通常大约4KB。)
你说那些300k文件,占用大约1.5GB到2.5GB的磁盘空间。如果有机会你可以将2 GB(或者更好,4)更多GB的RAM投入到您的服务器中,那么如果它有足够的RAM,那么将该磁盘读取的内容留给操作系统会更好非常在某些磁盘缓存中加载文件,它们和它们上面的任何read()都不会打到磁盘上。 (如果您没有使用noatime安装音量,它将在inode中存储atime。)
如果您尝试读取()文件,将它们放入内存并从那里提供服务,您现在可以确定它们将始终位于 RAM 中,而不是交换,因为操作系统还有其他一些与你几分未使用的内存有关的事情。
如果你有足够的RAM让操作系统进行磁盘缓存,并且你真的希望加载文件,你总是可以做一个小的脚本/程序,它将通过你的层次结构并读取所有文件。 (没有做任何其他事情。)它会让操作系统将它们从磁盘加载到内存磁盘缓存,但如果操作系统需要内存,你无法知道它们会留在那里。因此,我之前说过,你应该让操作系统处理它,并给它足够的RAM来做到这一点。
你应该阅读varnish的Architect Notes,其中phk用他自己的话告诉你,为什么你想要实现的东西更好地留给操作系统,这将永远,更了解JVM什么是RAM,什么不是。
答案 4 :(得分:0)
如果您需要快速访问所有这些文件,可以将它们加载到内存中,但我不会将它们作为文件加载。我会把这些数据放在某种对象结构中(最简单的形式,只是一个字符串)。
我要做的是创建一个服务,将文件作为对象结构从您使用的任何参数返回。然后围绕此服务实现一些缓存机制。然后就是调整缓存的问题。如果您确实需要在内存中加载所有内容,请配置缓存以使用更多内存。如果某些文件比其他文件使用得多,那么只缓存那些文件就足够了......
如果我们更了解你想要达到的目标,我们可能会给你一个更好的回应。
答案 5 :(得分:0)
将文件放在10个不同的服务器上,而不是直接提供请求,将客户端HTTP重定向(或等效的)发送到可以找到所需文件的URL。这允许分散负载。服务器只响应快速请求,(大)下载分布在多台机器上。
答案 6 :(得分:0)
如果您使用的是Linux,我会尝试使用旧的RAM disk。您可以坚持当前的做事方式,并大幅降低IO成本。您没有绑定到JVM内存,仍然可以轻松替换内容。
正如你所说的VFS:它还有一个RAM disk provider但我仍然会先尝试本机RAM磁盘方法。
答案 7 :(得分:0)
您需要的是在 HashTable 中加载所有信息。
使用它的名称作为键加载每个文件,并将内容作为值加载,您将能够比您想到的设置更快,更容易地工作数量级。