一、leveldb简介
Leveldb是一个Google实现的非常高效的kv开源数据库,版本1.2能够支持billion级别的数据量了。 在这个数量级别下还有着非常高的性能,主要归功于它的良好的设计,实现原理是依据LSM-Tree(Log Structed-Merge Tree)算法。其在区块链底层存储也有很好的应用,以太坊链和波场链等比较熟知的公链底层都是采用LevelDB数据库存储。LevelDB 是单进程的服务,性能非常之高,在一台4核Q6600的CPU机器上,每秒钟写数据超过40w,而随机读的性能每秒钟超过10w。

二、leveldb设计思路
做过存储的同学都很清楚,对于普通机械磁盘,由于写操作需要磁盘旋转和磁道寻址,顺序写的性能要比随机写的性能好很多。比如对于15000转的SAS盘,4K写IO,顺序写在200MB/s左右,而随机写性能可能只有1MB/s左右,LevelDB的设计正是利用了磁盘的这个特性。

LevelDB是依据LSM-Tree(Log Structed-Merge Tree)的原理实现的,LSM-Tree写性能极高,其原理简单地来说就是将磁盘的随机写转化为顺序写,从而大大提高了写速度。

LSM tree (log-structured merge-tree) 是一种对写操作非常友好的存储方案。LSM tree 是许多 KV型或日志型数据库所依赖的核心实现,例如BigTable、HBase、Cassandra、LevelDB、SQLite、RocksDB 等,甚至在mangodb3.0中也带了一个可选的LSM引擎(由Wired Tiger 实现的)。

三、LSM-Tree算法原理
LSM-tree 是专门为KV存储系统设计的,Key-Value类型的存储系统最主要的两个功能,put(key,value):写入一个Key-Value ; get(key):给定一个 key 查找 value。
从名字看,由两部分组成“Log Structed”和“Merge Tree”。“Log Structed”是日志结构的意思,而我们常说的日志就是软件系统输出的执行信息,其特点就是不断追加的写入日志文件中,不需要更改,只需要在后边追加就好了。很多数据库在写操作前的日志也是追加型的,因此说到日志结构,基本就是指“追加,Append-Only”。而“Merge Tree”,就是“合并树”的意思,就是把多个树合成一个大树。所以LSM-Tree就是数据以Append-Only方式写入文件,成为一颗小树,然后通过合并形成更大的树。

LSM tree是基于如下背景事实:简单来说,问题的本质还是磁盘随机操作慢,顺序读写快的问题。磁盘或内存的连续读写性能远高于随机读写性能,有时候这种差距可以达到三个数量级之高。这种现象不仅对传统的机械硬盘成立,对SSD 硬盘也同样成立。

LSM-Tree被设计成通过避免随机操作,充分发挥了连续读写的性能优势,采用Append-Only的日志追加的方式进行写操作,通过扬长避短达到了比传统的B+树更好的写性能,不失为一个好方法、好思路。打破了过去传统的思路“更新某个数据必须要同时覆盖旧的数据”的束缚(这带来了无数问题),开启了“更新某个数据不需要覆盖旧的数据”的完全不同的设计理念。

”扬长“付出的代价就是牺牲部分读性能、写放大(B-Tree/B+Tree 同样有写放大的问题)。而”避短“则进行了大量的读优化,使用了空间换时间的思想。

三、leveldb整体架构

LevelDB由以下几个重要的组件构成:

(1)MemTable:这是常驻内存的C0树,写操作数据的落脚点。写操作并不是直接将数据写入磁盘文件,而是写入内存的MemTable后即表示写成功,然后返回。MemTable就是一个在内存中进行数据组织和维护的数据结构,其本质是一个跳表SkipList,而之所以选用跳表这种数据结构,是由于其应用场景决定的。跳表SkipList这种数据结构的设计来源于数组的二分查找算法,把指针通过设计成数组的方式实现了数组二分查找的高效,使用了用空间换时间的思想。跳表SkipList在查找效率上可比拟二叉查找树,绝大多数情况下时间复杂度为O(log n)。这契合了LevelDB快速查找Key的需要。在MemTable中,所有的数据按用户定义的排序方法排序后有序存储,当其数据容量达到阈值(默认是4MB)时,则将其转化了一个只读的MemTable,即:Immutable MemTable。同时创建一个新的MemTable供用户继续读写。

