我有一个带有32GB ram的linux盒子和raid 0配置中的一组4个SSD,最大吞吐量大约为1GB(随机4k读取),我试图确定访问它们上的文件的最佳方式随机和连续使用java。到目前为止,我看到的两种主要方式是通过随机访问文件和映射的直接字节缓冲区。
但是它在哪里变得棘手。我有自己的对象内存缓存,所以对存储在文件中的对象的任何调用都应该通过磁盘而不是分页内存(我已经禁用了我的linux盒子上的交换空间来防止这种情况)。虽然映射的直接内存缓冲区被认为是最快的,但它们依赖于交换这是不好的,因为A)我使用所有可用内存用于对象缓存,而使用mappedbytebuffers会导致大量的序列化开销,这就是对象缓存所针对的阻止。(我的程序已经CPU限制)B)使用mappedbytebuffers操作系统处理数据写入磁盘的细节,我需要自己控制,即。当我写(byte [])时,它会立即直接进入磁盘,这是为了防止因电源故障而导致数据损坏,因为我没有使用ACID事务。
另一方面,我需要大规模并发,即。我需要同时读取和写入同一文件中的多个位置(同时使用偏移/范围锁以防止数据损坏)我不知道如果没有mappedbytebuffers我怎么能这样做,我总是可以只读取/写但我不确定这将如何对我的吞吐量产生负面影响。
最后,当我为读取或写入创建新的byte []对象时,我不会遇到这种情况,这是因为我每秒执行几乎100000个读/写操作,分配和垃圾收集所有这些对象会杀死我的程序这是时间敏感的并且已经CPU限制,重复使用byte []对象很好。
请不要建议任何数据库软件,因为我已经尝试了大部分数据库软件,它们会增加复杂性和CPU开销。
有人有这种困境吗?
答案 0 :(得分:3)
虽然映射的直接内存缓冲区被认为是最快的,但依赖于交换
不,如果你有足够的内存,那就不行了。映射将内存中的页面与磁盘上的页面相关联。除非操作系统决定需要恢复RAM,否则页面不会被换出。如果你的内存不足,那么所有禁用交换都会导致致命错误,而不是性能下降。
我正在使用对象缓存的所有可用内存
除非你的对象非常长寿,否则这是一个坏主意,因为垃圾收集器在运行时必须做很多工作。您经常会发现较小的缓存会导致更高的总吞吐量。
使用mappedbytebuffers操作系统处理数据写入磁盘的细节,我需要自己控制,即。当我写(byte [])时,它会立即直接进入磁盘
实际上,除非您使用sync
选项挂载文件系统,否则它不会。然后,您仍然存在因故障驱动器(特别是在RAID 0中)丢失数据的风险。
如果没有mappedbytebuffers,我不知道如何做到这一点
RandomAccessFile
会执行此操作。但是,您将在每次写入时至少为内核上下文切换付费(如果您为同步写入安装了文件系统,则每次写入都将涉及磁盘往返)。
我没有使用ACID交易
然后我猜数据并不是那么有价值。所以不要担心有人会用电源线绊倒。
答案 1 :(得分:1)
您对映射字节缓冲区的反对意见不成立。您的映射文件将与您的对象缓存不同,虽然它们占用地址空间但它们不占用RAM。您也可以随时同步映射的字节缓冲区(以某些性能为代价)。此外,随机访问文件最终使用相同的设备,因此您无法在那里保存任何性能。
如果映射的字节缓冲区没有为您提供所需的性能,则可能必须绕过文件系统并直接写入原始分区(这就是DBMS所做的)。为此,您可能需要为数据处理编写C ++代码并通过JNI访问它。