LevelDB源码阅读笔记(1、整体架构)

news2024/11/26 16:43:50

LevelDB源码阅读笔记(1、整体架构)

LeveDB源码笔记系列:

LevelDB源码阅读笔记(0、下载编译leveldb)

LevelDB源码阅读笔记(1、整体架构)

前言

对LevelDB源码的博客,我准备采用总-分的形式进行记录,我觉得先了解一下LevelDB整体流程,再往后讲解各个基础组件的话,读者会更容易理解这样设计的用意。

性能简介

数据参考自leveldb的README:https://github.com/google/leveldb。

写性能

分析如下:

  1. 顺序写:保证数据按key递增插入到数据库中。因为一个sst中的数据密集,key之间差距不会特别大,所以压缩的时候相邻两层参与压缩的sst不会很多,压缩的压力不会特别大。

  2. 每次写入执行sync同步操作:不测也能知道性能不会高到哪里去。

  3. 随机写入:程序随机生成key值,插到leveldb中,相对于顺序写,这样会导致一个sst中的数据稀疏,key之间间隔过大,压缩的时候参与压缩的sst可能会更多,所以压缩的压力就会相对大点。

  4. 修改或删除数据:结果和随机写入类似,插入和删除会导致一个sst文件的key变的稀疏,导致和随机写差不多的性能。

数据如下:

# 顺序写
fillseq      :       1.765 micros/op;   62.7 MB/s

# 每次写入执行sync同步操作
fillsync     :     268.409 micros/op;    0.4 MB/s (10000 ops)

# 随机写入
fillrandom   :       2.460 micros/op;   45.0 MB/s

# 修改或删除数据
overwrite    :       2.380 micros/op;   46.5 MB/s

读性能

分析如下:

  1. 随机读:具备不确定性,可能需要读n多个sst文件,如果sst文件不在cache中,又会涉及单个sst文件data index block的磁盘寻道和解压缩(可能需要解析n多个不在cache中的sst文件。)。所以性能上不去。

  2. 顺序读:level读数据是创建一个外部归并迭代器,顺序读从一定程度上减少了对一个sst文件的反复解析(因为cache有限,被缓存的sst会被lru算法置换出去),同时也减轻了data_block的反复解压和磁盘寻道的代价。

  3. 反向读:因为leveldb的sst文件data_block它的key是存在前缀压缩的,每个key相当于是一个增量key,想从一个key知道前一个key,必须从重启点重新解析,这个过程涉及到一个while循环,所以反向读性能会比顺序读要差点。

数据如下:

# 随机读
readrandom  : 16.677 micros/op;  (approximately 60,000 reads per second)

# 顺序读
readseq     :  0.476 micros/op;  232.3 MB/s

# 反向读
readreverse :  0.724 micros/op;  152.9 MB/s

根据leveldb的源码实现,考虑数据量很大,cache不命中的情况下,开销主要在每次读key至少都要进行的2次磁盘寻道(读data index block和data block),同时带来的data block的反复解压也是瓶颈所在,所以增大cache的大小一定程度上能改善leveldb的读性能。如下:

readrandom  : 9.775 micros/op;  (approximately 100,000 reads per second before compaction)
readrandom  : 5.215 micros/op;  (approximately 190,000 reads per second after compaction)

架构简介

