鸿篇巨制 —— LevelDB 的整体架构

手把手教你如何写一个FLink Connecter(一) 如何自定义flink sql connector sink 阅读详情

本节信息量很大,我们要从整体上把握 LevelDB 这座大厦的结构。当我们熟悉了整体的结构,接下来就可以各个击破来细致了解它的各种微妙的细节了。

一个比喻

LevelDB 有点类似于建筑,分为地基和地面两部分,也就是磁盘和内存,而地基又好比地壳结构分了很多层级,不同层级的数据还会定期从上往下移动 —— 沉积作用。如果磁盘底层的冷数据被修改了,它又会再次进入内存,一段时间后又会被持久化刷回到磁盘文件的浅层,然后再慢慢往下移动到底层,周而复始就好比地球水循环。

640?wx_fmt=jpeg

内存结构

LevelDB 的内存中维护了 2 个跳跃列表,一个是只读的 rtable,一个是可修改的 wtable。跳跃列表在我的另一本书《Redis 深度历险》中有详细讲解,这里就不再细致重复说明。简单理解,跳跃列表就是一个 Key 有序的 Set 集合,排序规则由全局的「比较器」决定,默认是字典序。跳跃列表的查找和更新操作时间复杂度都是 Log(n)。

640?wx_fmt=png

如果跳跃列表只存 Key,那 Value 存哪里呢?答案是 Value 也存在跳跃列表的 Key 中。跳跃列表中存储的 Key 比较特殊,它是一个复合结构字符串,它同时包含了键值对的 Key 和 Value。

640?wx_fmt=png

其中 sequence 为全局自增序列号,LevelDB 遇到一个修改操作,全局序列号自动加一。LevelDB 中的 Key 存储了多个版本的 Value。LevelDB 使用序列号来标记键值对的版本,序列号越大,对应的键值对越新。

type 为数据类型,标记是 Put 还是 Delete 操作,只有两个取值,0 表示 Delete,1 表示 Put。

internal_key = key + sequence + type
Key = internal_key_size + internal_key + value_size + value

640?wx_fmt=png

待 Put 和 Delete 操作日志写到日志文件后,其键值对合并成「复合 Key」插入到 wtable 的指定位置中。

640?wx_fmt=png

待 wtable 的大小达到一个阈值,LevelDB 将它凝固成只读的 rtable,同时生成一个新的 wtable 继续接受写操作。rtable 将会被异步线程刷到磁盘中。Get 操作会优先查询 wtable,如果找不到就去 rtable 中去找,rtable 如果还找不到,再去磁盘文件里去找。

因为 wtable 要支持多线程读写,所以访问它是需要加锁控制。而 rtable 是只读的,它就不需要,但是它的存在时间很短,rtable 一旦生成,很快就会被异步线程序列化到磁盘上,然后就会被置空。但是异步线程序列化也需要耗费一定的时间,如果 wtable 增长过快,很快就被写满了,这时候 rtable 还没有完成序列化,而wtable 急需变身怎么办?这时写线程就会阻塞等待异步线程序列化完成,这是 LevelDB 的卡顿点之一,也是未来 RocksDB 的优化点。

图中还有个日志文件,记录了近期的写操作日志。如果 LevelDB 遇到突发停机事故,没有持久化的 wtable 和 rtable 数据就会丢失。这时就必须通过重放日志文件中的指令数据来恢复丢失的数据。注意到日志文件也是有两份的,它和内存的跳跃列表正好对应起来。当 wtable 要变身时,日志文件也会跟着变身。待 rtable 落盘成功之后,只读日志文件就可以被删除了。

磁盘结构

LevelDB 在磁盘上存储了很多 sst 文件,sst 表示 Sorted String Table,文件里所有的 Key 都会有序的。每个文件都会对应一个层级,每个层级都会有多个文件。底层的文件内容来源于上一层,最终它们都会来源于 0 层文件,而 0 层的文件又来源于内存里的 rtable 序列化。一个 rtable 会被序列化为一个完整的 0 层文件。这就是我们前面所说的「下沉作用」。

640?wx_fmt=png

