LevelDB介绍和内部机制

介绍

        LevelDB 是 Google 开源的高性能键值对嵌入式数据库,具有一系列设计上的优势,特别适合写多读少、对存储空间要求高效的场景。

核心优势

1. 高写入性能(顺序写磁盘)

  • 基于 LSM-Tree(Log Structured Merge Tree)

  • 所有写操作首先写入内存(memTable)+ WAL;

  • 后台异步 flush 到磁盘,避免频繁随机写;

  • 大量写入性能远高于 B+Tree 类数据库(如 SQLite)。

2. 数据压缩与空间利用率高

  • 支持 Snappy 压缩

  • 自动 Compaction(压缩合并) 机制;

  • 清理删除或覆盖的旧版本,回收磁盘空间;

  • .sst 层级结构使数据有序紧凑。

3. 支持有序遍历与范围查询

  • 支持通过 Iterator 顺序遍历键值;

  • 可高效进行范围查询(Range Scan):

4. 轻量、嵌入式、依赖少

  • 无服务器(serverless),直接嵌入你的应用;

  • 单一 .a 静态库或 .so 动态库,无需依赖外部组件;

  • 跨平台支持良好(Linux、macOS、Windows)。

5. Crash-safe 崩溃恢复机制

  • 所有写入先写入 .log 文件(Write-Ahead Log);

  • 崩溃后可自动恢复到一致状态;

  • 无需额外事务机制即可保证写入安全性。

6. 支持快照(Snapshot)和原子批处理(WriteBatch)

  • Snapshot: 提供一致性读取视图;

  • WriteBatch: 批量写入操作可原子提交,提升性能并简化逻辑。

使用场景

场景类型是否适合说明
批量数据写入✅ 非常适合写优化结构(LSM-tree),顺序写性能极高
嵌入式/边缘设备存储✅ 非常适合轻量、无服务端,资源开销小
日志系统、缓存系统✅ 合适大量写入、偶尔查询
用户画像、指标记录✅ 合适小 key-value、高速写入
离线分析数据落地✅ 合适批量写入,偶尔按 key 扫描或查询
查询很少、但插入频繁的系统✅ 非常合适查询通过前置缓存减少压力

不太适合的场景

场景类型原因
高并发读场景(每秒几千次以上)读放大严重,需大量优化(如加 Bloom Filter、前置缓存)
大量随机读 + 大量随机写写放大 + 查询慢
多表 join、事务一致性需求强不支持 SQL 和事务
需要按字段查询、复杂查询不支持索引,只有键排序

数据结构

  • 内存表(MemTable):最新写入的数据,保存在内存中。

  • Immutable MemTable:旧内存表,尚未 flush。

  • SST 文件(磁盘):排序的 Key-Value 存储在多层磁盘文件中。

  • Block Cache(块缓存):LevelDB 会缓存 SST 文件中的数据块(默认 8MB)。

文件结构

  • 000123.log:正在写的 WAL
  • 000124.sst: L0 的第一个 SST 文件
  • 000125.sst: L0 的第二个 SST 文件(写入后产生)
  • 000130.sst: L1 的文件(Compaction 后生成)
  • MANIFEST-000001:元数据文件
  • CURRENT:指向当前 MANIFEST

memTable

        它是数据库打开时创建的空内存结构,用于接收写入。

生命周期如下:

  1. DB.open(),创建一个空的 memTable

  2. 写入数据时(put()/delete()),首先写 WAL(Write-Ahead Log),然后写入 memTable

  3. memTable 的大小超过阈值(writeBufferSize)时,会:

    • 将当前 memTable 移入 immutable memTable

    • 异步触发 flush 操作,将其写入 .sst 文件;

    • 创建新的 memTable 接收写入。

触发时机会怎样?
memTable flush提高 L0 score
Compaction 完成降低某层 score,增加下一层
写入压力上升多文件生成,score 提高
删除数据未及时 compactscore 居高不下,空间占用大

