我正在使用Chronicle Map临时存储/查找大量的KV对(实际上是几十亿)。我不需要持久性或复制,我使用的是内存映射文件,而不是纯粹的堆外内存。平均密钥长度为8个字节。
对于小型数据集 - 最多2亿条目 - 我每秒可获得大约100万条目的吞吐量,即创建条目大约需要200秒,这是惊人的,但是有4亿条目,地图显着减慢了创建它们需要1500秒。
我已经在运行Linux的Mac OSX / 16GB四核/ 500GB SSD和Proliant G6服务器上运行测试,其中包括8核/ 64GB ram / 300GB Raid 1(不是SSD)。在两个平台上都表现出相同的行为。
如果有帮助,这是地图设置:
try {
f = File.createTempFile(name, ".map");
catalog = ChronicleMapBuilder
.of(String.class, Long.class)
.entries(size)
.averageKeySize(8)
.createPersistedTo(f);
} catch (IOException ioe) {
// blah
}
一个简单的作家测试:
long now = -System.currentTimeMillis();
long count = 400_000_000L;
for (long i = 0; i < count; i++) {
catalog.put(Long.toString(i), i);
if ((i % 1_000_000) == 0) {
System.out.println(i + ": " + (now + System.currentTimeMillis()));
}
}
System.out.println(count + ": " + (now + System.currentTimeMillis()));
catalog.close();
所以我的问题是 - 我可以采取某种调整来改善这种情况,例如:更改段数,使用不同的密钥类型(例如CharSequence),或者这只是OS分页这样大文件的假象吗?
答案 0 :(得分:1)
有几件事可能会有所帮助:
确保您使用最新的可用的Chronicle Map版本(目前为3.3.0-beta
,下一个3.4.0-beta
以天为单位)
确实使用无垃圾技术,即使对于这样的测试,这也很重要,因为垃圾收集可能会起作用:
CharSequence
作为键类型,使用LongValue
作为值类型。简单的测试代码可能看起来像
public class VinceTest {
public static void main(String[] args) throws IOException {
long count = 400_000_000L;
File f = File.createTempFile("vince", ".map");
f.deleteOnExit();
try (ChronicleMap<CharSequence, LongValue> catalog = ChronicleMap
.of(CharSequence.class, LongValue.class)
.entries(count)
.averageKeySize(8.72)
.putReturnsNull(true)
.createPersistedTo(f)) {
long prev = System.currentTimeMillis();
StringBuilder key = new StringBuilder();
LongValue value = Values.newHeapInstance(LongValue.class);
for (long i = 1; i <= count; i++) {
key.setLength(0);
key.append(i);
value.setValue(i);
catalog.put(key, value);
if ((i % 1_000_000) == 0) {
long now = System.currentTimeMillis();
System.out.printf("Average ns to insert per mi #%d: %d\n",
(i / 1_000_000), now - prev);
prev = now;
}
}
System.out.println("file size " + MEGABYTES.convert(f.length(), BYTES) + " MB");
}
}
}
从上面的来源中,注意putReturnsNull(true)
的用法,以避免在返回值时意外产生垃圾(虽然不是这个测试的情况,因为所有键都是唯一的,put()
总是返回null
,但可能是您的作品的情况)
确保您指定了正确的averageKeySize()
。从该测试中,平均密钥大小实际上接近9个字节(因为大多数密钥大于100 000 000)。但最好尽可能精确,这个特殊测试的数量为8.72,计数为4亿。