从内存的 rtable 序列化成 0 层 sst 文件称之为「Minor Compaction」,从 n 层 sst 文件下沉到 n+1 层 sst 文件称之为「Major Compaction」。之所以这样区分是因为 Minor 速度很快耗费资源少,将 rtable 完整地序列化为一个 sst 文件就完事了。而 Major 会涉及到多个文件之间的合并操作,耗费资源多,速度慢。层级越深的文件总容量越大,在 LevelDB 源码里有一个层级容量公式,容量和层级呈指数级关系。而通常每个 sst 文件的大小都差不多,区别就成了每一层的文件数量不一样。

capacity = level > 0 && 10^(level+1) M

当内存出现读 miss 要去磁盘搜寻时,会首先从 0 层搜寻,如果搜不到再去更深层次搜寻。

如果是其它层级,搜寻速度会很快,因为可以根据 Key 的范围快速确定它可能会位于哪个文件中。但是对于 0 层,因为文件 Key 范围会重叠,所以它可能存在于多个文件中,那就需要对这多个文件进行搜寻。正因如此,LevelDB 限制了 0 层文件的数量,如果数量超出了默认的 4 个,就需要「下沉」到 1 层,这个「下沉」操作就是 Major Compaction。

所有文件的 Key 取值范围、层级和其它元信息会存储在数据库目录里面的 MANIFEST 文件中。数据库打开时,读取一下这个文件就知道了所有文件的层级和 Key 取值范围。

MANIFEST 文件也有版本号,它的版本号体现在文件名上如 MANIFEST-000361。每一次重新打开数据库,都会生成一个新的 MANIFEST 文件,具有不同的版本号,然后还需要将老的 MANIFEST 文件删除。

数据库目录中还有另外一个文件 CURRENT,它里面的内容很简单,就是当前 MANIFEST 的文件名。LevelDB 首先读取 CURRENT 文件才知道哪个 MANIFEST 文件是有效文件。在遇到断电时,会存在一个小概率中间状态,新旧 MANIFEST 文件共存于数据库目录中。

我们知道 LevelDB 的数据库目录不允许多进程同时访问,那它是如何防止其它进程意外对这个目录文件进行读写操作呢?仔细观察数据库目录,你还会发现一个名称为 LOCK 的文件,它就是控制多进程访问数据库的关键。当一个进程打开了数据库时,会在这个文件上加上互斥文件锁,进程结束时,锁就会自动释放。

还有最后一个不那么重要的操作日志文件 LOG,它记录了数据库的一系列关键性操作日志,例如每一次 Minor 和 Major Compaction 的相关信息。

640?wx_fmt=png

多路归并

Compaction 是比较耗费资源的操作,为了不影响线上的读写操作,LevelDB 将 Compaction 工作交给一个单一的异步线程来完成。如果工作量巨大,这个单一的异步线程也会有点吃不消。当异步线程吃不消的时候,线上内存的读写操作也会收到影响。因为只有 rtable 沉到磁盘里了,wtable 才可以变身。只有 wtable 变身了,才会有新的 wtable 被创建来容纳后续更多的键值对。总之就是一环套一环,环环相扣。

下面我们来研究一下 Compaction 。Minor Compaction 很好理解,就是内容空间有限,所以需要将 rtable 中的数据 dump 到磁盘 0 层文件。那为什么需要从 0 层文件 Compact 下沉到 1 层文件呢?因为 0 层文件如果过多,就会影响查找效率。前面我们提到 0 层文件之间的 Key 范围会有重叠,所以单个 Key 可能存在于多个文件中,IO 读次数将会被文件的数量放大。通过 Major Compaction 可以减少 0 层文件的数量,提升读效率。那是不是只需要下沉到 1 层文件就可以了呢?那 LevelDB 究竟是什么原因需要这么多层级呢?

640?wx_fmt=png

假设 LevelDB 只有 2 层( 0 层和 1 层),那么时间一长,1 层肯定会累计大量的文件。当 0 层的文件需要下沉时,也就是 Major Compaction 要来了,假设只下沉一个 0 层文件,它不是简简单单地将文件元信息的层数从 0 改成 1 就可以了。它需要继续保持 1 层文件的有序性,每个文件中的 Key 取值范围要保持没有重叠。它不能直接将 0 层文件中的键值对分散插入或者追加到 1 层的所有文件中,因为 sst 文件是紧凑存储的,插入操作肯定涉及到磁盘块的移动。再说还有删除操作,它需要干掉 1 层文件中的某些已删除的键值对,避免它们持续占用空间。

