lmdb简介

lmdb是openLDAP项目开发的嵌入式(作为一个库嵌入到宿主程序)存储引擎。其主要特性有:

  • 基于文件映射IO(mmap)
  • 基于B+树的key-value接口
  • 基于MVCC(Multi Version Concurrent Control)的事务处理
  • 类bdb(berkeley db)的api

实现

底层读写的实现

lmdb的基本思路是使用mmap访问存储,不管这个存储实在内存上还是在持久存储上。

lmdb的所有读取操作都是通过mmap将要访问的文件只读地装载到宿主进程的地址空间,直接访问相应的地址,这减少了硬盘、内核地址控件和用户地址空间之间的拷贝,也简化了平坦的“索引空间”上的实现,因为使用了read-only的mmap,规避了因为宿主程序错误将存储结构写坏的风险。IO的调度由操作系统的页调度机制完成。

而写操作,则是通过write系统调用进行的,这主要是为了利用操作系统的文件系统一致性,避免在被访问的地址上进行同步。

基于MVCC的存储引擎

我们在前面提及,lmdb上的读取操作,直接读取了mmap所装载的内存地址,那么,如果所读取的内容被修改了,不是出现了不一致的结果吗?事实是,lmdb上的所有内容都不会被修改。

lmdb用MVCC处理并发读写访问的问题。其要点在于:

  • 每一个变更对应一个版本
  • 变更发生的时候不修改原来的版本
  • 读者进入的时候会取得一个版本,它只读取这个版本的内容

对于一个树形数据结构,当它的一个节点上发生变更的时候,就创建一个新的节点,在新的节点上容纳这些变更,由于这个节点的父节点也要发生变更(从指向原来的节点变更为指向新的这个节点),那么重复上述过程,即,实际发生变更的节点通往根节点路径上的所有节点都必须重新创建一份,当变更工作完成的时候,我们通过一个原子操作提交这个变更版本。大体是这样一个过程:

如上图所示,每个新的版本就会产生一个新的跟节点,按照上述处理,最终的存储中就会保留历史上所有的版本,当然,所有版本中就包括了当前所有读者所读的版本,因此,变更不会对读者产生任何影响,所以,写可以不被读阻塞。

上面,我们讨论了读的情况,上述方法承诺给每一个读一个一致的版本(就是它进入时所得到的那个版本),但没有承诺给它一个最新的版本,我们考虑在一个事务中,依据一个值变更另一个值的情况,很显然,当我们想要提交变更的时候,很可能我们进入时所得到的版本已经不是最新的,也就是说,在我们的进入和提交之间发生了另一个提交,这种情况下,如果提交了变更就会发生不一致的状况,譬如一个单调递增的计数器,就因此可能“吃掉”多个递增。为了解决这个问题,我们只要在提交时检查我们进入的版本是否最新版本即可,这常常可以通过一个CAS原子操作完成,如果这个操作失败,就重新进入存储,重做整个事务。这样,读也可以不被(可能的)写阻塞。

按照上述描述,我们的存储中保存了所有的历史版本,这是否必要呢?事实上,我们所以保存历史版本,是因为有可能有读者读它,新的读者总是读到最新的版本,老的版本就没有用了,如果一个版本上没有任何读者(和写者),那它就没有必要存在了。我们可以依据上述原理实现旧版本的回收,不过lmdb做了一些改进:

  • 一个基本的事实是,新的读者总是去读最新的版本,因此,保留所有版本的根节点是不必要的,我们只需要保存一个最新版本的根节点和一个用于提交更加新的变更的节点即可。
  • 所有读者进入的时候,都复制当前的根节点的一个snapshot(因为它随后很可能被改变)
  • 当一个变更被提交的时候,它清楚因为这个提交,哪些节点迟早会变成没用的---所有因为这次变更发生过修改的节点,都会在相应版本的读者退出后变成无用的节点,因此可以回收
  • 因为上述理由,最新的版本可以收集所有需要被回收的节点和它们所属的版本
  • 维护一个读者的slot,可以从这里面查到最小的版本,比这个版本小的版本所属的可回收节点都可以进行回收

