【问题标题】:key-value store suggestion键值存储建议
【发布时间】:2011-07-10 04:01:52
【问题描述】:

我需要一个非常基本的 Java 键值对存储。我从 HashMap 开始,但似乎 HashMap 的空间效率有点低(我存储了大约 2000 万条记录,并且似乎需要大约 6GB RAM)。

地图是Map<Integer,String>,因此我正在考虑使用 GNU Trove TIntObjectHashMap<byte[]>,并将地图值存储为 ascii 字节数组而不是字符串。

作为替代方案,是否有一个键值存储只需要添加 jar 文件,不会一次将整个映射保存在 RAM 中,并且仍然相当快?

【问题讨论】:

  • 只是想评论一下我已经使用 Trove 有一段时间了,它们似乎非常可靠。每当我需要原始键和/或值时,我都会使用它们。
  • ehCache?具有自动溢出到磁盘的功能,并且对于内存中的内容具有类似哈希图的性能。不知道它如何处理 2000 万个进入磁盘的条目。
  • 你知道我可以通过 HashMap for Trove 节省什么样的空间吗?

标签: java nosql


【解决方案1】:

BabuDB

BabuDB 是一个嵌入式非关系型数据库系统。其精简和简单的设计使其能够持久存储大量键值对,而无需像 BerkeleyDB 等类似方法的开销和复杂性。

许可证:新 BSD 许可证,语言:Java

JDBM2

JDBM2 提供了 HashMap 和 TreeMap,它们是由磁盘存储支持的。

许可证:Apache 许可证 2.0,语言:Java

Banana DB

Banana DB 是一个用 Java 实现的自包含键/值对数据库。

许可证:Apache 许可证 2.0,语言:Java


我已经尝试过 BabuDB 和 JDBM2,它们工作正常。 BabuDB 设置起来有点困难,但可能提供比 JDBM2 更高的性能。

这些都是允许将数据持久化在磁盘上的所有数据库。还有一些解决方案可以在内存中保存大地图(ehcachehazelcast、...)。

【讨论】:

  • BabuDB 看起来不错,但我仍在寻找一些入门文档(向开发人员询问了这件事)。
  • 获得这些文档好运吗?我在 Babu DB 中有一个 this interface 的实现,但目前找不到它...
【解决方案2】:

使用Berkeley DB

Berkeley DB 将对象图、集合中的对象或简单的二进制键/值数据直接存储在磁盘上的 btree 中。这种简单、高效的方法消除了 ORM 解决方案中所有不必要的开销。使用直接持久层 (DPL) Java 开发人员使用存储信息对类进行注释,这与 JPA 非常相似。这种方法熟悉、高效且快速。 DPL 在不牺牲速度的情况下降低了数据存储的复杂性。

这肯定会给您带来巨大的内存和速度收益,同时不会增加应用程序的复杂性。尽情享受吧!

【讨论】:

  • 我听说这存在许可问题,这是真的吗?
  • @Kevin - 这取决于您/您的产品/您的公司会遇到什么问题。您可以在oracle.com/technetwork/database/berkeleydb/downloads/… 阅读有关许可选项的信息......并做出自己的判断。
  • tl;dr:如果 1) 您的项目是开源的,或者 2) 供内部使用(非再分发),您可以免费使用它。否则,您需要从 Oracle 获得许可(他们没有说明潜在成本)。
  • 啊,谢谢。开源许可证可用于未分发给第三方的非开源应用程序。完美。
  • 请注意,Oracle 最近将其开源许可证更改为 Affero 许可证:oracle.com/technetwork/products/berkeleydb/downloads/…
【解决方案3】:

http://www.mapdb.org/ 是您正在寻找的。这是 java.util.Map 的快速持久实现。

特点

并发

MapDB 具有记录级锁定和最先进的并发引擎。它的性能几乎与内核数量呈线性关系。数据可以由多个并行线程写入。

快速

MapDB 具有只有本地数据库才能匹敌的出色性能。这是十多年优化和重写的结果。

MapDB 可选择支持具有完全 MVCC 隔离的 ACID 事务。 MapDB 使用 write-ahead-log 或 append-only 存储来实现出色的写入持久性。

灵活

MapDB 可用于从内存缓存到多 TB 数据库的任何地方。它还有许多选项可以用持久性换取写入性能。这使得配置 MapDB 以完全满足您的需求变得非常容易。

