LevelDB是一个由谷歌开发的提供快速存取的key-value类型的数据库。从string类型的key到string类型的value之间的映射(mapping)是排序的。
Features:
1.key和value可以是任意字节的数组。
2.Data是根据key来存储并排序的。
3.用户可以定义自己的比较函数(comparsion)来从新实现排序规则。
4.基本操作有Put(key,value),Get(key),Delete(key).
5.大量的更新可以被定义为一个原子性操作。
6.用户可以创建一个短暂的快照来获得一个保持(保证)一致性的数据视图。
7.可以从前也可以从后遍历整个数据库。
8.数据会被自动压缩。
9.外部活动(例如对文件系统的操作)可以通过一个虚拟接口传递进来,
这样用户可以自己定义与操作系统的交互。
Limitations:
LevelDB不是一个SQL类型的数据库。他没有关系数据模型,也不支持SQL查询,
也不支持索引。
每次只能通过单进程(或单进程内的多线程)对特定的数据库进行处理。
数据库不提供自带的客户端,需要上述功能的应用必须自己围绕LevelDB编写客户端功能
Performance:
这里有一份db_bench程序运行之后的带解释的性能测试报告。比较粗略,但是足够得出
一个大致的性能报告。
Setup:
我们在数据库中存储了100W条记录。
每条记录由一个16字节的key和100字节的value组成。数据被压缩成了原来大小的一半。
LevelDB: version 1.1
Date: Sun May 1 12:11:26 2011
CPU: 4 x Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz
CPUCache: 4096 KBRaw Size: 110.6 MB (estimated)
File Size: 62.9 MB (estimated)
Write performance:
一般创建一个“fill"基准的数据库,可以是顺序的,也可以是乱序的。
如果创建的是"fillsync"基准的数据库,在每次操作后,都会把数据回写到硬盘上;
其他的写入操作,将会把数据保留在系统中的cache缓存中一段时间。
如果创建的是"overwrite"基准的数据库,当更新一个已存在的key值时会进行随机写入。
(不是很理解,之后实践操作一下)
fillseq : 1.765 micros/op; 62.7 MB/s
fillsync : 268.409 micros/op; 0.4 MB/s (10000 ops)
fillrandom : 2.460 micros/op; 45.0 MB/s
overwrite : 2.380 micros/op; 46.5 MB/s
上面的每一个操作对应着写入一个单一的key-value对。
一个random wirte基准的数据库,每秒大概写入400,000次。
一个fillsync的操作(大概花费0.3 millisecond)远少于一个磁盘寻道(10 milliseconds)时间。
我们猜测,这是因为硬盘自己本身会缓存刚刚更新的数据,如果要获取还没来得及写入到
盘片上,就直接从缓存中取出。(意思就是硬盘自己会缓存)
这到底是不是一种安全的方式呢?
要取决于发生电源故障的时候,硬盘是否有足够的电量支持将缓存中的数据写入到盘片上。
Read performance:
我们将列举出分别从正向和逆向的顺序读取,以及随机查找的性能报告。
指的注意的是,创建一个某一标准的数据库大家不是很大。
上面的性能报告描绘的是在内存能够容纳下数据库工作集的情况时的特点。
当要获取的一对数据不在操作系统的缓冲区内时,可能需要一次或两次寻道才能从硬盘上获取。
写入操作的性能几乎不受数据库工作集是否存在内存中的影响。
readrandom : 16.677 micros/op; (approximately 60,000 reads per second)
readseq : 0.476 micros/op; 232.3 MB/s
readreverse : 0.724 micros/op; 152.9 MB/s
LevelDB通过把后台中潜在数据压缩来提高读操作的性能。
上述的性能报告是紧接着一系列随机写入操作后马上进行的读取后得出的。
通过数据压缩(自动触发的)后处理的测试报告更好:
readrandom : 11.602 micros/op; (approximately 85,000 reads per second)
readseq : 0.423 micros/op; 261.8 MB/s
readreverse : 0.663 micros/op; 166.9 MB/s
读取操作的高开销主要是在重复的从磁盘块解压块数据,如果我们能都提供足够的
缓存来才存储那些未压缩的数据,那么读操作的性能将会大大提升:
readrandom : 9.775 micros/op; (approximately 100,000 reads per second before compaction)
readrandom : 5.215 micros/op; (approximately 190,000 reads per second after compaction)
Repository contents:
详细的解释请见doc/index.html。doc/impl.html中简单介绍了LevelDB是如何实现的。
include/*.h中的都是公有接口。用户不要依赖这个文件夹中的其他头文件。
这些内部API可能在没有提醒的情况下发生更改。
对头文件的预览:
include/db.hDB的主要接口,从这里开始。
include/options.h控制着整个数据库,也空着这每个读写的行为。
include/comparator.h一个用户自定义comparsion function的抽象。
如果你仅仅想逐字节比较每个关键字,可以直接使用默认的comparator;
如果用户想自己定义排序规则,就需要实现自己的comparator(还要处理不同的编码问题)。
include/iterator.h遍历数据的接口。可以从DB object中获得一个iterator.
include/write_batch.h原子性更新多个数据的接口。
include/slice.h一个简单的模块,该模块负责维护指向其他数组的指针和长度。
include/status.h很多public interfaces都返回status。status可以用来表明操作成功的状态,或者各种错误信息。
include/env.h操作系统环境的抽象。util/env_posix.cc是一个按照posix标准的对这个接口的实现。
include/table.h;include/table_builder.h一个大多数用户不会直接使用到的低层次的模块。