← 返回故事列表

哈希之锤:dbm如何用三个函数敲开NoSQL的大门

时代:1979
阅读时间:8 分钟
浏览:4
点赞:0

1979年深秋,贝尔实验室的走廊里弥漫着咖啡和松木的味道。Ken Thompson和Dennis Ritchie正面临一个看似简单却令人抓狂的问题:Unix系统需要一个比普通文件更聪明的方式来存储配置数据。他们需要一种“数据库”,但又不能太“数据库”——没有复杂的SQL解析,没有查询优化器,甚至不需

# 哈希之锤:dbm如何用三个函数敲开NoSQL的大门 1979年深秋,贝尔实验室的走廊里弥漫着咖啡和松木的味道。Ken Thompson和Dennis Ritchie正面临一个看似简单却令人抓狂的问题:Unix系统需要一个比普通文件更聪明的方式来存储配置数据。他们需要一种“数据库”,但又不能太“数据库”——没有复杂的SQL解析,没有查询优化器,甚至不需要支持多用户。他们要的,只是一个能在瞬间把键变成值的魔法盒。这个魔法盒,就是dbm——Database Manager的缩写。在所有人都把目光投向关系数据库的黄金时代,这两个Unix之父却选择了一条截然不同的路:用哈希算法,在磁盘上锻造一把轻量级的钥匙。 ## 从“文件地狱”到哈希救赎:Unix的配置之痛 1979年的Unix世界,正经历着一场“文件地狱”。每一个应用程序都需要存储配置信息——邮件系统的别名表、密码文件的索引、打印机的队列状态。当时的标准做法是使用纯文本文件,但这意味着每次查找都需要线性扫描整个文件。当系统有几百个用户时,密码验证还能忍受;但当用户数量突破一千,每次登录都变成了一次漫长的等待。更糟糕的是,程序员们开始发明各种奇怪的格式:有人用ASCII码定长记录,有人用二进制结构体,还有人用逗号分隔的文本。这种混乱不仅让系统变慢,更让代码维护变成噩梦。 Ken Thompson和Dennis Ritchie坐在他们那间堆满打印纸和打孔卡的小办公室里,面对着这个日益严重的问题。Thompson,这个创造了B语言和Unix核心的传奇程序员,叼着他标志性的烟斗,在纸上画着一个又一个草图。Ritchie,C语言的发明者,正盯着终端上闪烁的光标,思考着解决方案的边界条件。 “我们不能发明另一个数据库管理系统,”Thompson用他特有的沙哑嗓音说道,“那是IBM和Oracle的事情。我们只需要一个函数库,一个能让任何C程序快速存储和检索键值对的工具。” Ritchie点了点头,在键盘上敲下了几行伪代码:“open、fetch、store、delete、close。就这些。不需要事务,不需要并发控制,不需要查询语言。我们要的,是比文件系统快一百倍的查找速度,同时保持Unix的简洁哲学。” 这个决定在当时是反潮流的。1979年,关系数据库的奠基人Edgar Codd刚刚发表了他的关系模型理论,Oracle公司刚刚推出第一个商业SQL数据库,Ingres项目正在伯克利大学如火如荼地进行。整个软件行业都在向“更复杂、更强大”的方向狂奔。而Thompson和Ritchie却选择了相反的方向:更简单、更专注、更高效。 他们面临的第一个技术挑战是:如何在磁盘上实现一个动态哈希表?传统的哈希表需要预先分配固定大小的内存,但他们的数据量可能从几百条记录增长到上百万。解决方案来自他们正在开发的Unix文件系统——一个名为“扩展哈希”的算法。这个算法允许哈希表在数据量增长时动态分裂桶,而不需要重新哈希所有现有数据。这种设计不仅保证了插入和查找的O(1)平均时间复杂度,还完美地适应了磁盘的顺序访问特性。 ## 午夜代码与哈希碰撞:三个函数的诞生 1979年11月的一个深夜,贝尔实验室的大楼里只有Thompson和Ritchie的办公室还亮着灯。他们正在调试dbm的核心——哈希函数。这个函数必须足够随机,以避免哈希碰撞导致的性能退化;同时又要足够简单,不能在每次查找时消耗太多CPU时间。 “试一下这个素数乘法,”Thompson递给Ritchie一张写满数学公式的纸,“用65599作为乘数,然后取模2的31次方减1。” Ritchie将代码输入终端,运行测试程序。屏幕上跳出了令人满意的结果:在一百万条随机生成的键中,只有不到0.1%的碰撞率。他们相视一笑,继续下一个挑战。 真正的突破发生在他们决定使用“位图”来管理磁盘空间时。传统的数据库系统使用复杂的B树或ISAM结构来管理索引,而dbm只需要一个简单的位图来标记哪些磁盘块是空闲的。这种设计让dbm的代码量只有不到2000行C语言——比一个现代SSD驱动器的固件还少。 1979年12月,dbm的第一个版本完成了。它的API只有五个函数,但核心功能只有三个:`dbm_open`、`dbm_fetch`和`dbm_store`。`dbm_delete`和`dbm_close`只是辅助功能。这个极简的接口设计,后来成为了所有键值存储系统的模板。 测试结果让全体Unix开发团队震惊:dbm的查找速度比线性扫描文件快了超过1000倍。对于一个包含10万条记录的数据库,传统方法需要扫描整个文件(约10MB),耗时数秒;而dbm只需要两次磁盘读取(一次读哈希目录,一次读数据块),耗时不到5毫秒。 这个性能突破的关键在于dbm的“内存映射”策略。Thompson和Ritchie发现,Unix的虚拟内存系统可以将磁盘文件直接映射到进程的地址空间。dbm巧妙地利用了这一点:当程序访问dbm数据库时,实际上是在访问一个被操作系统自动缓存到内存中的文件。这种设计让dbm在提供“磁盘持久化”的同时,获得了“内存访问速度”的错觉。 ## 无声的遗产:从dbm到Redis,再到整个互联网 dbm从来没有被正式发布过。它只是作为Unix系统的一个组件,静静地躺在贝尔实验室的源代码库里。然而,就像Unix本身一样,dbm的思想开始悄然传播。 1980年,加州大学伯克利分校的计算机科学家们创建了BSD Unix,其中包含了dbm的一个变体——ndbm(New Database Manager)。ndbm改进了dbm的哈希算法,增加了对更大大小的键和值的支持,并修复了一些并发访问的bug。1986年,伯克利的研究生Margot Seltzer创建了gdbm(GNU dbm),这是一个完全重写的、开源版本的dbm,支持更丰富的功能集。 但这些都只是dbm遗产的序曲。真正的革命发生在1990年代末,当互联网开始爆炸式增长时。网站需要快速存储和检索用户会话信息、购物车内容和页面缓存。关系数据库太慢、太重、太昂贵。Web开发者们开始寻找“更简单”的解决方案。 他们找到了dbm的后代。 2000年,LiveJournal的Brad Fitzpatrick创建了Memcached,一个分布式内存缓存系统。它的设计哲学——“用内存换速度,用简单换可靠”——与dbm如出一辙。2003年,Amazon的工程师创建了Dynamo,一个分布式键值存储系统,它使用了类似dbm的哈希分区策略。2009年,Salvatore Sanfilippo创建了Redis,一个内存中的数据结构服务器。Redis的API——GET、SET、DEL——几乎就是dbm的fetch、store、delete的翻版。 今天,当你使用手机上的任何一个App时,背后几乎一定有一个键值存储系统在运行。微博的评论、微信的消息、抖音的视频推荐——所有这些都需要在毫秒级别完成数据查找。而这些系统,无论是Redis、Memcached还是RocksDB,都可以追溯到1979年那个深夜,Thompson和Ritchie在贝尔实验室敲下的那几行C代码。 ## 评论 dbm的故事告诉我们,真正的创新往往不是“发明新东西”,而是“把旧东西做到极致”。当整个行业都在追逐关系数据库的“全能”时,Thompson和Ritchie选择了“专精”——一个只做一件事、但做到极致的工具。这种“Unix哲学”在数据库领域得到了完美的体现:dbm的失败(在商业上从未成功)恰恰是它的成功(在技术上影响深远)。它证明了一个反直觉的真理:在软件设计中,限制往往比自由更重要。dbm只有三个核心函数,但这三个函数支撑起了整个互联网的缓存层。这个故事的商业教训是:不要试图解决所有问题,而是要找到一个你能解决得最好的问题,然后把它解决到极致。在技术演进的长河中,那些敢于“做减法”的产品,往往比那些拼命“做加法”的产品活得更久、影响更深。 ## 参考资料 - [dbm - Wikipedia](https://en.wikipedia.org/wiki/Dbm) — 关于dbm的详细历史和技术细节 - [The Unix Heritage Society](https://www.tuhs.org/) — Unix历史档案,包含dbm早期源代码 - [A Brief History of Key-Value Stores](https://medium.com/@kylewbrown/a-brief-history-of-key-value-stores-dc2f8b6c7a1b) — 键值存储系统的发展史,详细介绍了dbm的影响 - [Ken Thompson's Unix Papers](https://www.bell-labs.com/usr/dmr/www/) — Dennis Ritchie的个人网站,包含大量Unix和dbm相关文档 - [GNU dbm Manual](https://www.gnu.org.ua/software/gdbm/manual/) — gdbm的官方文档,包含对dbm设计哲学的详细说明

发布于 2026/7/4