可破解

MapDB 是基于组件的,大多数功能(实例缓存、异步写入、压缩)只是类包装器。将新功能或组件引入 MapDB 非常容易。

SQL 类

MapDB 是作为 SQL 引擎的更快替代品而开发的。它具有许多特性,使从关系数据库的转换变得更加容易:二级索引/集合、自动增量顺序 ID、连接、触发器、复合键......

磁盘空间使用率低

MapDB 具有许多功能(序列化、增量键打包……)以最小化其存储使用的磁盘。它还具有非常快速的压缩和自定义序列化程序。我们认真对待磁盘使用情况,不浪费单个字节。

【讨论】:

  • 我不喜欢这个需要多少依赖 jar。而且 MapDB 本身已经相当大了(700k)。
【解决方案4】:

考虑Koloboke Collections,根据各种测试,它比 Trove 快 2 倍:

如果配置为消耗与 Trove 相同的内存。或者,如果配置为与 Trove 一样快,您可以认为它消耗的内存要少得多。


如果您想通过非常快速的引导来保持 JVM 运行之间的映射,您可能还对 Chronicle-Map 感兴趣,它默认将 Strings 存储在 UTF-8 中(因此您不应该为转换而烦恼 @987654326 @ byte[] 与 Koloboke/Trove 一样)。 Chronicle-Map 对于持久键值存储来说是超快的,但比 Koloboke 甚至 Trove 要慢一些。

【讨论】:

    【解决方案5】:

    只是想参考一些自首次提出此问题以来随着时间的推移而变得可用的更多开源选项。

    Apache 2、BTree、Apache Directory Project JDBM 替换工作:

    http://directory.apache.org/mavibot/

    MPL2/EPL1、RTree、MVStore、H2 存储引擎:

    http://www.h2database.com/html/mvstore.html

    Apache 2、Xodus Environments、JetBrains YouTrack 和 Hub 存储引擎:

    https://github.com/JetBrains/xodus

    【讨论】:

      【解决方案6】:

      地图是 Map,所以我正在考虑使用 GNU Trove TIntObjectHashMap,并将地图值存储为 ascii 字节数组而不是字符串。

      这并不完全有道理,因为TIntObjectHashMap 不是Map。但是,这种方法是合理的。


      您知道 HashMap for Trove 可以节省哪些空间?

      最好的答案是尝试一下。

      但这里有一些粗略的估计(假设是 32 位 JVM):

      • HashMap 键需要是 Integer 实例。它们将占用每个实例约 18 个字节 + 每个引用 4 个字节。共 24 个字节。

      • Trove 密钥将是 4 字节 int 值。

      • 字符串值将是 20 字节 + 12 字节 + 2 * “字符”数。

      • 字节数组值将是 12 字节 + 1 * “字符”数。

      • 我还没有检查过各个哈希表内部数据结构的细节。

      这可能相当于节省了大约 50% 的内存,尽管它主要取决于值“字符串”的平均长度。 (它们越长,它们将越多地支配空间使用。)

      FWIW,Trove 发布了他们自己的基准测试here。它们看起来不太令人信服,但您应该能够挖掘出他们的基准代码并对其进行修改以更好地匹配您的用例。

      【讨论】:

      • TIntObjectHashMap 不是 Map,因为它没有实现 java.util.Map,但它确实支持原语的 put/get,这是我关心的。如果我没看错,它会使用开放寻址哈希映射实现。或者当你说 TIntObjectHashMap 不是地图时,你的意思是什么?
      • @Stephen 你是如何计算 HashMap 的内存的?顺便说一句:trove 需要 5 个字节,其中 4 个用于 int,1 个用于 state。
      • 哦,trove 需要 9 个字节!使用 4 表示索引 (int[]),1 表示状态 (byte[]),4 表示引用 (Object[])。
      • @Karussell - 我没有计算 HashMap 的内存。我估计并比较了键的大小;即Integer 实例与ints。如果您想添加自己的答案,请随时这样做。
      • @StephenC 啊,好的。 (不,我只是想知道如何计算)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-24
      • 1970-01-01
      • 2011-03-08
      • 2013-05-05
      • 2011-04-03
      相关资源
      最近更新 更多