那 LevelDB 究竟是怎么做的呢?它采用多路归并算法,将相关的 0 层文件和 1 层 sst 文件作为输入,进行多路归并,生成多个新的 1 层 sst 文件,再将老的 sst 文件干掉,同时还会生成新的 MANIFEST 文件。对于每个 0 层文件,它会根据 Key 的取值范围搜寻 1 层文件中和它的范围有重叠部分的 sst 文件。如果 1 层文件数量过多,每次多路归并涉及到的文件数量太多,归并算法就会非常耗费资源。所以 LevelDB 同样也需要控制 1 层文件的数量,当 1 层容量满时,就会继续下沉到 2 层、3 层、4 层等。

非 0 层的多路归并资源消耗要少一些,因为单个文件的 Key 取值范围有限,能覆盖到下一层的文件数量有限,参与多路归并的输入文件就少了很多。但是这个逻辑有个漏洞,那就是上下层的文件数量有 10 倍的差距,按照平均范围间隔来算,意味着上层平均一个文件的取值范围会覆盖到下一层的 10 个文件。所以说非 0 层的多路归并资源消耗其实也不低,Major Compaction 就是一个比较消耗资源的操作。

下一节我们将深入磁盘文件内部结构,看看每一个 sstable 内部究竟长什么样

640?wx_fmt=png

DINOv3实战指南:如何利用零样本视觉模型革新工业质检 本文详细介绍了如何利用DINOv3零样本视觉模型革新工业质检流程。通过无需标注数据的自监督学习技术,DINOv3能快速部署高精度检测系统,显著降低成本和提升效率。文章涵盖模型选型、数据准备、实时检测优化及典型行业解决方案,为工业质检提供革命性AI实践指南。 阅读详情

相关推荐

国赛数学建模高教社杯历届优秀论文全集

包含了2004到2023年高教社的赛题及优秀论文。

BanDeng001的博客 3288

hive 修改表的存储格式_58招聘技术团队:WTable数据导入Hive三步曲

背景五月份招聘企业团队开发了企业字典项目。基于对业务场景的分析,存储选型中采用了WTable。项目开发完毕后核心表数据大约有1.8亿左右,为了满足产品、运营同学对企业字典数据的盘点、运营需求,需要建立多张字典Hive表,将字典数据导入Hive表用于统计分析。目前通过58dp平台可较为方便的对源自mysql或hdfs日志导入Hive表,可是WTable如何导入Hive还没有直接方式。几番打探后没有找...

weixin_39817176的博客 822

Label Studio + SAM2分割半自动标注与yolo11训练

Label Studio + SAM2分割半自动标注与yolo11训练

schFallingCloud 1408

vue+element 实现拖拽table单元格列

【代码】vue+element 实现拖拽table单元格列。

无简介!! 757

Mininet 2.2.1 图形可视化界面使用注意事项

前言 关于mininet的安装,网上教程不少,大致可以参考以下这篇文章: https://blog.youkuaiyun.com/linyixiao88/article/details/65651390 安装的时候,也可以不必根据上面这篇文章这么麻烦,直接sudo apt-get install mininet,即可。 Mininet可视化 Mininet 2.2.0以上版本内置了...

裕东方的博客 4192

WGCNA样本量不够怎么办?5种替代方案帮你解决小样本基因共表达分析难题

本文针对WGCNA样本量不足的问题,提供了5种科学替代方案,包括CEMiTool、参数调整、多组学数据整合、机器学习特征提取和公共数据利用。这些方法帮助研究者在小样本条件下仍能进行可靠的基因共表达分析,特别适用于罕见病和珍贵临床样本研究。

weixin_42554042的博客 306

推荐文章:使用level-party,解锁多进程访问leveldb的魔力!

推荐文章:使用level-party,解锁多进程访问leveldb的魔力! 在分布式系统和微服务架构盛行的今天,数据库的并发访问和跨进程通信成为了开发中的痛点。特别是对于基于leveldb的应用,单进程独占式的访问限制常常成为制约应用扩展性的瓶颈。然而,这一切都随着level-party的出现而改变。 项目介绍 level-party是Node.js社区中一个极具创新性的解决方案,它优雅地解决了多...

