leveldb深度解析3:基础架构与数据库存储目录解析

一、基础架构梳理

leveldb基本数据流程如下:

1. 接收写入请求与预写日志(WAL)记录
  • 写入入口:用户调用 Put 或 Delete 接口提交键值对(或批量操作 WriteBatch)。
  • 原子性保证
    • 所有写入操作被封装为 WriteBatch,确保操作的原子性(要么全部成功,要么全部失败)。
  • 预写日志(WAL)
    • 操作首先以追加模式写入 LOG 文件(如 001289.log),格式为二进制记录。
    • 日志条目包含操作类型(Put/Delete)、键值数据、序列号(用于多版本控制)。
    • 持久化强制:通过 fsync(可配置)确保日志写入磁盘,防止系统崩溃导致数据丢失。
  • 日志文件切换
    • 当 MemTable 写满时,LOG 文件会关闭并生成新日志文件,旧日志保留至对应 MemTable 持久化后删除。
2. 写入内存表(MemTable)
  • MemTable 结构
    • 基于 跳表(SkipList) 实现,支持高效的有序插入和查询(O(log n) 复杂度)。
    • 所有键按字典序排列,支持范围查询。
  • 写入流程
    • 写入请求解析后,键值对按格式(操作类型、键、值、序列号)插入 MemTable。
    • 序列号递增:每个写入操作分配全局递增的序列号,用于实现快照隔离和旧版本数据清理。
  • 内存控制
    • MemTable 大小由 write_buffer_size 参数控制(默认 4MB),写满后触发 Immutable 转换。
3. MemTable 写满转换为 Immutable MemTable
  • 转换条件
    • 当 MemTable 大小达到阈值时,标记为 Immutable MemTable,停止接受新写入。
    • 新写入由新创建的 MemTable 处理,保证写入不阻塞。
  • 后台处理
    • Immutable MemTable 由后台线程异步持久化为 SSTable 文件(如 001290.ldb)。
    • 持久化前,数据按键排序并生成索引块、过滤块(Bloom Filter)等元信息。
4. 持久化到磁盘(SSTable 文件生成)
  • SSTable 结构
    • 文件按层级(Level 0 到 Level N)组织,每层文件数量与大小有限制。
    • Level 0 的 SSTable 由 Immutable MemTable 直接生成,允许键范围重叠;更高层级文件有序且无重叠。
  • 文件生成流程
    1. 排序与分块:Immutable MemTable 数据按键排序,分割为多个数据块(Block)。
    2. 元信息写入:生成数据块索引(记录每个块的起始键和偏移)、Bloom Filter(加速查询)、文件尾部校验和。
    3. 文件命名:全局递增编号(如 001290.ldb),确保唯一性。
    4. 原子提交:生成完成后,将文件加入元数据管理(通过 MANIFEST 更新)。
5. 元数据更新(MANIFEST 与 CURRENT)
  • MANIFEST 文件
    • 记录数据库的全局状态,包括所有 SSTable 文件、层级、键范围、压缩点等信息。
    • 每次新增或删除 SSTable 时,生成一条 VersionEdit 记录,追加到 MANIFEST。
  • CURRENT 文件
    • 指向当前生效的 MANIFEST 文件(如 MANIFEST-000052)。
    • 更新流程:生成新 MANIFEST 文件后,原子修改 CURRENT 文件内容为新文件名。
6. Compaction 过程
  • 触发条件
    • Level 0 文件数过多:默认阈值(4 个文件)触发 Compaction。
    • 层级大小限制:更高层级(如 Level 1+)总大小超过 max_bytes_for_level 时触发。
    • 查询优化:合并重叠键范围,减少读取时的文件访问数。
  • Compaction 类型
    • Minor Compaction:将 Immutable MemTable 转换为 Level 0 的 SSTable。
    • Major Compaction:跨层级合并 SSTable,删除过期数据,减少冗余。
  • 执行流程
    1. 选择文件:根据层级策略(如大小或文件数)选择待合并的 SSTable。
    2. 多路归并排序:合并多个文件的键,保留最新版本(高序列号)的数据。
    3. 生成新文件:输出到更高层级,旧文件标记为待删除。
    4. 元数据更新:更新 MANIFEST,删除旧文件(实际删除可能延迟到事务提交后)。
