MapDB
MapDB提供了并发的Maps,Sets 和 Queues,基于磁盘存储或off-heap-memory。这是一个快速,可扩展的和易于使用的嵌入式Java数据库引擎。小但功能强大,如事务,空间高效的序列化,实例缓存和透明压缩/加密。
<dependency>
<groupId>org.mapdb</groupId>
<artifactId>mapdb</artifactId>
<version>VERSION</version>
</dependency>
Version 可以从这里找到http://mvnrepository.com/artifact/org.mapdb/mapdb
in-memory 方式, 使用off-heap存储,不受GC限制:
//import org.mapdb.*
DB db = DBMaker.memoryDB().make();
ConcurrentMap map = db.hashMap("map").make();
map.put("something", "here");
当关闭db object,通过指定文件存储:
DB db = DBMaker.fileDB("file.db").make();
ConcurrentMap map = db.hashMap("map").make();
map.put("something", "here");
db.close();
MapDB默认使用通用序列化方式进行序列化各种数据类型,指定特定的序列化数据类型将会更加快速与内存使用更有效率。
DB db = DBMaker
.fileDB("file.db")
//TODO memory mapped files enable here
.make();
ConcurrentMap<String,Long> map = db
.hashMap("map", Serializer.STRING, Serializer.LONG)
.make();
map.put("something", 111L);
db.close();
HTreeMap提供HashMap and HashSet集合特性,支持entry expiration,可以用作缓存。
HTreeMap<String, Long> map = db.hashMap("name_of_map")
.keySerializer(Serializer.STRING)
.valueSerializer(Serializer.LONG)
.create();
//or shorter form
HTreeMap<String, Long> map2 = db
.hashMap("some_other_map", Serializer.STRING, Serializer.LONG)
.create();
HTreeMap推荐用于处理large key/values,有时候你需要进行压缩,它能提供开启压缩store-wide,但这样仍会有瓶颈。此外,更好的方式是通过特定的serializer压缩key和value,如下:
HTreeMap<Long, String> map = db.hashMap("map")
.valueSerializer(
new SerializerCompressionWrapper(Serializer.STRING))
.create();
还有Hash Code ,Layout, Expiration Overflow等定制内容,详情可以参考官网。
BTreeMap提供TreeMap and TreeSet特征。它基于 lock-free concurrent B-Linked-Tree实现方式,提供small keys更好的性能,与更好的水平伸缩。
使用指定的serializers将带来更好的性能,如下:
BTreeMap<Long, String> map = db.treeMap("map")
.keySerializer(Serializer.LONG)
.valueSerializer(Serializer.STRING)
.createOrOpen();
默认情况下BTreeMap并不会跟踪map的size,通过调用map.size()去线性搜索计算所有的元素实体。如果开启了size counter,调用map.size()将马上返回,但是对insert有性能损耗。如下:
BTreeMap<Long, String> map = db
.treeMap("map", Serializer.LONG, Serializer.STRING)
.counterEnable()
.createOrOpen();
BTrees存储keys与values作为btree节点部分。节点的长度对性能的影响很大。A large node意味着许多keys在查询需要被进行反序列化。A smaller node加载会快些,但会使得BTrees层级更深和需要更多的操作。默认最大的node size是32,可以通过以下方式进行修改:
BTreeMap<Long, String> map = db
.treeMap("map", Serializer.LONG, Serializer.STRING)
.maxNodeSize(64)
.createOrOpen();
Values存储作为btree叶节点部分。Large values意味着巨大的开销在单个map中。如果get(“key”)需要进行序列化,但是只返回一个值,更好的方式是存储在叶节点外,在一条单独的记录。在这种情况下,叶节点仅用6字节指向这个值。Large values可以通过压缩来减少存储空间。存储node outside BTree leaf nodes 和压缩每个值的例子:
BTreeMap<Long, String> map = db.treeMap("map")
//TODO external values are not supported yet
//.valuesOutsideNodesEnable()
.valueSerializer(new SerializerCompressionWrapper(Serializer.STRING))
.createOrOpen();
BTreeMap 需要以某种方法排序它的keys,默认情况下,大多数的Java类依靠Comparable接口的实现。如果此接口没有被实现,一个key serializer必须被提供。以下是可以比较 Object arrays 的例子:
BTreeMap<Object[], Long> map = db.treeMap("map")
// use array serializer for unknown objects
// TODO db.getDefaultSerializer()
.keySerializer(new SerializerArray(Serializer.JAVA))
// or use serializer for specific objects such as String
.keySerializer(new SerializerArray(Serializer.STRING))
.createOrOpen();
同样primitive arrays能被用作keys,一个String能被byte[]替代,这样将会有更好的性能:
BTreeMap<byte[], Long> map = db.treeMap("map")
.keySerializer(Serializer.BYTE_ARRAY)
.valueSerializer(Serializer.LONG)
.createOrOpen();
mark 这里还有性能的测试:
http://www.mapdb.org/benchmarks/