gitblog_00439的博客 727

钙钛矿太阳能电池稳定性测试:ISOS协议详解与标准化实践指南

在光伏器件研发中,稳定性测试是评估材料与器件长期可靠性的核心环节,其关键在于实现测试条件的标准化与数据的可比性。通过控制变量和模拟真实环境应力,标准化测试协议能够系统揭示材料衰减机理与器件失效模式,为技术迭代提供可靠依据。在钙钛矿太阳能电池领域,ISOS协议作为国际公认的测试框架,通过分级体系(如ISOS-L系列光照测试与ISOS-D系列暗态测试)和关键参数定义(如光源光谱匹配、MPP跟踪、结温控制),解决了不同实验室数据无法横向对比的痛点。该协议不仅规范了测试流程,还通过硬件系统搭建、自动化数据采集与归一

weixin_33600816的博客 323

levelDB引擎

主要受限于磁盘的寻道时间,优化磁盘数据访问的方法是尽量减少磁盘的IO次数。磁盘数据访问效率取决于磁盘IO次数,而磁盘IO次数又取决于数据在磁盘上的组织方式。磁盘数据存储大多采用B+树类型数据结构,这种数据结构针对磁盘数据的存储和访问进行了优化,减少访问数据时磁盘IO次数。

qq_18871751的博客 624

vLLM专题(七)-支持的模型列表

vLLM支持跨多种任务的生成式和池化模型。如果一个模型支持多个任务,您可以通过–task参数来设置任务。对于每个任务,我们列出了已在vLLM中实现的模型架构。每个架构旁边,我们列出了一些使用该架构的流行模型。

1261

使用C#和ASP.NET创建登录页面

在Visual Studio中,右键单击项目,选择"添加",然后选择"新建项"。在对话框中选择"Web",然后选择"Web 窗体"。在Visual Studio中,右键单击项目,选择"添加",然后选择"新建项"。在Visual Studio中,选择"新建项目",然后选择"ASP.NET Web应用程序"。在上面的代码中,我们创建了一个简单的用户界面,包含一个用户名输入框、一个密码输入框和一个登录按钮。在上面的代码中,我们创建了一个简单的用户界面,包含一个用户名输入框、一个密码输入框和一个登录按钮。

TzData的博客 763

leveldb NVM改造

NVM(Non-volatile Memory),非易失性内存,是一种新型的高速非易失性存储设备,具有百纳秒级的读写延迟和远高于SSD的读写吞吐能力,并且具有字节可寻址的特性,CPU能直接访问到NVM上的数据,不需要经过内存。

lihaihui1991的博客 522

IgH EtherCAT 从入门到精通:第 2 章 环境搭建与编译安装

环境搭建与编译安装指南 本章详细介绍了搭建IgH EtherCAT Master开发环境的完整流程。内容包括: 硬件要求:支持多种Intel和Realtek网卡的原生驱动,以及通用网卡的generic驱动选项 软件依赖:列出Linux系统下所需的工具链和开发包 源码获取:通过Git克隆官方仓库并切换稳定版本的方法 配置选项:详细解析bootstrap脚本和configure的核心参数,包括路径设置、功能开关和实时框架选项 编译流程:从生成构建系统到最终编译安装的完整步骤 通过本章指导,读者可以完成一个可运行

从事嵌入式linux android驱动开发,拥有全栈能力 481

TIDB突然断电pd文件损坏启动失败

记录一次TIDB数据库突然断电导致db文件损坏导致集群启动失败pd.log错误日志输出。

weixin_50870405的博客 788

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

LevelDb(二):LevelDb整体架构

1. LevelDb组成 2. Log文件 3.MemTable和Immutable Memtable 4.SSTable文件 5.Manifest文件 6.Current文件 7. Others 7.1 Version 7.2VersionEdit 7.3VersionSet 7.4 Builder 7.5TableCache 1. LevelDb组成 LevelDb作为存储系统,数据记录的存储介质包括内存以及磁盘文...

蓬莱道人的博客 6564

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

