1.译:一文科普 RocksDB 工作原理
2.FREE SOLO - 自己动手实现Raft - 15 - leveldb源码分析与调试-1
3.RocksDb 源码剖析 (1) | 如何混合 new 、mmap 设计高效内存分配器 arena ?
译:一文科普 RocksDB 工作原理
RocksDB 是一种可持久化的、内嵌型的键值存储(KV 存储)。它旨在存储大量 key 及其对应的 value,常被用于构建倒排索引、文档数据库、打字平台源码SQL 数据库、缓存系统和消息代理等复杂系统。RocksDB 在 年从 Google 的 LevelDB 分叉而来,针对 SSD 服务器进行了优化,并目前由 Meta 开发和维护。它以 C++ 编写,支持 C、C++ 及其他语言(如 Rust、Go、Java)的嵌入。如果你熟悉 SQLite,可以认为 RocksDB 是一种内嵌式数据库,需依赖应用层实现特定功能。电视转播源码
RocksDB 使用日志结构合并树(LSM-Tree)作为核心数据结构,这是一种基于多个有序层级的树形数据结构,可用于应对写密集型工作负载。LSM-Tree 的顶层是 MemTable,一个内存缓冲区,用于缓存最近的写入数据。较低层级的数据存储在磁盘上,以 L0 层为例,存储从内存移动到磁盘的数据,其他层级存储更旧的数据。当某一层级的数据量过大时,会通过合并操作转移到下一层。
为了保证数据持久化,RocksDB 将所有更新写入磁盘上的预写日志(WAL)。当应用重启时,可以通过回放 WAL 来恢复 MemTable 的原始状态。WAL 是一个只允许追加的文件,包含一组更改记录序列,app 仓库管理 源码每个记录包含键值对、操作类型和校验和。
当 MemTable 变满时,会触发刷盘(Flush)操作,将不可变的 MemTable 内容持久化到磁盘,并丢弃原始 MemTable,同时开始写入新的 WAL 和 MemTable。MemTable 默认基于跳表实现,以提高查询和插入效率。RocksDB 支持各种压缩算法,如 Zlib、BZ2、Snappy、LZ4 或 ZSTD,用于存储 SST 文件。
SST 文件是 MemTable 刷盘后生成的,包含了有序的键值对。每个 SST 文件由数据部分和索引块组成,asp网站源码 cms数据部分包含一系列有序的键值对,而索引块存储了数据块中最后一个键的偏移量,便于快速定位键值对。RocksDB 还支持布隆过滤器,用于快速检测某个键是否存在于 SST 文件中。
当数据库大小增加时,空间放大(存储数据所用实际空间与逻辑大小的比值)和读放大(用户执行一次逻辑读操作所需实际 IO 次数)的问题变得明显。为了解决这些问题,RocksDB 实现了 Compaction 机制,通过合并 SST 文件来降低空间和读放大,同时增加写放大。Leveled Compaction 是默认策略,它会在不同层级之间进行选择性合并,以优化空间使用。
RocksDB 的读路径相对简单,主要涉及从 MemTable 开始,下探到 L0 层,然后继续向更低层级查找,课程签到源码下载直到找到目标键或检查完整个树。合并(merge)操作允许用户在内存中对键值进行聚合操作,适用于需要对已有值进行少量更新的场景。然而,这种操作增加了读时的复杂性,因为读操作需要在多次调用 merge 函数后才能得到最终结果。
使用 RocksDB 需要针对特定工作负载进行配置调优,因为它提供了许多可配置项,但理解其内部原理并调整这些配置通常需要深入研究源代码。RocksDB 是构建高性能数据库模块的优秀选择,能够帮助开发者专注于上层业务逻辑实现,而无需从零开始设计底层存储系统。
FREE SOLO - 自己动手实现Raft - - leveldb源码分析与调试-1
leveldb 是由 Google 基础架构工程师 Jeff Dean 所设计的,是一种高效、可靠的键值对存储系统。它基于LSM(Log-Structured Merge)存储引擎,代码简洁精炼,非常适合深入学习与理解。leveldb 不仅可以作为一个简单的键值对引擎使用,而且内部组件如LRU Cache也具有独立的实用性,还能在此基础上封装出其他操作接口,例如vraft中的raftlog和metadata等。
通过理解leveldb,能够对后续学习如rocksdb等更高级的数据库引擎提供坚实基础。本文旨在从状态机的角度解析leveldb,帮助读者深入理解其内部工作原理。
在leveldb中,关键状态包括但不限于内存、磁盘状态以及LRU Cache状态。内存数据与磁盘数据的交互是leveldb的核心,用户的键值对数据通过日志写入到memtable,然后通过immutable memtable最终到达磁盘上的sorted table文件,这些文件按照级别(level)从0到6逐级存储。通过在关键时刻添加ToJson函数,可以记录这些状态的变化,便于分析。
LRU Cache在leveldb中的实现同样值得深入研究。它作为一种缓存机制,有助于优化数据访问效率。通过在LRU Cache中添加ToJson函数并打印状态,可以直观地观察其内部结构和状态的动态变化。
为了更好地理解leveldb,本文将重点分析关键数据结构,并通过观察不同动作导致的状态变化,来深入探究leveldb的内部机制。在后续文章中,将详细展示leveldb内部状态的转换过程,以帮助读者掌握其核心工作原理。
RocksDb 源码剖析 (1) | 如何混合 new 、mmap 设计高效内存分配器 arena ?
本文旨在深入剖析RocksDb源码,从内存分配器角度着手。RocksDb内包含MemoryAllocator和Allocator两大类内存分配器。MemoryAllocator作为基类,提供MemkindKmemAllocator和JemallocNodumpAllocator两个子类,分别集成memkind和jemalloc库的功能,实现内存分配与释放。
接着,重点解析Allocator类及其子类Arena的实现。基类Allocator提供两个关键接口:内存分配与对齐。Arena类采用block为单位进行内存分配,先分配一个block大小的内存,后续满足需求时,优先从block中划取,以减少内存浪费。一个block的大小由kBlockSize参数决定。分配策略中,Arena通过两个指针(aligned_alloc_ptr_和unaligned_alloc_ptr_)分别管理对齐与非对齐内存,提高内存利用效率。
分配内存时,Arena通过构造函数初始化成员变量,包括block大小、内存在栈上的分配与mmap机制的使用。构造函数内使用OptimizeBlockSize函数确保block大小合理,减少内存对齐浪费。Arena中的内存管理逻辑清晰,尤其在分配新block时,仅使用new操作,无需额外内存对齐处理。
分配内存流程中,AllocateNewBlock函数直接调用new分配内存,而AllocateFromHugePage和AllocateFallback函数则涉及mmap机制的使用与内存分配策略的统一。这些函数共同构成了Arena内存管理的核心逻辑,实现了灵活高效地内存分配。
此外,Arena还提供AllocateAligned函数,针对特定对齐需求分配内存。这一函数在使用mmap分配内存时,允许用户自定义对齐大小,优化内存使用效率。在处理对齐逻辑时,Arena巧妙地利用位运算优化计算过程,提高了代码效率。
总结而言,RocksDb的内存管理机制通过Arena类实现了高效、灵活的内存分配与管理。通过深入解析其源码,可以深入了解内存对齐、内存分配与多线程安全性的实现细节,为开发者提供宝贵的内存管理实践指导。未来,将深入探讨多线程内存分配器的设计,敬请期待后续更新。