spacejam/sled
GitHub: spacejam/sled
一款用 Rust 编写的高性能嵌入式键值数据库,提供 ACID 事务支持和无锁并发访问。
Stars: 8958 | Forks: 421
|
|
|
# sled - ~~从这里开始下坡吧!!!~~
一个嵌入式数据库。
```
let tree = sled::open("/tmp/welcome-to-sled")?;
// insert and get, similar to std's BTreeMap
let old_value = tree.insert("key", "value")?;
assert_eq!(
tree.get(&"key")?,
Some(sled::IVec::from("value")),
);
// range queries
for kv_result in tree.range("key_1".."key_9") {}
// deletion
let old_value = tree.remove(&"key")?;
// atomic compare and swap
tree.compare_and_swap(
"key",
Some("current_value"),
Some("new_value"),
)?;
// block until all operations are stable on disk
// (flush_async also available to get a Future)
tree.flush()?;
```
$${\color{red}本 \space README \space 与 \space 主分支 \space 不同步,\space 主分支 \space 包含 \space 正在进行 \space 大规模 \space 重写 }$$
如果您想使用结构化数据,同时避免昂贵的反序列化成本,请查看 [structured](examples/structured.rs) 示例!
# 功能特性
* 类似于线程安全 `BTreeMap<[u8], [u8]>` 的 [API](https://docs.rs/sled)
* 可序列化 (ACID) [事务](https://docs.rs/sled/latest/sled/struct.Tree.html#method.transaction)
用于原子性地在多个 keyspace 中读取和写入多个键。
* 完全原子性的单键操作,包括 [比较并交换](https://docs.rs/sled/latest/sled/struct.Tree.html#method.compare_and_swap)
* 零拷贝读取
* [写入批次](https://docs.rs/sled/latest/sled/struct.Tree.html#method.apply_batch)
* [订阅键前缀的变更](https://docs.rs/sled/latest/sled/struct.Tree.html#method.watch_prefix)
* [多个 keyspace](https://docs.rs/sled/latest/sled/struct.Db.html#method.open_tree)
* [合并运算符](https://docs.rs/sled/latest/sled/doc/merge_operators/index.html)
* 支持范围项的正向和反向迭代器
* 一个崩溃安全的单调 [ID 生成器](https://docs.rs/sled/latest/sled/struct.Db.html#method.generate_id)
每秒能够生成 7500 万到 1.25 亿个唯一 ID
* [zstd](https://github.com/facebook/zstd) 压缩(使用
`compression` 构建特性,默认禁用)
* cpu 可扩展的无锁实现
* 针对闪存优化的日志结构化存储
* 使用现代 B 树技术,如前缀编码和后缀
截断,以减少具有共享
前缀的长键的存储成本。如果键长度相同且
连续,系统在大多数情况下可以避免
存储 99% 以上的键数据,
本质上就像一个学习型索引
# 预期、注意事项与建议
* 也许看起来最奇怪的事情之一是 `IVec` 类型。
这是一个可内联的 `Arc` 切片,使某些事情更高效。
* 持久性:**sled 默认每 500ms 自动 fsync**,
这可以通过 `flush_every_ms` 配置,或者您可以
在操作后手动调用 `flush` / `flush_async`。
* **事务是乐观的** - 除非是
[幂等](https://en.wikipedia.org/wiki/Idempotent)的,否则不要从事务闭包中
与外部状态交互或执行 IO。
* 内部树节点优化:sled 对
在范围内分组在一起的具有相似前缀的
长键执行前缀编码,
以及后缀截断以进一步减少长键的
索引成本。如果键或值
长度全部相同(单独跟踪,不必
担心让键与值长度相同),节点将跳过潜在昂贵的长度和偏移指针,因此如果您使用固定长度的键或值,可能会稍微改善空间使用。这也使得
更容易使用 [结构化访问](examples/structured.rs)。
* sled 暂时不支持多个打开的实例。请
在进程的生命周期内保持 sled 打开。使用全局 lazy_static sled 实例是完全
安全的,而且通常非常方便,
除了正常的全局变量权衡之外。每个操作都是线程安全的,
并且大多数在底层使用无锁算法实现,避免
在热路径中阻塞。
# 性能
* 类似于 [LSM tree](https://en.wikipedia.org/wiki/Log-structured_merge-tree) 的写入性能
以及类似于 [传统 B+ tree](https://en.wikipedia.org/wiki/B%2B_tree) 的读取性能
* 在 16 核的小数据集上,95% 读取 5% 写入的情况下,一分钟内完成超过 10 亿次操作
* 测量您自己的工作负载,而不是依赖一些针对人为工作负载的营销宣传
# 关于字典序和字节序的说明
如果您想以一种能很好地配合 sled 迭代器和有序操作的方式存储数字键,请记住以 big-endian 形式存储您的数字项。Little endian(许多事物的默认设置)通常看起来在做正确的事情,直到您开始处理超过 256 个项(超过 1 个字节),导致序列化字节的字典序与其反序列化的数字形式的字典序发生偏离。
* Rust 整数类型具有内置的 `to_be_bytes` 和 `from_be_bytes` [方法](https://doc.rust-lang.org/std/primitive.u64.html#method.from_be_bytes)。
* bincode [可以配置](https://docs.rs/bincode/1.2.0/bincode/struct.Config.html#method.big_endian) 为以 big-endian 形式存储整数类型。
# 与 Async 的交互
如果您的数据集完全驻留在缓存中(可在启动时通过将缓存设置为足够大的值并执行完整迭代来实现),那么所有读取和写入都是非阻塞且对异步友好的,无需使用 Futures 或异步运行时。
为了在写入的持久性上异步挂起您的异步任务,我们支持
[`flush_async` 方法](https://docs.rs/sled/latest/sled/struct.Tree.html#method.flush_async),
它返回一个 Future,如果您的异步任务需要高持久性保证,并且您愿意支付 fsync 的延迟成本,则可以等待其完成。
请注意,sled 会自动尝试在后台每秒多次
将所有数据同步到磁盘,而不会阻塞用户线程。
我们支持对键前缀上发生的事件进行异步订阅,因为
`Subscriber` 结构体实现了 `Future
标签:ACID事务, BTreeMap, HTTP工具, KV数据库, Rust, sled, 原子操作, 可视化界面, 嵌入式存储, 嵌入式数据库, 数据存储引擎, 本地存储, 磁盘持久化, 结构化数据, 网络流量审计, 通知系统, 键值存储