(2)Immutable MemTable:当MemTable数据容量达到阈值(默认是4MB)时,则将其转化了一个只读的MemTable,即:Immutable MemTable。这两者的结构定义完全一样,区别只是Immutable MemTable只读。后台的Compaction线程会将Immutable MemTable中的内容,创建一个SSTable文件,持久化到该磁盘文件中。

(3)log(journal)日志文件:持久化的存储系统为了防止机器掉电或系统宕机造成正在写入的数据丢失,在写操作时通常都会先写日志,将要写入的数据先保存下来,若发生机器掉电或系统宕机,机器恢复后,可以读该日志文件恢复待写入的数据。LevelDB也是如此,LevelDB在写入内存MemTable之前,先写入Log日志文件,再写内存MemTable。当发生以下异常情况时,均可以通过Log日志文件进行恢复。

1)写log时,进程异常
2)写log完成,写内存未完成
3)写操作完成(即:写log、写内存MemTable均完成),进程异常
4)Immutable MemTable持久化过程中进程异常
5)其他压缩异常

当出现1)中异常时,数据库重启读取log日志文件,发现log日志文件异常,则认为此次用户写入操作失败,这样保障了数据的一致性。当2)3)4)异常发生时,用户上次写入的数据、MemTable、Immutable MemTable中的内存数据必然会丢失,而数据库重启后要读取log日志文件,都可以重新恢复出用户上次写入的数据、MemTable、Immutable MemTable。这也意味着log日志文件保留了所有的写入数据(包括旧数据),随着频繁地写操作,log日志文件必然随之膨胀。已经持久化地数据SSTable文件,不应该再恢复,它只在数据库损坏情况下,修复数据库时用来恢复SSTable文件,此时,如果log日志文件太大,势必恢复起来非常耗时间。

此外,LevelDB的用户写操作的原子性同样通过日志来实现。

(4)SSTable文件:虽然LevelDB的写操作是写内存中的MemTable,但是写内存不可能无限的膨胀,一旦机器掉电或系统宕机,恢复起来必然时间很长,因此当内存中数据容量达到阈值(默认是4MB)时,则将其转化了一个只读的MemTable,即:Immutable MemTable,然后创建SSTable文件来保存内存中的数据。除了少数元数据信息,LevelDB中的数据都是通过SSTable存储的。何谓SSTable?就是Sorted String Table,有序的固化表文件,有序体现在Key是按序存储的,也体现在除了Level-0之外,其他Level中的SSTable文件之间也是Key有序的,即:Key不重叠。

为何会有这样特点的SSTable文件呢?本质还是为了查找方便,为了读性能!查找算法最好的就是二分查找算法,要想使用二分查找算法,就要保证每个SSTable文件中的Key是有序排列,但是在Level-0,由于直接由内存中的Immutable MemTable新创建的SSTable文件,而内存中的Immutable MemTable存储的Key数据是有重复的,有重叠的,这样查找起来就要查找多个SSTable文件,查找效率低下。因此,就需要有一个额外的线程定期地来整理这些SSTable文件,使之没有重叠,并且减少文件个数目,从而减少磁盘IO的次数,这样就可以方便的使用二分查找算法,这个额外的线程就是Compaction压缩线程。

