一文彻底搞懂leveldb架构(代码片段)

神技圈子 神技圈子     2022-12-04     339

关键词:

leveldb

leveldb是一个写性能十分优秀的存储引擎,是典型的LSM-tree的实现。LSM的核心思想是为了换取最大的写性能而放弃掉部分读性能。那么,为什么leveldb写性能高?简单来说它就是尽量减少随机写的次数。leveldb首先将数据更新到内存中。当内存中的数据量达到一定阈值,将这部分数据再真正刷新到磁盘文件中。一般来说,顺序写60MB/s,随机写45MB/s.

整体架构


leveldb主要由以下几个重要的部件构成:
1.memtable
2.immutable memtable
3.sstable
4.manifest
5.current
6.log

memtable

刚才提到leveldb的一次写入操作并不是直接将数据写入到磁盘文件,而是采用先将数据写入内存的方式。所以,memtable就是一个内存中进行数据组织与维护的结构。在memtable中,数据按用户定义的方法排序之后按序存储。等到其存储内容到达阈值时(4MB)时,便将其转换成一个不可修改的memtable,与此同时创建一个新的memtable来供用户进行读写操作。memtable底层采用跳表,它的大多数操作都是O(logn)。

immutable memtable

当memtable的容量达到阈值时,便会转换成一个不可修改的memtable即immutable memtable。它同memtable的结构定义一样。两者的区别只是immutable memtable是只读的。immutable memtable被创建时,leveldb的后台压缩进程便会利用其中的内容创建一个sstable,然后持久化到磁盘中。

sstable

leveldb虽然采用了先写内存的方式来提高写效率。但是内存中的数据不可能是无线增长,并且日志中记录的写入操作过多会造成异常发生,而且恢复时间过长。因此内存中的数据达到一定容量就得将数据持久化到磁盘中。除了某些元数据文件,leveldb的数据主要都是通过sstable来存储的。
虽然在内存中,所有的数据都是按序排列的,但是当多个memtable数据持久化到磁盘后,其对应的sstable之间是存在交集的,这样造成在读操作时得对所有的sstable文件进行遍历,严重影响了读效率。所以,leveldb会定期整合这些文件,也叫做compaction。随着compaction的进行,sstable文件在逻辑上被分成若干层。通过内存数据直接dump出来的是level 0 层文件,后期整合出来的level i层文件。sstable本身是不可修改的。

manifest

在leveldb中有个版本的概念。一个版本记录了每一层所有文件的元数据。元数据包括如下几点:

  • 文件大小
  • 最大key值
  • 自小key值
    版本信息十分关键,除了在查找数据时利用两个key值来加快查找,还在其中为了一些compaction的统计值来控制compaction的进行。
    可以看到文件的元数据主要包含最小和最小key
// tFile holds basic information about a table.
type tFile struct 
    fd         storage.FileDesc
    seekLeft   int32
    size       int64
    imin, imax internalKey

版本则维护了每一层所有文件的元数据信息。入下代码所示:

type version struct 
    s *session // session - version

    levels []tFiles // file meta

    // Level that should be compacted next and its compaction score.
    // Score < 1 means compaction is not strictly needed. These fields
    // are initialized by computeCompaction()
    cLevel int // next level
    cScore float64 // current score

    cSeek unsafe.Pointer

    closing  bool
    ref      int
    released bool

当每次compaction完成时,leveldb都会创建一个新的version。compaction完成简单来说就是sstable的新增或者减少。而version创建的规则是:
versionNew = versionOld + versionEdit
这里的versionEdit指的是在旧版本基础上变化的内容。一般指sstable的增加或者删除。
manifest文件就是用来记录这些versionEdit信息的。一个versionEdit数据会编码成一条记录写入到manifest文件中。如下图所示