如上所述,我们现在只有两个根节点,所有变更最终都要修改这个根节点,这样,所有的写事实上要被序列化。这并没有降低性能,理由是这样的,如我们上面所述的,当两个变更并发进行的时候,确切的说,是进入同一个版本,并依据这个版本进行了某些变更,然后要提交这些变更,两者中必有一个事务必须重做,因为在它的提交和进入之间有别的提交,这个结论可以推广到多个并发的情况。也就是说,变更事实上是序列化的,由于不同的变更之间没有阻塞,MVCC的方案消耗了更多的计算资源(所有失败的提交都要被重做)。因此,lmdb用一把锁序列化了所有的变更操作。

以上就是lmdb实现中大部分要点。

原文链接:http://www.jianshu.com/p/yzFf8j

Leveldb和lmdb

Caffe生成的数据分为2种格式:Lmdb和Leveldb。
它们都是键/值对(Key/Value Pair)嵌入式数据库管理系统编程库。
虽然lmdb的内存消耗是leveldb的1.1倍,但是lmdb的速度比leveldb快10%至15%,更重要的是lmdb允许多种训练模型同时读取同一组数据集。

因此lmdb取代了leveldb成为Caffe默认的数据集生成格式。

LevelDb有如下一些特点:
   首先,LevelDb是一个持久化存储的KV系统,和Redis这种内存型的KV系统不同,LevelDb不会像Redis一样狂吃内存,而是将大部分数据存储到磁盘上。
   其次,LevleDb在存储数据时,是根据记录的key值有序存储的,就是说相邻的key值在存储文件中是依次顺序存储的,而应用可以自定义key大小比较函数,LevleDb会按照用户定义的比较函数依序存储这些记录。
   再次,像大多数KV系统一样,LevelDb的操作接口很简单,基本操作包括写记录,读记录以及删除记录。也支持针对多条操作的原子批量操作。

   另外,LevelDb支持数据快照(snapshot)功能,使得读取操作不受写操作影响,可以在读操作过程中始终看到一致的数据。

除此外,LevelDb还支持数据压缩等操作,这对于减小存储空间以及增快IO效率都有直接的帮助。LevelDb性能非常突出,官方网站报道其随机写性能达到40万条记录每秒,而随机读性能达到6万条记录每秒。总体来说,LevelDb的写操作要大大快于读操作,而顺序读写操作则大大快于随机读写操作。

转载于:https://www.cnblogs.com/bonelee/p/6236298.html

