键值商店建议

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

映射是Map ,因此我正在考虑使用GNU Trove TIntObjectHashMap ,并将映射值存储为ascii字节数组而不是String。

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

使用Berkeley DB

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

这绝对可以为您带来内存和速度的巨大提升,同时不会增加应用程序的复杂性。 请享用!

BabuDB

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

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

JDBM2

JDBM2提供由磁盘存储支持的HashMap和TreeMap。

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

香蕉DB

Banana DB是一个用Java实现的独立键/值对数据库。

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


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

这些所有数据库都允许将数据保存在磁盘上。 还有解决方案可以在内存中保存大型地图( ehcache , hazelcast ,…)。

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

特征

同时

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

快速

MapDB具有与原生数据库相媲美的出色性能。 这是十多年的优化和重写的结果。

MapDB可选地支持具有完全MVCC隔离的ACID事务。 MapDB使用预写日志或仅附加存储来提高写入持久性。

灵活

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

容易被破解

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

SQL喜欢

MapDB是作为SQL引擎的更快替代品而开发的。 它具有许多function,可以简化从关系数据库的转换:二级索引/集合,自动增量顺序ID,连接,触发器,复合键…

磁盘空间使用率低

MapDB具有许多function(序列化,增量密钥包装……),以最大限度地减少其商店使用的磁盘。 它还具有非常快速的压缩和自定义序列化程序。 我们认真对待磁盘使用,不浪费单字节。

只是想引用一些自首次提出此问题以来随时间推出的更多开源选项。

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环境,JetBrains YouTrack和Hub存储引擎:

https://github.com/JetBrains/xodus

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

这并不完全有意义,因为TIntObjectHashMap不是Map 。 但是,这种方法很合理。


你知道我对HashMap for Trove可以节省多少空间吗?

最好的答案是尝试一下。

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

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

  • Trove键是4字节的int值。

  • 字符串值为20个字节+ 12个字节+ 2个“字符数”。

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

  • 我没有检查相应哈希表内部数据结构的细节。

这可能相当于节省大约50%的内存,但它关键取决于值“字符串”的平均长度。 (它们越长,它们将占据空间使用的越多。)

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

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

  • 时间 – 内存权衡与Java地图的例子
  • 大型HashMap概述:JDK,FastUtil,Goldman Sachs,HPPC,Koloboke,Trove

如果配置为使用与Trove相同的内存。 或者,如果配置为与Trove同样快,您可以认为它消耗相当少的内存。


如果你想在非常快速的引导程序之间保持JVM运行之间的映射,你可能也会对Chronicle-Map感兴趣,它默认以UTF-8存储String s(所以你不应该为转换而烦恼String < - > byte[]和Koloboke / Trove一样)。 Chronicle-Map对于持久的键值存储非常快,但比Koloboke甚至Trove慢一点。