0

我有一个带有 32GB ram 和一组 4 个 SSD 的 linux 机器,在 raid 0 配置中,最大吞吐量约为 1GB(随机 4k 读取),我正在尝试确定随机并同时访问文件的最佳方式使用java。到目前为止,我看到的两种主要方式是通过随机访问文件和映射的直接字节缓冲区。

这是它变得棘手的地方。我有自己的对象内存缓存,因此对存储在文件中的对象的任何调用都应该通过磁盘而不是分页内存(我已禁用我的 linux 机器上的交换空间以防止这种情况发生)。虽然映射的直接内存缓冲区被认为是最快的,但它们依赖于交换,这并不好,因为 A)我将所有空闲内存用于对象缓存,而使用映射字节缓冲区会产生大量的序列化开销,这就是对象缓存的存在防止。(我的程序已经受 CPU 限制) B)使用映射字节缓冲区,操作系统处理数据何时写入磁盘的详细信息,我需要自己控制它,即。当我 write(byte[]) 时,它会立即直接输出到磁盘,这是为了防止电源故障时数据损坏,因为我没有使用 ACID 事务。

另一方面,我需要大量并发,即。我需要同时读取和写入同一个文件中的多个位置(同时使用偏移/范围锁来防止数据损坏)我不确定如果没有映射字节缓冲区我怎么能做到这一点,我总是可以查询读取/写,但我不确定这会对我的吞吐量产生什么负面影响。

最后,当我为读取或写入创建新的 byte[] 对象时,我不会遇到这种情况,这是因为我每秒执行几乎 100000 次读取/写入操作,分配和垃圾收集所有这些对象会杀死我的程序,这是时间敏感且已经受到 CPU 限制,重用 byte[] 对象就可以了。

请不要推荐任何数据库软件,因为我已经尝试过其中的大多数软件,它们增加了很多复杂性和 CPU 开销。

有人遇到过这种困境吗?

4

2 回答 2

3

虽然映射的直接内存缓冲区据说是最快的,但它们依赖于交换

不,如果您有足够的 RAM,则不会。该映射将内存中的页面与磁盘上的页面相关联。除非操作系统决定需要恢复 RAM,否则页面不会被换出。而且,如果您的 RAM 不足,那么禁用交换所做的一切只会导致致命错误,而不是性能下降。

我将所有可用内存用于对象缓存

除非您的对象的寿命非常长,否则这是一个坏主意,因为垃圾收集器在运行时必须做很多工作。您经常会发现较小的缓存会导致较高的整体吞吐量。

使用映射字节缓冲区,操作系统处理数据何时写入磁盘的详细信息,我需要自己控制它,即。当我写(字节[])时,它会立即直接输出到磁盘

实际上,它不会,除非您使用该sync选项安装了文件系统。然后您仍然冒着因驱动器故障(尤其是在 RAID 0 中)而丢失数据的风险。

我不确定如果没有映射字节缓冲区我怎么能做到这一点

ARandomAccessFile会这样做。但是,您将在每次写入时至少为内核上下文切换付费(并且如果您为同步写入安装了文件系统,则每次写入都将涉及磁盘往返)。

我没有使用 ACID 事务

那么我猜这些数据并没有那么有价值。所以不要再担心有人会被电源线绊倒的可能性。

于 2013-02-14T19:00:04.747 回答
1

您对映射字节缓冲区的反对是站不住脚的。您的映射文件将与您的对象缓存不同,尽管它们占用地址空间,但它们不会消耗 RAM。您还可以随时同步映射的字节缓冲区(以牺牲一些性能为代价)。此外,随机访问文件最终会在幕后使用相同的设备,因此您无法在其中保存任何性能。

如果映射字节缓冲区没有为您提供所需的性能,您可能必须绕过文件系统并直接写入原始分区(这是 DBMS 所做的)。为此,您可能需要为数据处理编写 C++ 代码并通过 JNI 访问它。

于 2013-02-14T18:06:13.973 回答