一共有两条versionEdit记录,每条记录包括

  1. 新增哪些sstable文件
  2. 日志文件编号
  3. 删除哪些sstable文件
  4. 当前compaction的下标
  5. 操作seqNumber等信息
    通过这些信息,leveldb变可以启动时创建一个空的version,不断apply这些记录。最终可以得到一个上次运行结束时的版本信息。

current

主要是记录当前manifest 的文件名。为什么需要这个?因为leveldb每次启动时,都会创建一个新的manifest文件,因此会出现很多个manifest文件。current则用来指出那个才是我们需要关心的文件。

log

leveldb写操作不是直接写入磁盘,而是先写入内存。加入写入到内存的数据还未来得及持久化,leveldb发生异常或者服务器宕机等会造成写入的数据丢失。因此,leveldb在写入内存之前会首先将所有的写操作写入日志文件中。每次写操作都是一次顺序写入,这样写效率高,整体写入性能好。此外,leveldb写操作的原子性也可以通过log来实现。
异常情况主要有以下几种:
1.写log完成,写内存未完成
2.写log期间进程异常
3.write操作完成后(写日志、写内存都完成)异常
4.immutable memtable持久化过程异常
5.其它压缩异常
第2种情况发生,数据库重启读取log时,发现异常日志数据则丢弃该条日志数据,即视作这次用户写入失败
第1、3、4情况发生时,都可以通过读取redo日志文件中记录的写入操作来完成数据库的恢复。

一文彻底搞懂leveldb架构(代码片段)

leveldbleveldb是一个写性能十分优秀的存储引擎,是典型的LSM-tree的实现。LSM的核心思想是为了换取最大的写性能而放弃掉部分读性能。那么,为什么leveldb写性能高?简单来说它就是尽量减少随机写的次数。leveldb首先将... 查看详情

一文彻底搞懂cookiesessiontoken到底是什么(代码片段)

点击上方关注“终端研发部”设为“星标”,和你一起掌握更多数据库知识责编:架构君 | 来源:不学无数的程序员链接:https://my.oschina.net/u/4030990/blog/3136476上一篇好文:MySQL数据库的优化,你知道有哪... 查看详情

图文详解一文全面彻底搞懂hbaseleveldbrocksdb等nosql背后的存储原理:lsm-tree日志结构合并树...(代码片段)

LSM树广泛用于数据存储,例如RocksDB、ApacheAsterixDB、Bigtable、HBase、LevelDB、ApacheAccumulo、SQLite4、Tarantool、WiredTiger、ApacheCassandra、InfluxDB和ScyllaDB等。在这篇文章中,我们将深入探讨LogStructuredMergeTree,又 查看详情

图文详解一文全面彻底搞懂hbaseleveldbrocksdb等nosql背后的存储原理:lsm-tree日志结构合并树...(代码片段)

LSM树广泛用于数据存储,例如RocksDB、ApacheAsterixDB、Bigtable、HBase、LevelDB、ApacheAccumulo、SQLite4、Tarantool、WiredTiger、ApacheCassandra、InfluxDB和ScyllaDB等。在这篇文章中,我们将深入探讨LogStructuredMergeTree,又 查看详情

一文彻底搞懂zookeeper(代码片段)

本文是基于CentOS7.9系统环境,进行Zookeeper的学习和使用1.Zookeeper简介1.1什么是ZookeeperZookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。本质上,就是文件系统+通知机制1.2Zookeeper工作机制Zookeepe... 查看详情

一文彻底搞懂zookeeper(代码片段)

本文是基于CentOS7.9系统环境,进行Zookeeper的学习和使用1.Zookeeper简介1.1什么是ZookeeperZookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。本质上,就是文件系统+通知机制1.2Zookeeper工作机制Zookeepe... 查看详情

一文彻底搞懂slam技术(代码片段)

什么是SLAM?SLAM (simultaneouslocalizationandmapping),也称为CML(ConcurrentMappingandLocalization),即时定位与地图构建,或并发建图与定位。问题可以描述为:将一个机器人放入未知环境中的未知位置,是否有办法让机器人一边逐步描... 查看详情

