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