注意,所有的SSTable文件本身是不可修改的,Compaction压缩线程会把多个SSTable文件归并后产生新的SStable文件,并删除旧的SSTable文件。由于Level-0是直接由内存Immutable MemTable中的数据转化而来,所以Level-0中的SSTable文件中的Key是存在重叠的,不同的SSTable文件也存在Key重叠的情况,因此Level-0会有很多的限制条件,1)Level-0中文件的个数达到4个时,会触发压缩Compaction;2)Level-0中文件的个数达到8个时,写入操作将会受到限制;3)Level-0中文件的个数达到12个时,写入操作将会被停止。

后期归并生成的SSTable文件在Level-i层,这就是LevelDB的名字的由来。而之所以叫leveled,而不是tiered,是因为第i+1层的数据量是i层的倍数。 这种设计哲学为LevelDB带来了许多优势,简化了很多设计。

(5)Manifest文件:LevelDB中有版本Version的概念,一个版本Version主要记录了每一层Level中所有文件的元数据。std::vector<FileMetaData*> files_[config::kNumLevels];,而一个文件的元数据主要信息包含:文件号、文件大小、最大的Key和最小的Key等。每次Compaction完成,LevelDB都会创建又给新的Version,newVersion=oldVersion+VersionEdit,其中VersionEdit是指在oldVersion基础上变化的内容(新增或减少的SSTable文件)。Manifest文件就是用来记录这些VersionEdit信息的。一个VersionEdit信息会被编码成一条Record记录,写入Manifest文件,每条记录包括:1)新增哪些SSTable文件;2)删除哪些SSTable文件;3)当前Compaction的指针下标;4)日志文件编号;5)操作SequenceNumber等信息。通过这些信息LevelDB在启动时便可以基于一个空的Version,不断地Apply这些记录,最终得到一个上次运行结束时的版本信息。

下图便是一个Manifest文件示意图:

(6)Current文件:这个文件中只有一个信息,就是记录当前的Manifest文件名。

因为每次LevelDB启动时,都会创建一个新的Manifest文件。因此数据目录可能会存在多个Manifest文件。Current则用来指出哪个Manifest文件才是我们关心的那个Manifest文件。

(7)Compaction压缩:LSM-Tree中有两种压缩策略Size-Tiered Compaction Strategy和Leveled Compaction Strategy。LevelDB采用的是Leveled Compaction Strategy。SSTable被划分到不同的Level中,Level-0层的SSTable文件中的Key是存在相互重叠的,且限制默认文件个数是4个。除Level-0层,Level-i(i>0)中的SSTable文件之间所包含的Key是不重叠的,全局有序,任意两级Level之间的SSTable文件容量呈指数级倍数。在Compaction过程中,首先对参与压缩的SSTable文件按key进行归并排序,然后将排序后结果写入到新的SSTable文件中,删除参与Comaction的旧SSTable文件。

以上是对LevelDB的总体介绍,谢谢。

技术交流请加微信:wxid_508b6ru2awt022