一文彻底搞懂slam技术(代码片段)

什么是SLAM?SLAM (simultaneouslocalizationandmapping),也称为CML(ConcurrentMappingandLocalization),即时定位与地图构建,或并发建图与定位。问题可以描述为:将一个机器人放入未知环境中的未知位置,是否有办法让机器人一边逐步描... 查看详情

一文彻底搞懂前端沙箱(代码片段)

什么是“沙箱”沙箱(Sandbox)[1]也称作:“沙箱/沙盒/沙盘”。沙箱是一种安全机制,为运行中的程序提供隔离环境。通常是作为一些来源不可信、具破坏力或无法判定程序意图的程序提供实验之用。沙箱能够安全的执行不受信... 查看详情

一文彻底搞懂docker中的namespace(代码片段)

什么是namespacenamespace是对全局系统资源的一种封装隔离。这样可以让不同namespace的进程拥有独立的全局系统资源。这样改变一个namespace的系统资源只会影响当前namespace中的进程,对其它namespace中的资源没有影响。以前Linux也... 查看详情

一文彻底搞懂kafka(代码片段)

Kafka的学习和使用本文是基于CentOS7.9系统环境,进行Kafka的学习和使用一、Kafka的简介1.1Kafka基本概念(1)什么是KafkaKafka是一个分布式的基于发布/订阅模式的消息队列,主要应用于大数据实时处理领域(2)消息队列点对点模式... 查看详情

一文彻底搞懂hbase(代码片段)

本文是基于CentOS7.9系统环境,进行HBase的学习和使用一、HBase的简介1.1HBase基本概念HBase是一种分布式、可扩展、支持海量数据存储的NoSQL数据库,可以解决HDFS随机写的问题1.2HBase数据模型逻辑上,HBase的数据模型同关系... 查看详情

一文彻底搞懂hbase(代码片段)

本文是基于CentOS7.9系统环境,进行HBase的学习和使用一、HBase的简介1.1HBase基本概念HBase是一种分布式、可扩展、支持海量数据存储的NoSQL数据库,可以解决HDFS随机写的问题1.2HBase数据模型逻辑上,HBase的数据模型同关系... 查看详情

字符串匹配,一文彻底搞懂(代码片段)

1暴力破解法在主串A中查找模式串B的出现位置,其中如果A的长度是n,B的长度是m,则n>m。当我们暴力匹配时,在主串A中匹配起始位置分别是0、1、2….n-m且长度为m的n-m+1个子串。暴力匹配对应代码是:#inc... 查看详情

mybatis缓存专题-一文彻底搞懂mybatis二级缓存(代码片段)

文章目录1.二级缓存概念2.二级缓存使用2.1.配置二级缓存2.2.分开关2.3.实体类实现序列化接口2.4.测试方法3.cache有一些可选的属性3.1.type3.2.eviction3.3.flushInterval3.4.size3.5readOnly3.6blocking4.MyBatis的缓存机制整体设计以及二级缓存的工作... 查看详情

一文让你彻底搞懂多线程(代码片段)

如果对什么是线程、什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内。用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其... 查看详情

一文带你彻底搞懂docker中的cgroup(代码片段)

前言进程在系统中使用CPU、内存、磁盘等计算资源或者存储资源还是比较随心所欲的,我们希望对进程资源利用进行限制,对进程资源的使用进行追踪。这就让cgroup的出现成为了可能,它用来统一将进程进行分组࿰... 查看详情

一文带你彻底搞懂springboot-rabbitmq(代码片段)

一、环境搭建采用maven多module模式,共计创建三个子modulecommon:通用实体信息rabbitmq-publisher:消息发布者,基于SpringBootrabbitmq-subscriber:消息订阅者,基于SpringBoot在消息发布者和订阅者两个项目中加入rabbitm... 查看详情