深入解读 Redb:高性能嵌入式键值存储的新秀

  • King
  • 发布于 1天前
  • 阅读 451

引言在当今的数据驱动时代,高效的数据存储和管理至关重要。嵌入式键值存储因其轻量级、高性能和易于集成的特点,在众多应用场景中得到了广泛应用。Redb作为一个新兴的嵌入式键值存储库,以其简单、可移植、高性能和支持ACID等特性,吸引了众多开发者的关注。本文将深入解读Redb的核心特性、

引言

在当今的数据驱动时代,高效的数据存储和管理至关重要。嵌入式键值存储因其轻量级、高性能和易于集成的特点,在众多应用场景中得到了广泛应用。

Redb 作为一个新兴的嵌入式键值存储库,以其简单、可移植、高性能和支持 ACID 等特性,吸引了众多开发者的关注。

本文将深入解读 Redb 的核心特性、性能表现、设计原理以及使用方法,帮助你更好地了解和使用这个强大的工具。

Redb 概述

Redb 是一个用纯 Rust 编写的嵌入式键值存储库,它受到了 lmdb 的启发,采用了复制写(copy-on-write)的 B 树来存储数据。这种设计使得 Redb 具有很高的性能和可靠性,同时保持了代码的简洁性和可维护性。

核心特性

  • 零拷贝与线程安全:提供基于 BTreeMap 的零拷贝、线程安全 API,减少了数据复制的开销,提高了并发性能。
  • ACID 事务支持:支持完全符合 ACID 标准的事务,确保数据的一致性和完整性。
  • MVCC 并发控制:采用多版本并发控制(MVCC),支持并发的读写操作,且不会产生阻塞,提高了系统的并发处理能力。
  • 崩溃安全:默认具备崩溃安全特性,即使在系统崩溃或异常情况下,也能保证数据的一致性和完整性。
  • 保存点与回滚:支持保存点和回滚操作,方便开发者在事务处理过程中进行错误恢复和数据回滚。

性能表现

Redb 的性能表现是其一大亮点,它与其他顶级嵌入式键值存储(如 lmdb 和 rocksdb)相近。下面是 Redb 与其他存储库的性能对比: 操作类型 redb lmdb rocksdb sled sanakirja
批量加载(bulk load) 2689ms 1247ms 5330ms 5892ms 1187ms
单条写入(individual writes) 226ms 419ms 703ms 816ms 398ms
批量写入(batch writes) 2522ms 2070ms 1047ms 1867ms 2776ms
获取长度(len()) 0ms 0ms 304ms 444ms 64ms
随机读取(random reads) 860ms 624ms 2432ms 1596ms 875ms
随机读取(random reads) 866ms 624ms 2464ms 1588ms 842ms
随机范围读取(random range reads) 2347ms 1179ms 4436ms 4907ms 1367ms
随机范围读取(random range reads) 2322ms 1207ms 4465ms 4732ms 1373ms
随机读取(4 线程)(random reads (4 threads)) 337ms 158ms 732ms 488ms 349ms
随机读取(8 线程)(random reads (8 threads)) 185ms 81ms 433ms 259ms 277ms
随机读取(16 线程)(random reads (16 threads)) 116ms 49ms 238ms 165ms 1708ms
随机读取(32 线程)(random reads (32 threads)) 100ms 44ms 203ms 142ms 4714ms
删除操作(removals) 1889ms 803ms 2038ms 2371ms 1170ms
未压缩大小(uncompacted size) 1.00 GiB 582.22 MiB 206.38 MiB 457.01 MiB 4.00 GiB
压缩后大小(compacted size) 311.23 MiB 284.46 MiB 106.26 MiB N/A N/A

从上述数据可以看出,Redb 在单条写入和获取长度操作上表现出色,而在其他操作上也与其他存储库各有优劣。这表明 Redb 在不同的应用场景下都能提供较好的性能表现。

设计原理

文件格式

Redb 的数据库文件逻辑上由一些元数据和多个 B 树组成,包括待释放页树(pending free tree)、表树(table tree)和数据表树(data tree)。除了数据库元数据外,所有其他数据结构都是复制写的,这意味着在修改数据时,会创建新的数据副本,而不是直接修改原始数据,从而保证了数据的一致性和可恢复性。

事务处理

Redb 支持两种事务提交策略:单阶段加校验和提交(1PC+C)和两阶段持久化提交(2PC)。

  • 单阶段加校验和提交(1PC+C):这是默认的提交策略,通过一次 fsync 操作完成提交。首先,将所有数据和校验和写入磁盘,同时写入一个单调递增的事务 ID,然后翻转主页面标志并调用 fsync。如果发生崩溃,需要验证主页面的事务 ID 是否更大,以及所有校验和是否有效。如果验证失败,数据库将用备用页面替换部分更新的主页面。这种策略减少了提交延迟,但在处理恶意数据时存在一定的安全风险。
  • 两阶段持久化提交(2PC):该策略通过两次 fsync 操作完成提交,能够减轻处理恶意数据时的理论攻击风险。首先,将数据写入 B 树的新副本,然后进行第一次 fsync;最后,翻转控制 B 树主副本的字节并进行第二次 fsync

MVCC(多版本并发控制)

Redb 采用了基于纪元的页面回收机制,确保页面在不再被引用后才被释放。在事务和保存点的处理过程中,需要特别注意避免释放仍被引用的页面,以保证数据的一致性和完整性。

使用方法

下面是一个简单的使用示例,展示了如何创建数据库、插入数据和读取数据:

use redb::{Database, Error, ReadableTable, TableDefinition};

const TABLE: TableDefinition<&str, u64> = TableDefinition::new("my_data");

fn main() -> Result<(), Error> {
    let db = Database::create("my_db.redb")?;
    let write_txn = db.begin_write()?;
    {
        let mut table = write_txn.open_table(TABLE)?;
        table.insert("my_key", &123)?;
    }
    write_txn.commit()?;

    let read_txn = db.begin_read()?;
    let table = read_txn.open_table(TABLE)?;
    assert_eq!(table.get("my_key")?.unwrap().value(), 123);

    Ok(())
}

开发与测试

要运行 Redb 的所有测试和基准测试,需要安装一些额外的依赖:

cargo install cargo-deny --locked
cargo install cargo-fuzz --locked
apt install libclang-dev

总结

Redb 作为一个新兴的嵌入式键值存储库,具有简单、可移植、高性能和支持 ACID 等特性,在性能上与其他顶级存储库相近。其采用的复制写 B 树和 MVCC 并发控制机制,保证了数据的一致性和并发性能。

同时,支持多种事务提交策略和保存点回滚操作,提高了系统的可靠性和灵活性。如果你正在寻找一个高性能、可靠的嵌入式键值存储解决方案,Redb 是一个值得考虑的选择。

Redb 目前正在区块链行业中得到广泛应用。其文件格式保持稳定,在区块链领域的应用展示了它在现实世界高需求场景中的可靠性和性能。

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
King
King
0x56af...a0dd
擅长Rust/Solidity/FunC/Move开发