区块链之LevelDB相关推荐

  1. 区块链之智能合约详解

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 什么是智能合约? 智能合约又称智能合同,是由事件驱动的.具有状态的.获得多方承认的.运行在区块链之上的.且能够根据预设条 ...

  2. 【我的区块链之路】- Hyperledger fabric的简单入门(四)链码的编写及调试

    [我的区块链之路]- Hyperledger fabric的简单入门(四)链码的编写及调试       之前的文章中我们有讲过了fabric的一些核心的配置文件的选项说明,讲过fabric 的网络启动 ...

  3. BC之SC:区块链之智能合约——与传统合约的比较以及智能合约模型部署原理、运行原理相关配图

    BC之SC:区块链之智能合约--与传统合约的比较以及智能合约模型部署原理.运行原理相关配图 目录 SC与传统合约的比较 SC模型部署原理.运行原理 SC与传统合约的比较 1.传统合约VS智能合约  特 ...

  4. BC之CM:区块链之共识机制——深入浅出以及国内外当下主流区块链平台共识机制纵向、横向比较相关配图

    BC之CM:区块链之共识机制--深入浅出以及国内外当下主流区块链平台共识机制纵向.横向比较相关配图 目录 区块链共识机制的深入浅出 国内外当下主流区块链平台共识机制纵向.横向比较 区块链共识机制的深入 ...

  5. BlockChain:互联网与区块链之间的那些事(P2P下载、P-CDN、分布式计算、社交媒体、P2P借贷、众筹、区块链、自组织)

    BlockChain:互联网与区块链之间的那些事(P2P下载.P-CDN.分布式计算.社交媒体.P2P借贷.众筹.区块链.自组织) 目录 区块链与互联网之间的那些事 互联网传递信息 区块链传递价值 区 ...

  6. 区块链之智能合约入门

    区块链之智能合约入门 第一步 安装环境 首先这里写的合约是指solidity合约,使用Remix IDE.所以我们第一步就是安装Remix IDE.remix ide是开发以太坊智能合约的神器,支持网 ...

  7. BlockChain:区块链入门课程 -- 区块链之类型 、应用程序、技术挑战和潜力

    BlockChain:区块链 类型 .应用程序.面临挑战和潜力 区块链的类型 不同类型的区块链协议概述.我们将深入探讨共识方法,了解公共区块,财团区块和私有区块链之间的差异; 他们的用途和价值主张. ...

  8. 云图说丨不同区块链之间如何跨链交互?

    本文分享自华为云社区<[云图说]第237期 不同区块链之间如何跨链交互?>,作者:  阅识风云. 可信跨链服务是基于一系列制定的可信区块链标准跨链协议,保证跨链交易全栈可追溯.可扩展性及可 ...

  9. 【区块链之菜鸟入门】区块链发展史:从拜占庭将军问题到智慧契约

    在"[区块链之菜鸟入门]亲,你淘的区块链到了!"这篇文章中,我们了解到了区块链技术的出现其实是为了去除银行类等中心机构的信用背书.从原本信任足够信用度的单独个体(中心)到信任一堆个 ...

最新文章

  1. Python xlrd 读取xls文件
  2. 细思恐极,插上U盘就开始执行Python代码的程序
  3. Linux、Mac 命令行快捷键
  4. 利用MAVEN的profile 实现打包环境的切换
  5. python类定义中__init__()_转:python学习——类中为什么要定义__init__()方法
  6. 从0基础学Python:装饰器及练习(基础)
  7. script setup 实验性 vue 语法
  8. python 区块链_Python 模拟简单区块链
  9. 计算机无法安装蓝牙驱动,win7电脑蓝牙驱动怎么安装,教您怎么安装
  10. 测试 minpy gpu加速 numpy 矩阵相乘 matmul matrix multiplication
  11. Docker 镜像制作之DockerFile
  12. 几种比较和谐的文字背景颜色搭配
  13. 说说知名软件的伪装和防范(下)
  14. python中nums[:]和nums
  15. delphi每次mysql密码BDE_关于DELPHI中BDE连接不上ORACLE数据库的問題
  16. 【c++篇】c++常见容器中list的模拟实现
  17. 了解 C++ 之 typename
  18. 【写博客常用】x86,x64,arm都是什么
  19. FileHelpers Library
  20. 笔记:RTSP在线视频流资源地址

热门文章

  1. [Unity] Generic 模式的动画混合和移动方向发生错误的解决办法:使用 Humanoid 模式
  2. 氮杂环化合物改性磁性/多羟基化合物改性/β-二羰基接枝/三乙胺修饰聚苯乙烯微球的制备
  3. Is the server running on host “localhost“ (127.0.0.1) and accepting TCP/IP connections on port 5432?
  4. Ubuntu Desktop 设置中文界面
  5. springboot框架学习 - 自定义 starter
  6. matlab 随机数有效数字,MATLAB中生成随机数方法总结
  7. pbootcms仿站标签_pbootcms仿站工具下载
  8. SVG停车场地图与停车场导航
  9. 回归系数t检验公式_如何用分组回归检验调节作用?
  10. dell730 服务器硬盘,戴尔R730服务器磁盘阵列