forked from zigcc/zigcc.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path2026-04-02-zig-kvdb.smd
More file actions
105 lines (61 loc) · 5.65 KB
/
2026-04-02-zig-kvdb.smd
File metadata and controls
105 lines (61 loc) · 5.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
---
.title = "从 Rust 到 Zig,我写了一个小型 KV 数据库后,终于理解 Zig 到底“怪”在哪",
.date = @date("2026-04-02T13:11:11+0800"),
.author = "lispking",
.layout = "post.shtml",
.draft = false,
---
> 作为一个 Rust 爱好者,在真正深入使用 Zig 之后,我对这门语言的理解发生了转变。
在这篇文章中,我将通过 vibe coding 写的一个 **小型 KV 数据库** 项目来分析 Zig 和 Rust 的异同。
[Rust vs Zig]($image.siteAsset('images/rust-vs-zig.webp'))
## `kvdb`:一款轻量级嵌入式 KV 数据库
首先,来看看我们这个项目:`kvdb`。它是一个轻量级、嵌入式的 **Key-Value 数据库**,采用了 **B-tree 索引** 和 **写前日志(WAL)** 来确保数据持久化。核心功能如下:
* **B-tree** 结构:实现高效的键值对插入、查找和删除。
* **写前日志(WAL)**:确保数据在发生崩溃时的可恢复性。
* **事务支持**:提供基本的事务机制,保证操作的原子性。
* **页面存储**:使用固定大小的 4KB 页进行存储,以优化磁盘 I/O 性能。
然而,尽管这个项目具备了数据库的基本功能,它更像是一个数据库内核的雏形,并不完全是一个成熟的产品。
> 仓库地址:https://github.com/lispking/kvdb
## 设计与实现:从 Rust 的眼光看 Zig
在实现过程中,我很快就意识到,Zig 和 Rust 在设计哲学上有显著的差异。
* Rust 是一门注重“内存安全”的语言,依靠 **ownership** 系统来确保内存安全,无需垃圾回收。
* 而 Zig 则倾向于“暴露真相”,减少语言的魔法,给程序员更多的控制权。
### **Zig 的优点:暴露底层,简洁透明**
Zig 在内存管理、控制流等方面非常直接:
* 没有隐藏的控制流或内存分配,所有操作都是显式的。
* 没有预处理器,也没有宏。它的语法看起来可能有点古怪,但这正是 Zig 希望消除复杂抽象的体现。
这种设计让我在写 `kvdb` 时感受到了极大的灵活性,虽然刚开始时有些不适应。
### **Rust 的优点:内存安全与高抽象**
与此相对,Rust 则通过 **ownership**、**borrowing** 和 **lifetime** 等特性提供了强大的内存安全保证,它通过 **编译期检查** 让程序员避免了许多常见的内存错误。
Rust 会在编译时就要求程序员“遵守规则”,这让我在写代码时不需要担心内存泄漏或者悬空指针等问题。在大型工程中,Rust 的这一点尤其重要。
### **Zig 让我“重新认识”底层控制感**
Zig 的核心哲学是“程序员直接面对控制流和内存管理”。
在我写 `kvdb` 时,我不得不深入思考每一行代码,思考它如何与硬盘交互、如何管理内存、如何确保数据一致性。
Zig 不会通过隐藏一些复杂的实现来“保护”我,而是让我在做每个决定时都能清楚了解背后的原因。
这种直接控制的感觉,非常像我之前在 C 语言中体验到的那种“强烈的底层感”。不过,Zig 的优势在于,它减少了 C 语言中的许多危险操作,同时仍保留了较高的控制力。
## `kvdb`:当前的局限性与改进方向
尽管 `kvdb` 的架构已经具备了基本的数据库功能,但它并不完美。当前最显著的问题是 **B-tree 索引** 部分:
1. **B-tree 目前是单页版本**:`BTree.put()` 方法会检查 root 是否已满,如果已满就返回 `Error.NodeFull`,而没有实现分裂节点的逻辑。这样一来,B-tree 的操作非常简化,无法支持真正的多页树结构。
2. **事务回滚不完全**:`abort()` 方法并没有完全实现 WAL 的回滚机制,而是通过 `reload()` 恢复状态。虽然 WAL 已经在代码中实现,但恢复操作的精细度还远远不够。
3. **WAL 的性能问题**:每次写入 WAL 后都会执行 `sync()`,这对于性能要求较高的场景来说会成为瓶颈。
### **B-tree 需要支持节点分裂与多页操作**
目前,B-tree 只支持单页插入,当根节点满时直接返回 `Error.NodeFull`,缺少分裂、合并和多页遍历的完整实现。接下来,应该完善分裂和合并机制,确保数据库能够处理更大规模的数据集。
### **事务回滚与恢复机制的改进**
`abort()` 方法虽然已经实现了基本的回滚,但还缺少通过 WAL 重放来实现更细粒度的撤销。后续可以进一步增强这一部分,使得系统能够在发生故障时,准确地恢复到正确的状态。
### **WAL 的性能优化**
目前,WAL 的每条记录都进行 `sync()`,这对于写入密集型应用来说可能会影响性能。未来可以通过引入批量提交、事务提交时才刷新 WAL 等方式来优化这一部分。
## 总结
> Zig 的独特魅力与 Rust 的优势
通过这次使用 Zig 写数据库内核的经历,我更加深刻地理解了 **Rust 和 Zig 的设计哲学**。
* Rust 强调编译时安全,强调内存和并发安全。
* 而 Zig 则通过显式的控制流和内存管理,给程序员更多的自由和控制权。
两者各有千秋。
在项目中,我对 Zig 的控制力和透明性有了全新的理解。尽管它的语法有点“古怪”,但它的设计哲学却让我对底层编程有了更深的体验。
### **Rust**:
* 强调安全、性能和并发。
* 适用于长期维护、大型项目。
### **Zig**:
* 更加透明、直接控制底层。
* 适合高性能计算、嵌入式应用。
如果让我选择,我会依然选择 Rust 作为主要开发语言,尤其是在大型系统和复杂并发场景下。
但 Zig 的底层控制感和灵活性,绝对值得在一些特定场景下使用。