# Sled 数据库详细说明 **文档日期:** 2026-05-29 **评估版本:** sled 1.0.0-alpha.124 --- ## 一、Sled 是什么? ### 1.1 定义 **Sled = Simple Lightweight Embedded Database** 一个纯 Rust 实现的嵌入式键值存储数据库。 **核心特点:** - 100% Rust 实现 (无 C/C++ FFI) - 轻量级高性能 - ACID 事务支持 - MVCC 并发控制 - 跨平台支持 ### 1.2 发展历史 **创建者:** Tyler Neely (spacejam) **创建时间:** 2017年 **GitHub:** https://github.com/spacejam/sled **Stars:** 7,000+ **版本状态:** 1.0.0-alpha.124 (接近稳定) **设计目标:** > "A modern embedded database that is built entirely in Rust, with no unsafe code blocks, no FFI, and a focus on correctness and performance." --- ## 二、技术架构 ### 2.1 存储模型 **架构:B-Tree + MVCC** ``` Sled Internal Structure: ┌─────────────────────────────────┐ │ In-Memory B-Tree (PageCache) │ ← 读取优化 ├─────────────────────────────────┤ │ MVCC Version Chain │ ← 并发控制 ├─────────────────────────────────┤ │ Log-Structured Storage │ ← 写入优化 ├─────────────────────────────────┤ │ Snapshot Files │ ← 持久化 └─────────────────────────────────┘ ``` **关键组件:** 1. **PageCache:** - 内存 B-Tree 节点缓存 - LRU 淘汰策略 - 支持并发读取 2. **MVCC:** - 多版本并发控制 - 无锁读取 - Snapshot isolation 3. **Log-Structured Storage:** - 顺序写入优化 - 批量提交 - 后台压缩 4. **Trees (类似 Column Families):** - 逻辑分区 - 类似 RocksDB Column Families - 独立命名空间 ### 2.2 并发模型 **MVCC (Multi-Version Concurrency Control):** ``` Sled MVCC Concurrency: ┌─────────────────────────────────────┐ │ Reader 1 ──┐ │ │ Reader 2 ──┤ │ │ Reader 3 ──┼──> Snapshot Version N │ ← 无锁读取 │ Reader 4 ──┤ │ │ Reader N ──┘ │ ├─────────────────────────────────────┤ │ Writer 1 ──┤ │ │ Writer 2 ──┼──> New Version N+1 │ ← 并发写入 │ Writer M ──┘ │ └─────────────────────────────────────┘ 优势: - 读取无锁 (多个 reader 并发) - 写入并发 (多个 writer) - Snapshot isolation (一致性读取) ``` **对比 SQLite WAL:** ``` SQLite WAL: - Reader: ✅ 多个并发 - Writer: ❌ 单个 (排他锁) Sled MVCC: - Reader: ✅ 多个并发 - Writer: ✅ 多个并发 ``` ### 2.3 数据结构 **Tree (命名空间):** ```rust // 类似 RocksDB Column Families let db = sled::open("my_db")?; // 创建多个 Trees (类似多个表) let nodes_tree = db.open_tree("file_nodes")?; let registry_tree = db.open_tree("file_registry")?; let locations_tree = db.open_tree("file_locations")?; // 每个 Tree 独立命名空间 nodes_tree.insert("node_123", node_data)?; registry_tree.insert("uuid_456", registry_data)?; locations_tree.insert("loc_789", location_data)?; ``` **IVec (内联向量):** ```rust // Sled 的核心数据类型 pub struct IVec { inline: [u8; 24], // 小数据内联存储 heap: Option>, // 大数据堆存储 } // 优势: // - 小数据 (<24 bytes) 无额外分配 // - 大数据自动切换到堆 // - 减少 heap allocation ``` --- ## 三、性能特性 ### 3.1 性能基准 **官方性能数据 (sled 0.34):** | 操作 | 性能 | 备注 | |------|------|------| | **写入吞吐** | ~50,000 ops/sec | 单线程 | | **读取吞吐** | ~100,000 ops/sec | 单线程 | | **事务吞吐** | ~10,000 tx/sec | ACID | | **批量写入** | ~100,000 ops/sec | WriteBatch | **对比其他数据库:** | 数据库 | 写入吞吐 | 读取吞吐 | 事务吞吐 | |--------|----------|----------|----------| | SQLite | 14,243/sec | 10,000+/sec | 5,000/sec | | RocksDB | 50,000+/sec | 50,000+/sec | 20,000/sec | | Sled | 30,000/sec | 20,000/sec | 10,000/sec | ### 3.2 性能优势 **读取优势:** - ✅ B-Tree 结构 (O(log n) 查找) - ✅ PageCache 缓存 (LRU) - ✅ MVCC 无锁读取 - ✅ 小数据内联存储 (减少 allocation) **写入优势:** - ✅ Log-Structured 写入 (顺序写入) - ✅ 批量提交 (WriteBatch) - ✅ 后台压缩 (不阻塞写入) **并发优势:** - ✅ 多个 reader 并发 (MVCC) - ✅ 多个 writer 并发 (MVCC) - ✅ 无锁读取 ### 3.3 性能劣势 **写入吞吐:** - ⚠️ 不如 RocksDB (30K vs 50K) - ⚠️ Log-Structured 有额外开销 **空间效率:** - ⚠️ 不如 RocksDB (无内置压缩) - ⚠️ MVCC 有版本开销 **大规模数据:** - ⚠️ 不如 RocksDB (>100GB 后性能下降) - ⚠️ PageCache 有内存限制 --- ## 四、API 设计 ### 4.1 基本 API ```rust use sled::{Db, IVec, Tree}; // 打开数据库 let db = sled::open("my_database.sled")?; // 基本操作 (类似 HashMap) db.insert("key", "value")?; let value = db.get("key")?; db.remove("key")?; // 批量操作 db.apply_batch(|batch| { batch.insert("k1", "v1"); batch.insert("k2", "v2"); batch.remove("k3"); })?; ``` ### 4.2 Tree API (命名空间) ```rust // 创建 Tree (类似 Column Family) let tree = db.open_tree("my_tree")?; // Tree 操作 tree.insert("key", "value")?; let value = tree.get("key")?; tree.remove("key")?; // 范围查询 for item in tree.range("start".."end") { let (key, value) = item?; println!("{:?}: {:?}", key, value); } // 前缀查询 for item in tree.scan_prefix("prefix") { let (key, value) = item?; println!("{:?}: {:?}", key, value); } ``` ### 4.3 事务 API ```rust // ACID 事务 db.transaction(|tx| { // 多个操作在一个事务中 tx.insert("key1", "value1")?; tx.insert("key2", "value2")?; // 可以跨多个 Trees let tree1 = tx.open_tree("tree1")?; let tree2 = tx.open_tree("tree2")?; tree1.insert("k1", "v1")?; tree2.insert("k2", "v2")?; Ok(()) })?; ``` ### 4.4 高级 API ```rust // Watch (订阅变更) let subscriber = db.watch_prefix("prefix"); while let Ok(event) = subscriber.next() { println!("Key changed: {:?}", event); } // Compare and Swap (CAS) let old_value = db.get("key")?; let result = db.compare_and_swap("key", old_value, Some("new_value"))?; // Merge (合并操作) db.merge("counter", b"1")?; // 自动合并数值 ``` --- ## 五、MarkBase 适用性评估 ### 5.1 数据模型映射 **SQLite → Sled 映射:** ```rust // SQLite 表 → Sled Tree let nodes_tree = db.open_tree("file_nodes")?; let registry_tree = db.open_tree("file_registry")?; let locations_tree = db.open_tree("file_locations")?; // SQLite Row → Sled Key-Value // Key: node_id (TEXT) // Value: JSON or MessagePack // 示例: let node_data = serde_json::json!({ "node_id": "abc123", "label": "test.mp4", "parent_id": "parent123", "node_type": "file", "file_size": 1024, "sha256": "...", "aliases_json": {...} }); nodes_tree.insert("abc123", serde_json::to_vec(&node_data)?)?; ``` ### 5.2 查询映射 **SQLite 查询 → Sled 查询:** ```rust // SQLite: SELECT * FROM file_nodes WHERE parent_id = ? // Sled: scan_prefix(parent_id) let prefix = parent_id.as_bytes(); for item in nodes_tree.scan_prefix(prefix) { let (key, value) = item?; let node: Node = serde_json::from_slice(&value)?; if node.parent_id == parent_id { println!("{}", node.label); } } // SQLite: SELECT * FROM file_nodes WHERE sha256 = ? // Sled: 需要建立索引 Tree let sha256_tree = db.open_tree("sha256_index")?; sha256_tree.insert(sha256, node_id)?; // 查询: let node_id = sha256_tree.get(sha256)?; let node_data = nodes_tree.get(node_id)?; ``` ### 5.3 优势场景 **适合 MarkBase 的场景:** 1. **高并发写入** - ✅ 多个 users 同时导入 - ✅ MVCC 无锁写入 2. **纯 Rust 项目** - ✅ 无 FFI 依赖 - ✅ 内存安全 3. **简单 KV 存储** - ✅ node_id → node_data - ✅ 类似 HashMap API 4. **并发读取** - ✅ FUSE 多线程读取 - ✅ MVCC 无锁读取 ### 5.4 劣势场景 **不适合 MarkBase 的场景:** 1. **复杂查询** - ❌ 无 SQL 支持 - ❌ 需要手动实现 JOIN 2. **关系查询** - ❌ parent_id → children 查询复杂 - ❌ file_uuid → locations 查询复杂 3. **大规模写入** - ⚠️ 性能不如 RocksDB - ⚠️ 无内置压缩 4. **调试工具** - ❌ 无类似 SQLite Browser - ❌ CLI 工具较少 --- ## 六、迁移成本评估 ### 6.1 迁移步骤 **SQLite → Sled 迁移:** **Day 1: Schema 设计** ```rust // 定义 Trees pub fn init_user_db(db: &Db) -> Result<()> { db.open_tree("file_nodes")?; db.open_tree("file_registry")?; db.open_tree("file_locations")?; db.open_tree("sha256_index")?; db.open_tree("parent_index")?; Ok(()) } ``` **Day 2: 数据导出** ```bash sqlite3 warren.sqlite "SELECT * FROM file_nodes" > nodes.csv sqlite3 warren.sqlite "SELECT * FROM file_registry" > registry.csv sqlite3 warren.sqlite "SELECT * FROM file_locations" > locations.csv ``` **Day 3: 数据导入** ```rust let db = sled::open("warren.sled")?; let nodes_tree = db.open_tree("file_nodes")?; for row in csv::Reader::from_reader(nodes_csv) { let node_data = serde_json::to_vec(&row)?; nodes_tree.insert(row.node_id.as_bytes(), node_data)?; } ``` **Day 4-6: 代码重写** - 重写 filetree/mod.rs (553行) - 重写 server.rs 数据库部分 - 重写 scan.rs 批量导入 **Day 7-8: 测试验证** - 功能测试 (7个测试) - 性能测试 (5个场景) - 并发测试 **总工作量:** 8天 ### 6.2 迁移风险 **高风险点:** - ⚠️ Schema 变更风险 (SQL → KV) - ⚠️ 查询逻辑重写风险 - ⚠️ 索引维护复杂度 **缓解措施:** - ✅ 保留 SQLite 作为 metadata layer - ✅ Sled 仅用于 KV 存储 - ✅ 混合架构降低风险 --- ## 七、与 SQLite/RocksDB 对比 ### 7.1 技术对比 | 特性 | SQLite | RocksDB | Sled | |------|--------|---------|------| | **语言实现** | C | C++ | Rust ✅ | | **FFI依赖** | ✅ 有 | ✅ 有 | ❌ 无 ✅ | | **存储模型** | B-Tree | LSM-Tree | B-Tree + MVCC | | **并发模型** | WAL (单writer) | LSM (多writer) | MVCC (多writer) ✅ | | **SQL支持** | ✅ 完整 | ❌ 无 | ❌ 无 | | **压缩支持** | ❌ 无 | ✅ Snappy | ❌ 无 | | **事务支持** | ✅ ACID | ✅ ACID | ✅ ACID | ### 7.2 性能对比 | 性能指标 | SQLite | RocksDB | Sled | |----------|--------|---------|------| | **写入吞吐** | 14K/sec | 50K+/sec | 30K/sec | | **读取吞吐** | 10K+/sec | 50K+/sec | 20K/sec | | **查询延迟** | <1ms | <5ms | <2ms | | **并发写入** | ❌ 单writer | ✅ 多writer | ✅ 多writer | | **并发读取** | ✅ 多reader | ✅ 多reader | ✅ 多reader | | **空间效率** | 高 | 中 (压缩) | 中 | ### 7.3 适用场景对比 **SQLite 适用场景:** - ✅ 需要 SQL 查询 - ✅ 需要复杂 JOIN - ✅ 需要事务完整性 - ✅ 需要调试工具 - ⚠️ 小规模数据 (<100GB) **RocksDB 适用场景:** - ✅ 高并发写入 (>10 users) - ✅ 大规模数据 (>100GB) - ✅ 需要压缩节省空间 - ❌ 不需要复杂查询 - ⚠️ 团队熟悉 LSM-Tree **Sled 适用场景:** - ✅ 纯 Rust 项目 - ✅ 需要并发写入但规模不大 - ✅ 需要简单 KV 存储 - ✅ 降低学习成本 - ❌ 不需要复杂查询 --- ## 八、综合评估 ### 8.1 MarkBase 适用性评分 | 维度 | SQLite | RocksDB | Sled | |------|--------|---------|------| | **功能匹配度** | 95/100 | 75/100 | 85/100 | | **性能匹配度** | 85/100 | 95/100 | 80/100 | | **运维成本** | 95/100 | 60/100 | 85/100 | | **开发效率** | 95/100 | 65/100 | 80/100 | | **迁移成本** | 100/100 | 40/100 | 60/100 | | **Rust生态** | 95/100 | 75/100 | 95/100 | | **总分** | **665/700** | **510/700** | **535/700** | ### 8.2 推荐决策 **当前推荐:SQLite + 优化** ⭐⭐⭐⭐⭐ **Sled 适用时机:** - 需要纯 Rust 实现 (无 FFI) - 需要并发写入但规模不大 (<50GB) - 团队不熟悉 LSM-Tree (RocksDB 复杂) - 想降低学习成本 (API 简单) **混合架构推荐:** ``` MarkBase Hybrid DB Architecture: ┌─────────────────────────────────┐ │ Metadata Layer (SQLite) │ ← 复杂查询 │ - file_nodes, file_registry │ │ - user_auth, sync_log │ └─────────────────────────────────┘ ↓ ┌─────────────────────────────────┐ │ KV Layer (Sled) │ ← 并发写入 │ - file_content_hash → path │ │ - hot_files_cache │ └─────────────────────────────────┘ ``` --- ## 九、总结 ### 9.1 Sled 核心优势 1. **纯 Rust 实现** - 无 FFI 依赖,内存安全 2. **MVCC 并发** - 多 reader + 多 writer 3. **简单 API** - 类似 HashMap,易上手 4. **跨平台** - 100% Rust,无平台依赖 ### 9.2 Sled 核心劣势 1. **无 SQL 支持** - 需要手动实现复杂查询 2. **性能中等** - 不如 RocksDB 高吞吐 3. **无内置压缩** - 空间效率不如 RocksDB 4. **社区较小** - 维护者少,文档有限 ### 9.3 最终建议 **一句话总结:** > Sled 是纯 Rust 实现的嵌入式 KV 数据库,适合并发写入场景,但 MarkBase 当前需求下 SQLite 更适合。 **推荐路径:** - 当前:SQLite + 优化 - 6个月后:评估混合架构 (SQLite + Sled) - 长期:Metadata (SQLite) + KV (Sled/RocksDB) --- **文档完成日期:** 2026-05-29 **下次评估日期:** 2026-11-29