图片引用自知乎(https://zhuanlan.zhihu.com/p/206608102)若有侵权,可联系我将其删除,LevelDB架构图如下:

整体架构

LevelDB内存中使用了跳表:mem_(内存跳表)、imm_(只读内存跳表)。

LevelDB在磁盘数据结构上:设计了SSTable只读磁盘数据结构。并且SST是按分层组织的。

使用两种形式的内存跳表:mem_和imm_,mem_相当于是前台的buff供用户读写数据,而imm_为写满了的mem_充当一种临时容器,这样做的好处是能让imm_和后台Compaction线程打交道(置换)。当后台Compaction线程繁忙时,不至于说写满了的mem_没地方放,从而需要阻塞去等待后台Compaction线程的压缩。imm_的角色本质上和Muduo异步日志的AsyncLogging::buffers_是一样的。当然LevelDB的前台缓存:mem_、imm_,后台Compaction线程的设计,是双缓冲技术的实践。

LevelDB的读流程

  1. 先读取内存中的跳表:mem_(内存跳表),找到返回,没找到继续。

  2. 再读内存中的只读跳表:imm_(只读内存跳表),找到返回,没找到继续。

  3. 按层查找sst文件。

    • 对于第一层sst文件,由于第一层sst文件之间是存在重叠的,所以会顺序查找第一层的每个和key有重叠的sst文件。(涉及多个sst文件)。

    • 对于其他层,由于leveldb在压缩的时候就保证了其sst之间是不存在重叠的,所以,其他层的查找就会采用二分的形式去定位可能包含key的sst文件,当然,这种情况下,其他层的key的查找最多涉及一个sst文件。(最多涉及一个sst文件)。

  4. 找到返回OK和对应的value,找不到返回NotFound。

从后面SST以及双层迭代器的源码分析我们就可以看到,因为sst结构设计的精妙,LevelDB对SST的查找也是使用了二分。这里就不过多赘述。

LevelDB的读流程图如下:

ReadProcess

LevelDB的写流程(删除,插入,修改

  1. 如果存在多个线程并发写,将请求写的所有线程放到一个队列里面,仅让位于对头的线程执行下面真正的写操作,其他线程阻塞在条件变量上。

  2. 执行MakeRoomForWrite,确保mem_有足够的空间写。如果第1层的sst文件数达到阈值config::kL0_SlowdownWritesTrigger(默认8个sst),就触发慢写(sleep1000微妙后再来尝试MakeRoomForWrite);如果第1层的sst文件达到阈值config::kL0_StopWritesTrigger(默认12个sst),就触发停止写(阻塞在条件变量上,等待Compaction线程的唤醒);如果mem_满了 && imm_为nullptr,就将mem_转换为imm_,并清空mem_;如果mem_满了 && imm_非nullptr,也即后台Compaction线程繁忙,来不及压缩imm_,就阻塞在条件变量上,等待后台Compaction线程的唤醒。

  3. 做一个BuildBatchGroup的操作:将其他线程请求写的kv对 合并。

  4. 将3合并的数据写到WAL日志中。

  5. 将3合并的数据统一写到mem_中。

  6. 唤醒其他阻塞的线程,并且从队列中移除。同时,必要的话,唤醒下一个队头执行写操作。

在LevelDB中,删除、插入、修改均是向mem_中插入一条包装过的key(InternalKey)。

InternalKey的组成:

InternalKey

  • UserKey:用户提供的key。

  • SequenceNumber:由全局逻辑计时器提供,保证key不重复。

  • ValueType:存在两个值:kTypeDeletion和kTypeValue。

删除:是插入一条ValueType为kTypeDeletion的InternalKey。插入和修改:都是插入一条带kTypeValue的InternalKey。

那么LevelDB是如何确定一个key最新状态是删除还是插入呢?如果对key进行了修改,又如何知道它的最新值能?删除也是插入key的话,怎么保证删除之前的key删除干净呢?

要解决上面的问题,SequenceNumber字段就起到了关键作用。LevelDB整体上会以UserKey升序,当UserKey相同时,会以SequenceNumber降序排列。因为SequenceNumber最大的靠前排,这样就保证了在查询的时候最先获取到一个key的最新状态(是否删除、没删除的话最近一次修改的Value是多少?)。而真正的删除会在压缩阶段进行。

引用陈硕的话,这其实是一种记流水账的思想(追加写),不管是删除、插入还是修改,都是在末尾记录一下,而不会去动以前的记录。这也是LevelDB精华所在。

LevelDB的压缩流程

压缩作为LSMTree的核心组件之一,在LevelDB中由后台专门的一个线程执行。本质上讲压缩就是剔除key的历史记录,只保留key最新的记录。压缩过程中同样重要的有:压缩时机?压缩哪一层的哪一个sst?对sst以什么策略进行分割?如何控制sst和祖父间的关系?为什么LevelDB设置成7层?sst文件大小为什么默认2M?每层的sst文件数量为什么默认是那么多?

这些问题LevelDB都有具体的策略和参数进行控制,目前作者的功力有限,有些地方还未能完全明白用意,所以此处仅简述一下大概的压缩流程。

压缩流程图如下:

CompactionProcess

具体流程如下述:

  1. 确定要压缩的sst文件,假设该sst文件在level层,收集level层和level + 1层和sst文件有重叠的所有sst文件。

  2. 将1中收集到的sst文件建立成一个多路归并迭代器。并将迭代器指向首个元素(最小的)。

  3. 遍历归并迭代器,迭代器的元素按UserKey升序 && UserKey相同的按SequenceNumber降序排列。对于同一个key,由SequenceNumber最大(最新)的ValueType决定该key的状态,然后直接忽略所有其他SequenceNumber过小(状态过时)的key。

    • 对于带TypeDeletion标签的key(假设Internal Key为kD),如果level + 2以及以外的层不可能也包含k,该key就会在本次压缩中直接删除。如果level + 2以及以外的层可能也包含k,kD会保留下来,写到sst文件中,在随后的压缩中再一起删除干净。

    • 对于带kTypeValue标签的key,保留SequenceNumber最大的那个即可,其余的忽略。

  4. 在遍历归并迭代器过程中,会按序建立sst文件,建立sst文件的过程中,还会按设定大小对sst文件进行一个切割,防止单个sst文件过大。单个sst文件与祖父层重叠大小太大也会被切割,重新建立一个新的sst文件。

  5. 将输出的sst文件放到level + 1层。

总结

理想情况下:

  • LevelDB的读操作:最多会涉及2次磁盘IO(读data index block和data block)。

  • LevelDB的写操作(插入、修改、删除):是直接插到内存,不涉及磁盘IO。但在随后的压缩的过程中,可能会涉及一些磁盘IO(在归并迭代器中遍历sst时涉及磁盘读,将压缩的数据输出到磁盘时涉及磁盘顺序写)。


本章完结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1606831.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HZNUCTF第五届校赛实践赛初赛 Web方向 WriteUp

ezssti 很简单的ssti 源码给了,调用Eval即可执行命令 package mainimport ("fmt""net/http""os/exec""strings""text/template" )type User struct {Id intName stringPasswd string }func (u User) Ev…

短视频去水印解析接口 可测试

短视频解析聚合接口80多个热们短视频平台。可测试 接口开发文档: 返回格式: JSON 请求方式: GET/POST 示例请求地址:https://www.dspqsy.vip/spapi?keykey&url短视频url 请求参数说明: 字段必填类型说明url是…

Golang | Leetcode Golang题解之第36题有效的数独

题目: 题解: func isValidSudoku(board [][]byte) bool {var rows, columns [9][9]intvar subboxes [3][3][9]intfor i, row : range board {for j, c : range row {if c . {continue}index : c - 1rows[i][index]columns[j][index]subboxes[i/3][j/3]…

2021年全国大学生电子设计竞赛D题——基于互联网的摄像测量系统(二)

09 电路设计 前面介绍了系统的硬件框图如下: 硬件基本分为三块,两个摄像节点,一个终端节点。 1. 摄像节点硬件 摄像节点由一个DE10-Nano开发板和一个D8M摄像头实现,DE10-Nano开发板的HDMI接口外接HDMI显示器来显示拍摄到的视频。…

Linux下SPI设备驱动实验:验证读写SPI设备中数据的函数功能

一. 简介 前面文章实现了 SPI设备驱动框架,并在此基础上添加了字符设备驱动框架,实现了读 / 写SPI设备中数据的函数,文章如下: Linux下SPI设备驱动实验:向SPI驱动框架中加入字符设备驱动框架代码-CSDN博客 Linux下…

基于springboot实现工程教育认证的计算机课程管理平台项目【项目源码+论文说明】

基于springboot实现计算机课程管理平台系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了基于工程教育认证的计算机课程管理平台的开发全过程。通过分析基于工程教育认证的计算机课程管理平台管理的不足…

opencv | 编译缺失ippicv相关文件解决方案

1.执行cmake后,查看控制台输出信息 ~/VM_data/opencv-4.9.0$ cd buile_temp ~/VM_data/opencv-4.9.0/buile_temp$ cmake ..2.去浏览器打开链接,下载对应的压缩包,解压到 路径:/3rdparty/ippicv/

【Canvas技法】四条C形色带填满一个圆/环形

【关键点】 通过三角函数计算控制点的位置。 【成果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>四条C形色带填满一个…

2024华中杯C题平面曲线重建思路

华中杯数学建模思路 光纤传感技术是伴随着光纤及光通信技术发展起来的一种新型传感器技 术。它是以光波为传感信号、光纤为传输载体来感知外界环境中的信号&#xff0c;其基本原理是当外界环境参数发生变化时&#xff0c;会引起光纤传感器中光波参量&#xff08;如波长、相位、…

IDEA使用SCALA

一、在IDEA中下载插件 在设置->插件中找到scala&#xff0c;并下载。 下载完成后重启idea 二、在idea中创建spark的RDD操作项目 新建项目选中Scala。 创建完成后为项目添加java包&#xff0c;这个添加的是spark安装包中jars目录下的所有jar包 然后编写RDD操作 import or…

24年蓝桥杯java-b组

24年蓝桥杯javaB组 蓝桥杯在昨天考完了&#xff0c;结果很不乐观&#xff0c;哎&#xff0c;还是太笨了&#xff0c;脑子确实转的慢&#xff1b;&#x1f625; 本篇博客中解题思路和代码并不一定完全正确&#xff0c;是我和同学们讨论的解答方法&#xff0c;但并未使用官方题…

Sharding-JDBC笔记1

Sharding-JDBC笔记1 1.分库分表1.1 垂直分库1.2 垂直分表1.3 水平分库1.4 水平分表 2.存在问题2.1 事务一致性2.2 跨节点关联查询2.3 跨节点分页、排序函数2.4 主键避重2.5 公共表 1.分库分表 分库分表就是为了解决由于数据量过大而导致数据库性能降低的问题&#xff0c;将原来…

亚马逊云挂机项目,单机600+,详细拆解

一、什么是亚马逊云挂机项目&#xff1f; 此项目有很多种叫法&#xff0c;也有人叫它亚马逊店铺挂机浏览项目。 二、赚钱原理&#xff1f; 新入驻的亚马逊商家往往是没有流量和曝光的&#xff0c;为了让店铺的商品更多的被人看到&#xff0c;花钱在平台直接买流量又不划算&a…

android远程更新下载apk

最近业务有涉及到&#xff0c;奈何是个app代码小白&#xff0c;遂记录一下 一&#xff1a;AndroidManifest.xml文件配置 application标签里面加上 android:networkSecurityConfig"xml/network_config" <!-- app下载更新配置--> <uses-permission andr…

国内主流的盗版软件检测工具有哪些?盗版软件检测工具推荐

在当前数字化时代&#xff0c;企业面临着越来越多的挑战&#xff0c;其中之一就是如何防止员工私自安装使用盗版软件。盗版软件不仅侵犯了知识产权&#xff0c;还可能给企业带来诸多风险如安全隐患、法律纠纷和财务损失。因此&#xff0c;企业需要采取一系列措施来防范员工私自…

Qt实现XYModem协议(六)

1 概述 XMODEM协议是一种使用拨号调制解调器的个人计算机通信中广泛使用的异步文件运输协议。这种协议以128字节块的形式传输数据&#xff0c;并且每个块都使用一个校验和过程来进行错误检测。使用循环冗余校验的与XMODEM相应的一种协议称为XMODEM-CRC。还有一种是XMODEM-1K&am…

分布式系统的监控基础架构Dapper

文章目录 基本设计目标监控系统设计基本要求三个基本设计目标 Dapper监控系统简介三个基本概念区间Helper.Call的详细信息监控信息的汇总监控数据汇总单独进行的原因 关键性技术轻量级核心功能库二次抽样技术 常用Dapper工具Dapper存储API 基本设计目标 监控系统设计基本要求 …

力扣(leetcode) 42. 接雨水 (带你逐步思考)

力扣(leetcode) 42. 接雨水 &#xff08;带你逐步思考&#xff09; 链接&#xff1a;https://leetcode.cn/problems/trapping-rain-water/ 难度&#xff1a;hard 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多…

「GO基础」在Windows上配置VS Code GO语言开发环境

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

【数据结构(八)上】二叉树经典习题

❣博主主页: 33的博客❣ ▶文章专栏分类: Java从入门到精通◀ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你学更多数据结构的知识 目录 1.前言2.经典习题2.1相同的树2.2另一棵子树2.3翻转二叉树2.4平衡二叉树2.5对…