compactionScore 是 LevelDB 内部的一个关键指标,它决定是否需要触发 Compaction(压缩),以及优先压缩哪个 Level。

  • 每个 Level(L0 ~ L6)都有一个 compactionScore

  • 值越大,代表该 Level 越“拥堵”,越需要被压缩;

  • compactionScore ≥ 1.0,LevelDB 会调度一次 Compaction;

  • 通常由 VersionSet::Finalize() 计算。

JAVA客户端配置

参数默认值说明
createIfMissingfalse如果数据库不存在,是否自动创建(通常你会手动设为 true
errorIfExistsfalse如果数据库已存在,是否抛出异常
paranoidChecksfalse是否进行一致性检查
verifyChecksumsfalse读取时是否校验数据块的校验和
cacheSize8 * 1024 * 1024(8MB)内存缓存大小
blockSize4 * 1024(4KB)每个 block 的大小
writeBufferSize4 * 1024 * 1024(4MB)写缓冲区大小
maxOpenFiles1000打开的文件数上限(仅 native JNI 实现中有效)
compressionTypeSnappy是否启用 Snappy 压缩

使用逻辑

写数据流程

  1. 写入 WAL(Write-Ahead Log)

    1. 写入先追加到 .log 文件(顺序写);

    2. 保证宕机后数据可恢复;

    3. 默认采用 同步写(Sync=true)才能确保持久化;

    4. .log 文件位于 Level 0

  2. 写入 memTable(跳表)

    1. 同步写入内存结构 memTable

    2. 快速写入(无锁 skiplist),数据可被读取;

    3. 内存中结构,不会持久化;

    4. 达到 writeBufferSize 限制(默认 4MB)后变为 immutable memTable,进入 flush。

  3. 触发 MemTable Flush,生成 SST 文件

    1. immutable memTable 转为 SST 文件;

    2. 写入磁盘(SST 为排序存储);

    3. 这些文件是查询的主要来源(也是 compaction 的输入);

    4. 会和已有 Level 0 文件产生重叠。

  4. 进行 Compaction(压缩)

    1. 定期触发(或写压力大时自动触发);

    2. 将多个 SST 文件合并、去重、合并覆盖;

    3. 数据从 L0 -> L1 -> L2 逐层下推;

    4. 保证后期查询高效,数据唯一性提升。

举例

执行 db.put("user123", "value1"),可能流程如下:

  1. 日志:写入 .log 文件中(WAL);

  2. 内存:写入到 memTable

  3. 若 memTable 满:

    • 转为 immutable;

    • 后台线程 flush 成一个新的 000123.sst

  4. 触发 compaction,将多个 sst 合并入更低 level;

  5. .log 文件在 flush 成功后被删除。

读取方式

  1. 先查 memTable(内存表)

    1. memTable 是当前活跃写入的跳表结构;

    2. 有序、支持二分查找;

    3. 如果找到了 key,直接返回对应的 value。

  2. 再查 immutable memTable(只读内存表)

    1. memTable flush 到磁盘前,会被转为 immutable;

    2. 查询会优先在这查找;

    3. 如果 key 存在,会返回。

  3. 然后查各层 .sst 文件(从 Level 0 开始)

    1. Level 0:
      1. 文件之间的 key 区间可能重叠;

      2. 必须逐个文件遍历查找;

      3. 优先查最新的文件(文件编号大 → 数据新);

    2.  Level 1~N(通常到 Level 6):
      1. 每层中的文件 key 区间互不重叠;

      2. 可以通过 key 二分定位到最多一个文件

      3. 只需要在该文件中查找一次;

  4. 使用 Bloom Filter 加速排除(配置生效)

    1. 每个 .sst 文件都可带一个 Bloom Filter;

    2. 在读文件前先看 Bloom Filter 是否可能包含该 key;

      1. 否 → 立即跳过;

      2. 是 → 真正读取磁盘文件;

    3. 可大幅降低磁盘 IO 次数,特别是 key 不存在时。

  5. 读取 Block → 解压缩 → 查找 KV

    1. .sst 文件是由多个 Block 组成的;

    2. 使用索引块定位 block;

    3. 如果有 Snappy 压缩,先解压再查找;

    4. 查到 key 返回 value,否则继续查下一个层级。

举例

执行 db.get("user123"),可能流程如下:

  1. 不在 memTable;

  2. immutable memTable 也没有;

  3. 查 L0 中的 3 个文件,(Bloom Filter 排除 2 个),只查 1 个;

  4. 没找到,再查 L1;

  5. 在 L1 的某个 .sst 文件中命中

  6. 去除文件中的block

  7. 解压 block → 返回 value。

重启恢复步骤

  1. 读取 .log 文件;

  2. 重建 memTable;

  3. 保证数据一致性;

  4. 再继续写入。

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

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

相关文章

数据库-数据查询-Like

引言 <模糊沟通> 父亲(45岁,对外谦和,对内急躁,东北口音) 儿子(18岁,逻辑思维强,喜用生活化比喻) 母亲(43岁,家庭矛盾调…

SD-WAN优化云应用与多云架构访问的关键策略

1. SD-WAN如何优化企业对公有云和SaaS应用的访问? 1.1 智能流量优化 SD-WAN通过应用识别技术,可以根据不同的业务应用流量需求,动态分配网络资源。例如,SD-WAN能够优先为钉钉、企业微信、金山文档等关键SaaS应用分配低延迟、高带…

JVM——对象模型:JVM对象的内部机制和存在方式是怎样的?

引入 在Java的编程宇宙中,“Everything is object”是最核心的哲学纲领。当我们写下new Book()这样简单的代码时,JVM正在幕后构建一个复杂而精妙的“数据实体”——对象。这个看似普通的对象,实则是JVM内存管理、类型系统和多态机制的基石。…

专题:2025年跨境B2B采购买家行为分析及采购渠道研究报告|附160+份报告PDF汇总下载

原文链接:https://tecdat.cn/?p42612 在商业决策的复杂版图中,数据是穿透迷雾的精准坐标。本报告汇总解读聚焦2024年跨境B2B行业核心动态,以详实数据为锚,串联商品出口、品牌网站运营、独立站流量生态三大关键领域。我们深入挖掘…

使用spring-ai-alibaba接入大模型

spring-ai-alibaba 是Spring AI生态里与阿里巴巴相关的组件,借助它能够实现接入各类大模型。以下为你详细介绍如何使用 spring-ai-alibaba 接入不同大模型: 接入open ai 项目环境准备 首先要创建一个Spring Boot项目,并且在 pom.xml 里添加…

字符串的向量处理技巧:KD树和TF-IDF向量

使用下面的技术,可以构建不用DL的搜索引擎。 向量搜索引擎使用KD-Tree KD-Tree 搭建以字符串向量为索引的树,以 O ( l o g n ) O(logn) O(logn) 的时间复杂度快速查找到最近的向量 代码来源:https://github.com/zhaozh10/ChatCAD/blob/ma…

Modbus TCP 转Canopen网关连接台达伺服驱动器的配置案例

本案例是使用欧姆龙PLC通过开疆智能ModbusTCP转Canopen网关连接台达A2伺服驱动器的配置案例。 配置过程: 首先打开PLC组态软件“Sysmac Studio”,新建项目并进行配置。 编写ModbusTCP的通讯程序。 设置连接的IP地址,端口号等参数。 设置Modb…

Vim Z 开头的视图滚动/折叠命令完整学习笔记

Vim Z 开头的视图滚动/折叠命令完整学习笔记 文章目录 Vim Z 开头的视图滚动/折叠命令完整学习笔记1. 核心概念2. 垂直滚动对齐命令2.1 基础对齐2.2 重画增强版 3. 横向滚动命令3.1 字符级滚动3.2 半屏滚动 4. 代码折叠命令4.1 基础折叠操作4.2 高级折叠操作4.3 全局折叠控制4.…

【Keepalived】Keepalived-2.3.4 已恢复对 CentOS 7 支持

之前在CentOS 7.9系统中对 Keepalived 2.3.2、2.3.3 版本进行编译和安装测试,都出现了编译报错,且官方文档中也给出了不再支持RHEL 7的申明,但是6月10日,Keeplived-2.3.4版本在CentOS 7.9系统中编译、安装成功。 对于此问题&#…

Java NIO 面试全解析:9大核心考点与深度剖析

文章目录 🚀 Java NIO 面试全解析:9大核心考点与深度剖析📌 一、基础概念:BIO/NIO/AIO 终极对比📌 二、Buffer核心机制:状态机设计精髓Buffer状态机原理 📌 三、零拷贝原理:高性能IO…

C++提高编—(模板,泛型,异常处理)

一 模板 1.1 模板概论 以下图为例子,提供了三个西装的证件照,谁都可以取拍照,可以是小孩,男女人,也可以是某些动物等等等。n那么我们这个模板也是这样,它可以是任何类型,基础类型,c…

Python图像处理基础(六)

Python图像处理基础(六) 文章目录 Python图像处理基础(六)3.4 双层图像3.5 具有更多色阶的位图数据3.6 基于调色板的图像3.6.1 超过 256 种颜色的图像3.7 处理透明度3.7.1 Alpha 通道3.7.2 透明调色板条目3.7.3 透明颜色3.8 隔行扫描和交替像素排序3.4 双层图像 某些类型的…

卷积神经网络(一)

第七章 卷积神经网络 从今天开始学习卷积神经网络的内容。 本章的主题是卷积神经网络(Convolutional Neural Network,CNN)。 CNN被用于图像识别、语音识别等各种场合,在图像识别的比赛中,基于 深度学习的方法几乎都以…

OpenCV 多边形绘制与填充

一、知识点 1、void polylines(InputOutputArray img, InputArrayOfArrays pts, bool isClosed, const Scalar & color, int thickness 1, int lineType LINE_8, int shift 0 ); (1)、在图像上绘制多边形曲线。 (2)、参数说明: img: 输入、输出参数&#xff0…

C#接口代码记录

using System;namespace InterfacesExample {// 定义接口public interface INBAPlayable{void KouLan();}public interface ISupermanable{void Fly();}// 基类public class Person{public void CHLSS(){Console.WriteLine("人类吃喝拉撒睡");}}// Student 类实现多个…

SpringDataJpa实体类中属性顺序与数据库中生成字段顺序不一致的问题

自己写的代码覆盖hibernate中的代码 翻了翻源码发现,很多地方都是使用LinkedHashMap或者是List来传输Entity里面的fields,于是感觉Hibernate应该是考虑到使用Entity里面定义的fields的顺序来实现建表语句里的表字段顺序的。   于是就一步步跟踪下去&…

软件架构期末复习

题型 填空题 20分,2分/空,10空 选择题 30分,2分/题,15题 简答题 30分,6分/题,5题(概念+分析) 案例分析题 20分,5个小题(综合) 分值:体系结构、设计模式各占50% 考试内容 体系结构 SA基础(SA03PPT):SA概念、SA与软件过程(阶段)的关系、SA核心概念模型(重要…

Oracle ADG 日常巡检指南

一、基础状态检查 数据库角色与模式 SELECT db_unique_name, open_mode, database_role, switchover_status FROM v$database;预期状态: 主库:OPEN_MODEREAD WRITE, DATABASE_ROLEPRIMARY备库:OPEN_MODEREAD ONLY WITH APPLY, DATABASE_ROLE…

【MV】key_moments 与 continuous_timeline的编排权衡

一、编排顺序: key_moments → continuous_timeline* 建议使用顺序:key_moments → continuous_timeline 📊 两者关系 key_moments:从continuous_timeline中精选出来的重点(约11个关键时间点)continuous_timeline:完整的时间轴(37个片段,覆盖每句歌词)🎭 实际编…

Tomcat线程模型

目录 1 Linux I/O模型 2 Linux I/O模型分类 3 Tomcat支持的I/O模型 4 Tomcat I/O模型选型 5 Tomcat NIO实现 6 Tomcat异步IO实现 1 Linux I/O模型 I/O:在计算机内存和外部设备之间拷贝数据的过程程序通过cpu向外部设备发出读指令,数据从外部设置拷贝至内…