7. 异常处理与崩溃恢复
  • 日志重放
    • 重启时检查残留的 .log 文件(如 001289.log),重放未持久化到 SSTable 的操作。
    • 通过序列号过滤已过期的写入,确保数据一致性。
  • MANIFEST 恢复
    • 读取 CURRENT 文件找到最新 MANIFEST,加载所有 SSTable 文件和层级信息。
    • 校验文件完整性(通过校验和),丢弃损坏的文件。
  • 原子性保证
    • 文件删除和元数据更新通过 Rename 操作保证原子性,避免部分写入导致状态不一致。

二、存储目录解析

如下为一个使用leveldb进行存储的一个数据实际存储的结构目录,目录中一般包含.ldb、.log、CURRENT、LOG、MANIFEST、LOCK等文件。其具体作用如下:

1. LOG 文件(当前日志文件)

  • 作用:记录所有写操作的预写日志(Write-Ahead Log, WAL),用于崩溃恢复。
  • 机制
    • 写入数据时,首先追加到 LOG 文件,确保操作持久化。
    • 内存中的 MemTable 更新后,若系统崩溃,重启时通过重放 LOG 文件恢复未持久化的数据。
    • 当 MemTable 写满转为 Immutable MemTable 并刷入磁盘(生成 SSTable)后,对应的 LOG 文件会被删除。
  • 文件名:默认为 LOG,若存在未处理的旧日志,可能保留为 [0-9]+.log(如 001289.log),在恢复后被删除。

2. CURRENT 文件

  • 作用:指向当前生效的清单文件(MANIFEST)。
  • 机制
    • LevelDB 每次启动或元数据变更时,可能生成新的 MANIFEST 文件(如 MANIFEST-000052)。
    • CURRENT 文件仅保存最新 MANIFEST 的文件名,确保数据库知道加载哪个版本的元数据。
  • 示例:若 CURRENT 内容为 MANIFEST-000052,则使用该文件加载元数据。

3. MANIFEST 文件

  • 作用:记录数据库的元数据,包括 SSTable 文件列表、层级结构、键范围等信息。
  • 机制
    • 每次 Compaction 或 MemTable 刷盘时,元数据变更会追加到 MANIFEST。
    • 为避免文件过大,MANIFEST 会周期性合并(通过 Compaction),旧版本文件被删除。
    • 文件名格式为 MANIFEST-[0-9]+(如 MANIFEST-000052)。
  • 内容:包含版本编辑日志(VersionEdit),记录 SSTable 的增删和层级变动。

4. [0-9]+.log 文件(历史日志文件)

  • 作用:已持久化的旧日志文件,可能用于异常恢复。
  • 场景
    • 若 LevelDB 非正常关闭(如崩溃),可能存在未处理的 [0-9]+.log 文件。
    • 重启时,这些文件会被读取以恢复未刷入 SSTable 的数据,随后删除。
  • 示例001289.log 表示第 1289 号日志文件。

5. [0-9]+.ldb 文件(SSTable 文件)

  • 作用:存储实际数据的不可变文件,按层级组织,支持高效查询。
  • 机制
    • Immutable MemTable 刷盘时生成 .ldb 文件(如 001290.ldb),文件名全局递增。
    • 不同层级(Level 0 到 Level N)的 SSTable 文件通过 Compaction 合并,高层级文件范围更大且有序。
    • 文件名中的数字(如 001290)是唯一标识符,与生成顺序相关。
  • 结构:包含数据块、元信息块、索引块等,采用前缀压缩优化存储。

其他辅助文件

  • LOCK 文件:防止多进程同时访问同一数据库,通过文件锁实现。
  • 临时文件:操作中生成的临时文件(如 *.dbtmp),完成后删除或重命名。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值