纪事报地图显着减慢,参赛人数超过200米

时间:2016-01-04 14:27:51

标签: chronicle chronicle-map

我正在使用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分页这样大文件的假象吗?

1 个答案:

答案 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亿。