• 结论:
    • 写性能:
    • 读性能:
    • 警告和限制
      • 隔离级别低到高:
        • 1)未提交读(READ UNCOMMITTED)
        • 2)在提交读(READ COMMITTED)
        • 3)在可重复读(REPEATABLE READS)
        • 4)可串行化 (Serializable)
    • 联系作者
    • 参与贡献
    • 致谢
    • License

    结论:

    写性能:

    NutsDB最快。 NutsDB比BoltDB快2-5倍 , 比BadgerDB快0.5-2倍。
    BadgerDB次之,他比BoltDB快1-3倍。
    BoltDB最慢。

    读性能:

    默认模式下,读都很快。其中NutsDB在默认配置下比其他数据库快一倍。但是如果使用HintKeyAndRAMIdxMode的选项,读速度比默认配置低很多。道理很简单,默认配置是全内存索引,但是HintKeyAndRAMIdxMode的模式,是内存索引+磁盘混合的方式,但是这个选项模式可以保存远大于内存的数据。特别是value远大于key的场景效果更明显。

    警告和限制

    • 启动索引模式

    从v0.3.0开始不再支持MMap的模式,使用HintKeyValAndRAMIdxModeHintKeyAndRAMIdxMode 这两种作为db启动的时候索引模式。
    默认使用HintKeyValAndRAMIdxMode。在基本的功能的string数据类型(put、get、delete、rangeScan、PrefixScan)这两种模式都支持。HintKeyValAndRAMIdxMode,作为数据库默认选项,他是全内存索引,读写性能都很高。他的瓶颈在于内存。如果你内存够的话,这种默认是适合的。如果你需要存下大于内存的数据,可以使用另一种模式HintKeyAndRAMIdxMode,他会把value存磁盘,通过索引去找offset,这种模式特别适合value远大于key的场景。他的读性能要比起默认模式要降低不少,具体看自己的要求。关于其他的数据结构(list\set\sorted set)不支持HintKeyAndRAMIdxMode这个模式,只支持默认的HintKeyValAndRAMIdxMode,所以如果你要用到其他数据结构如list、set等。请根据需要选模式

    • Segment配置问题

    NutsDB会自动切割分成一个个块(Segment),默认SegmentSize是8MB,这个参数可以自己配置,但是一旦配置不能修改

    • key和value的大小限制问题

    关于key和value的大小受到SegmentSize的大小的影响,比如SegmentSize为8M,key和value的大小肯定是小于8M的,不然会返回错误。
    在NutsDB里面entry是最小单位,只要保证entry不大于SegmentSize就可以了。

    • entry的大小问题

    entry的的大小=EntryHeader的大小+key的大小+value的大小+bucket的大小

    • 关于支持的操作系统

    目前对Mac OS X 和 Linux 支持,Windows平台暂时不予支持。

    • 关于事务说明

    在传统的关系式数据库中,常常用 ACID 性质来检验事务功能的安全性,NutsDB目前的版本并没有完全支持ACID。 NutsDB从v0.2.0之后的版本开始完全支持ACID。

    这这特别感谢 @damnever 给我提的issue给我指出,特别在这说明下,免得误导大家。

    从v0.3.0版本起,NutsDB支持(A)原子性、C(一致性)、I(隔离性),并保证(D)持久化。以下参考wiki百科的对ACID定义分别讲一下。如讲的有误,欢迎帮我指正。

    1、(A)原子性

    所谓原子性,一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。实现事务的原子性,要支持回滚操作,在某个操作失败后,回滚到事务执行之前的状态。一般的做法是类似数据快照的方案。关于这一点,NutsDB支持回滚操作。NutsDB的作法是先实际预演一边所有要执行的操作,这个时候数据其实还是uncommitted状态,一直到所有环节都没有问题,才会作commit操作,如果中间任何环节一旦发生错误,直接作rollback回滚操作,保证原子性。 就算发生错误的时候已经有数据进磁盘,下次启动也不会被索引到这些数据。

    2、(C)一致性

    在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的数据必须完全符合预期的。NutsDB基于读写锁实现锁机制,在高并发场景下,一个读写事务具有排他性的,比如一个goroutine需要执行一个读写事务,其他不管想要读写的事务或者只读的只能等待,直到这个锁释放为止。保证了数据的一致性。所以这一点NutsDB满足一致性。

    3、(I)隔离性

    数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。如上面的一致性所说,NutsDB基于读写锁实现锁机制。不会出现数据串的情况。所以也是满足隔离性的。

    关于事务的隔离级别,我们也来对照wiki百科,来看下NutsDB属于哪一个级别:

    隔离级别低到高:

    1)未提交读(READ UNCOMMITTED)

    这个是最低的隔离级别。允许“脏读”(dirty reads),事务可以看到其他事务“尚未提交”的修改。很明显nutsDB是避免脏读的。

    2)在提交读(READ COMMITTED)

    定义:这个隔离级别中,基于锁机制并发控制的DBMS需要对选定对象的写锁一直保持到事务结束,但是读锁在SELECT操作完成后马上释放(因此“不可重复读”现象可能会发生)。
    看下“不可重复读”的定义:在一次事务中,当一行数据获取两遍得到不同的结果表示发生了“不可重复读”。

    nutsDB不会出现“不可重复读”这种情况,当高并发的时候,正在进行读写操作,一个goroutine刚好先拿到只读锁,这个时候要完成一个读写事务操作的那个goroutine要阻塞等到只读锁释放为止。也就避免上面的问题。

    3)在可重复读(REPEATABLE READS)

    定义:这个隔离级别中,基于锁机制并发控制的DBMS需要对选定对象的读锁(read locks)和写锁(write locks)一直保持到事务结束,但不要求“范围锁”,因此可能会发生“幻影读”。

    关于幻影读定义,指在事务执行过程中,当两个完全相同的查询语句执行得到不同的结果集。这种现象称为“幻影读(phantom read)”,有些人也叫他幻读,正如上面所说,在nutsDB中,当进行只读操作的时候,同一时间只能并发只读操作,其他有关“写”的事务是被阻塞的,直到这些只读锁释放为止,因此不会出现“幻影读”的情况。

    4)可串行化 (Serializable)

    定义:这个隔离级别是最高的。避免了所有上面的“脏读”、不可重复读”、“幻影读”现象。

    在nutsDB中,一个只读事务和一个写(读写)事务,是互斥的,需要串行执行,不会出现并发执行。nutsDB属于这个可串行化级别。
    这个级别的隔离一般来说在高并发场景下性能会受到影响。但是如果锁本身性能还可以,也不失为一个简单有效的方法。当前版本nutsDB基于读写锁,在并发读多写少的场景下,性能会好一点。

    4、(D)持久化

    事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。v0.3.0之前版本的nutsdb为了提供高性能的写入,并没有实时的做sync操作。从v0.3.0开始使用sync操作作强制同步,开始支持持久化,建议使用最新版本。

    关与其他信息待补充。有错误请帮忙指出,提给我issue,谢谢。

    联系作者

    • xujiajun

    参与贡献

    :+1::tada: 首先感谢你能看到这里,参与贡献 :tada::+1:

    参与贡献方式不限于:

    • 提各种issues(包括询问问题、提功能建议、性能建议等)
    • 提交bug
    • 提pull requests
    • 优化修改README文档

    详情参考英文版的 CONTRIBUTING 。

    致谢

    这个项目受到以下项目或多或少的灵感和帮助:

    • Bitcask-intro
    • BoltDB
    • BuntDB
    • Redis
    • Sorted Set

    License

    The NutsDB is open-sourced software licensed under the Apache 2.0 license.