lmdb简介——结合MVCC的B+树嵌入式数据库相关推荐

  1. python123实验七答案_2020年智慧树嵌入式系统与实验第七单元章节测试答案

    2020年智慧树嵌入式系统与实验第七单元章节测试答案 更多相关问题 [多选题]含挥发油丰富,易散失气味的中药饮片有() A. 荆芥 B. 薄荷 C. 当归 D. 白芷 E. 肉桂 [单选题]求大同存小 ...

  2. 【Rust每周一库】sled - 嵌入式数据库

    简介 Sled是基于Bw树构建的嵌入式KV数据库,其API接近于一个线程安全的BTreeMap<[u8], [u8]>.而其Bw树的数据结构加上包括crossbeam-epoch的&quo ...

  3. 嵌入式数据库BERKELEY DB 之dubbo实战

    berkeley db 时oracle旗下的一款嵌入式数据库...当然,在互联网业界,他并不火,但是它确实很省内存,,对于一些想要替换redis的解决方案--可以考虑..想要学习它.甚至在一些主流的网 ...

  4. java内嵌数据库_Java嵌入式数据库-MapDB

    MapDB可以直接将Java的数据类型存储至直接内存而非JVM的堆中,也可以将数据持久化到磁盘. 与文无关 今天和大家介绍一个Java的第三方库,MapDB,它是用Kotlin写的,据说代码质量还不错 ...

  5. 嵌入式数据库知识概括

    嵌入式数据库知识概况 嵌入式数据库 Derby SQLite H2 总结 嵌入式数据库 嵌入式数据库(Embedded Database)简介: 从软件角度来说,数据库分类为两种: ①第一种:数据库服 ...

  6. Linux网络编程小项目sqlite,嵌入式数据库sqlite

    *************************************** * 嵌入式数据库sqlite在LPC22XX上的应用 * ******************************* ...

  7. 嵌入式数据库SQLite的编译、安装和使用[ZT]

    嵌入式数据库SQLite的编译.安装和使用 下文介绍的内容都是基于 RedHat Linux 9.0 平台的. 引言:sqlite简介 sqlite是嵌入式SQL数据库引擎SQLite(SQLite ...

  8. 嵌入式数据库Sqlite移植教程-转

    嵌入式数据库Sqlite移植教程 sqlite-3.3.6编译安装与交叉编译全过程详细记录 本文介绍的内容都是基于 Linux RedHat 9.0 平台的. 一.PC机编译安装 请阅读在安装包里的 ...

  9. Linux嵌入式数据库

    文章目录 一.SQLite简介 二.SQLite数据库安装 三.SQLite的命令用法 3.1 创建一个数据库 3.2 创建一张表格 3.3 向创建的表格中插入数据 3.4 查看数据库的记录 3.5 ...

最新文章

  1. python手机版做小游戏代码大全-Python大牛手把手教你做一个小游戏,萌新福利!...
  2. Docker学习笔记之二,基于Dockerfile搭建JAVA Tomcat运行环境
  3. c语言猴子吃桃嵌套调用编程,C语言实现猴子吃桃问题(循环、递归两种方法)...
  4. 连接目标数据库+无恢复目录连接目标数据库+使用有恢复目录连接目标数据库+注册数据库+目录同步+取消目标数据库的连接...
  5. python做数据分析需要oracle_精通 Oracle+Python,第 1 部分:查询最佳应践
  6. pku3670 Eating Together
  7. 别怀疑,孩子在家里也能学编程!
  8. 由“从按下回车到网页显示”粗谈网页优化
  9. 课程一(Neural Networks and Deep Learning),第三周(Shallow neural networks)—— 2、Practice Questions...
  10. 下半年值得关注的新机和科技趋势
  11. JAVA中的枚举使用总结
  12. PHP常用正则类(全)
  13. 手把手原生js简单轮播图
  14. 【springmvc】传值的几种方式postman接口测试
  15. 2022年6月25日PMP考试通关宝典-4
  16. 身份证前六位地址验证
  17. 京瓷打印机m5521cdn_京瓷M5521cdn打印机驱动(京瓷打印机驱动程序)V5.1.2107 最新版...
  18. 那些创造外汇神话的交易员们
  19. 凯德中国 × 阿里云 × 奇点云 | 沉淀数据资产,遇见数智未来
  20. android短信分享,android 短信分享

热门文章

  1. 正则表达式匹配所有script及其内容_VLOOKUP函数进阶用法:模糊一对多匹配之匹配带关键字的所有内容...
  2. proc除了能用于oracle开发_能不能用于mysql开发_Oracle数据库开发(二).Linux下配置使用ProC...
  3. vscode 默认初始化_VSCode设置初始化模板
  4. html如何用v-for遍历,v-for循环遍历
  5. 最小二乘法多元线性回归_回归系列(二)| 最小二乘法真有那么复杂吗?
  6. yii2.0框架中自定义接口,实现类的多继承
  7. 你知道面试必问的AOP吗(1),2021吊打面试官系列
  8. 别再说你不会!kafka延迟队列
  9. 【深度学习】深度神经网络后处理之全连接CRFs(DenseCRF)
  10. 解决Latex图片或者表格浮动