LevelDB 常见问题解决方案

LevelDB 常见问题解决方案 【免费下载链接】leveldb LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values...

gitblog_09401的博客 795

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

【uniapp】通用列表封装组件

uniapp列表封装

Songywaa的博客 2970

10-leveldb repair流程及优化方法

leveldb做为一个单机存储引擎,难免遇到数据损坏的情况:比如意外断电、磁盘坏块等。轻者文件损坏无法读取,严重者则导致数据库无法启动。这个时候就需要进行数据修复了。 leveldb提供的修复流程如下: (1) wal日志文件转化为sstable文件 (2) 扫描所有的sstable文件(3) 生成MANIFEST文件:由上述流程可知,leveldb修复后会将所有的文件添加到level 0,根据level 0层的规则,由于文件之间key有重叠,读取时会在每个文件都读取一次,速度是很慢的;同时,我们知道Lev

错位竞争,单点突破。 1578

leveldb深度剖析-初始化流程

本篇来介绍一下leveldb初始化流程,初始化流程中涉及了很多内容,例如:文件组织方式,存储内容序列化和反序列化等等。在了解这些内容后,是有助于日后分析存储流程和压缩流程的。 一、创建/Open数据库 leveldb属于轻量级kv数据库,可以很方便写一个hello程序并结合gdb单步调试,来辅助我们阅读源码,起到事半功倍的效果。 1.1、版本管理 leveldb采用分层思想对数据进行管理,...

程序员的世界 1400

探索高效数据库协作:Level-party 开源项目详解

探索高效数据库协作:Level-party 开源项目详解 在分布式系统和多进程应用中,数据库的共享与协作往往是一个棘手的问题。今天,我们向您推荐一款名为 Level-party 的开源库,它解决了这个问题,为使用 LevelDB 的开发者提供了一种优雅的方式来处理多个进程间的数据库共享。 项目介绍 Level-party 是一个针对 LevelDB 数据库的智能工具,允许在同一数据目录下多次打开数...

gitblog_00025的博客 394

leveldb

原文地址http://leveldb.googlecode.com/svn/trunk/doc/index.html 特征: 1. 高效的kv持久化存储系统,key为任意字节的数组,顺序读写的qps可达几百K; 2. 数据按key 有序存储, 支持自定义比较函数; 3. 支持数据压缩,默认为snappy 压缩; 4. 支持前向后向迭代器 打开一个数据库:       一个le

小辉的专栏 1529

LevelDB 入门 —— 全面了解 LevelDB 的功能特性

本节我们将全面了解一下 LevelDB 的各种特性。LevelDB 的开发语言是 C++,考虑到会使用 C++ 语言的同学不是很多,在本节我们将使用 Java 语言来描述 LevelDB 的特性。其它语言栈的同学也不必担心,因为不同语言操纵 LevelDB 的接口 API 都是一样的,使用起来大同小异。 打开和关闭 LevelDB 的数据存储在一个特定的目录中,里面有很多数据文件、日志文件等。使...

weixin_34221276的博客 1163

LevelDB初探之简单使用

LevelDB初探之简单使用 2014-07-28 17:16:18 分类: 大数据 一、简介         LevelDB是google开源的一个key-value存储引擎库,从版本1.2开始就能够支持billion级别的数据量了。LevelDB是单进程的服务,性能非常之高,在一台4个Q6600的CPU机器上,每秒钟写数据超过40w,而随机读的性能每秒钟超过1

boshuzhang的专栏 461

【数据库】Redis和RocksDB、levelDB的区别

区别 Redis 是一个服务,独立的进程,用户的程序需要与它建立连接才能向它发请求,读写数据。 RocksDB 和LevelDB 是一个库,嵌入在用户的程序中,用户程序直接调用接口读写数据。 Redis 是一个远程内存数据存储(类似于 memcached)。它是一个服务器。单个 Redis 实例非常高效,但完全不可扩展(就 CPU 而言)。 Redis 集群是可扩展的(就 CPU 而言)。Roc...

小鱼菜鸟的博客 1万+
上一篇: 文字与编码的奥秘(下)
下一篇: 阿里分布式事务框架 GTS 全解析
码洞
博客等级 码龄10年 41粉丝 137原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值