SQlite 如今走过了24个年头,如今有了超一万亿的活跃使用量,它被许多顶尖的网页浏览器、操作系统、移动电话和其他嵌入式系统使用,是部署最广泛的数据库引擎之一,许多编程语言都有与 SQLite 库绑定。但SQlite 背后的贡献开发者却只有三人,其中项目最初的开发者Richard也已经63岁。Richard 如何失业后“闲着也是闲着”,然后搞出了这么一个使用范围超级广的通用关系数据库?
“不想背锅”
1992 年,31 岁的 D. Richard Hipp 在 Hwaci. 公司负责技术开发,他的专项团队中有一个客户是巴斯钢铁厂,负责为 DDG-79 Oscar Austin 号开发软件——那是一艘庞大、复杂、随时都会出毛病的战舰。
当时的数据库 Informix 运行得并不好,有时候服务器会宕机,导致应用程序无法运行。船员双击这款软件后会弹出对话框报错:“无法连接到数据库服务器”,而负责此项目的 Richard 团队对此无可奈何,因为他们无权控制数据库服务器。
Richard 之所以被选中,是因为他向来以能解决难题而闻名。“头顶着技术团队的名号,出的问题还是要由我们背锅,毕竟对话框这块可是我们负责的。”Richard 说道。
Richard 团队的思路是哪怕在战斗中受损,整个船舶系统也应该能够正常工作,因此数据库必须可靠。事实上,他们做的事情很简单,就是把数据读入 RAM——不做事务处理、不做任何类似的操作,只是把数据拉入内存。
这给了 Richard 这样的领悟:我们为什么非得需要服务器?为什我不能直接从磁盘驱动器上把数据提取出来?这样如果计算机运行状态良好,它就能运行应用程序,整个流程中不再存在可能导致失败的依赖项。
但四处打探后,他发现当时根本就没有能做到这一点的 SQL 数据库引擎。之后,Richard 的一位同事提醒道:
“Richard,你为什么不自己写一个呢?”
“行啊,我试试吧。”
Richard 回应了,但并没有立马动手。2000 年左右,公司资金中断,当时恰逢纽特·金里奇和比尔·克林顿就国会预算案发生了争执,导致所有政府合同都被取消了,Richard 被迫失业了好几个月。
“闲着也是闲着,正好来写那个数据库引擎。”就这样,Richard 开始了 SQLite 的研发。
2000 年时,人们主要使用拨号上网,只有 1% 的美国家庭拥有网络带宽,因此 Richard 不像现在的人们那样可以谷歌搜索学会构建数据库。
但他根据自己先前的编译器构建经验制定了一项清晰的计划:如果把每一条 SQL 语句视为一个程序,那自己的任务就是把这些程序编译成某种可执行的代码。
因此,Richard 编写了一套能够实际运行查询的字节码引擎,之后又编写了一款编译器,用于将 SQL 转换成相应的字节码。就这样,SQLite 诞生了。
可惜它并没有在 Richard 当时从事的战舰项目上发挥作用,因为那个项目被关闭了。后来项目重启,Richard 尝试把 SQLite 引入其中进行测试。不过遗憾的是客户坚持使用 Informix。“倒是可以理解,但 Informix 在开发方面的使用感受真的很差。”Richard 说道。
为了不浪费,Richard 把它放在了互联网上,于是有更多人开始使用。“当时还没有 Twitter 之类的东西,但已经有帖子说‘哇,我在自己的 Palm Pilot PDA 设备上运行 SQL 数据库啦!’不开玩笑,这样的事情当时确实吸引到很多人的关注,这也激励着我继续做研究和开发。”Richard 表示。
“其实我只是在到处借鉴”
“我最早开始编写 SQLite 的时候,曾经到处搜寻,想要看看有没有关于如何编写 SQL 数据库引擎的参考资料。可我什么都没找到,所以只能边做边学边发明。这是个完全由自己摸索出来的路径。”Richard 说道。
大部分理论都是由麻省理工学院、哈佛大学、剑桥大学或者伯克利大学的研究小组提出的,而如果大家没上过这些学校,就很可能完全没听说过这些理论,更没有靠谱的方式能够查询相关资料。
但奇怪的是,如果回头看看 Postgres 使用的火山模型和 SQLite 曾经使用的字节码模型,就会发现大家都不约而同选择了类似的方向。这些方案虽然从宏观来讲起点各不相同,但大家在如何提高速度表现方面却意见统一,所以 Richard 认为这也是对理论的一种印证,两条独立的开发路径得出了同样的答案。
例如,Richard 就从来没听说过覆盖索引。只是在一场位于德国的 PHP 大会上,他见到了 MySQL 初创团队成员之一的 David Axmark,Axmark 解释了 MySQL 是如何实现覆盖索引的。Richard 想,“哇哦,这个想法简直天才!”于是在回途的飞机上就开始为 SQLite 编写覆盖索引。
“其实我只是在到处借鉴。”Richard 说道,人们会分享自己的心得,有人会主动找他:
“你为什么不试试这种优化方法?”
“我没想到啊。”
“那你看能行吗?”
“那就试试呗。”
之后它就成了 SQLite 的一部分。这就是边做边学边发明的好处。
SQLite,“三战”成名
SQLite 开发出来的头一两年,Richard 忙于推进他的数据库项目。突然,有一天他接到了当时科技巨头摩托罗拉打来的电话。
“你好,我们正在设计一款新的手机操作系统,而且打算将 SQLite 纳入其中。你能为我们提供支持吗?”
“哦,可以的。我没问题。”
“那能不能给报个价?”
“好的,这样吧,明天咱们再打个电话,到时候我给你答复。”
当时 Richard 的内心一阵狂跳——居然还能靠做开源软件赚钱?真有这样的事?我该定多少钱?怎么办怎么办……Richard 四下搜索,想出了几种定价策略。摩托罗拉当时还有改进要求,需要适应手机硬件,于是 Richard 报了 8 万美元左右。“在当时的我看来,那数字简直就是在明抢,可以说贵得离谱。”
后来,Richard 又找来三位前同事一起做这个项目,而这就是 SQLite 项目起飞的原点。
而真正让 SQLite 走上成功道路的是诺基亚手机的操作系统塞班。塞班打电话希望 Richard 在感恩节那天能飞一趟伦敦总部。去了之后,Richard 才发现,塞班之前已经搞了一场大规模的招标,从中挑选出塞班系统的数据库引擎。
当时参加选拔的大约有 10 种不同的数据库引擎,其中有两款是开源项目,另外七款属于专有产品。塞班在数据集上运行了这些引擎,想看看哪种最适合自己的需求,最后 SQLite 顺利胜出。塞班还给了其他九家调整的机会,但最后又是 SQLite 赢了。
Richard 过去后,塞班的人对 SQLite 大加赞赏,同时又提出了一些改进要求。之后,双方签订了合同,由 Richard 负责做相应的开发。
当时 Richard 几人真的是尽心尽力,Richard 本人差不多是全职在做这方面工作了。
但是,后来塞班的人告诉他们:“不好意思,你得想办法提高巴士因子。”他们觉得 SQLite 的巴士因子不够……所以希望建立一个 SQLite 联盟,让更多人参与进来以保证项目长期存续。
注:所谓巴士因子,就是说一支团队里有多少成员意外被巴士撞了(或者受其他偶发因素影响而无法继续工作),才会导致项目陷入停滞。
接到需求后,Richard 开始推动这项重要工作,但他其实也不知道该怎么做。后来,当时 Mozilla 基金会的负责人 Michell Baker 听到了风声,主动给他打电话说:“Richard,你的做法有问题,让我来告诉你怎么建立一个联盟。”
Baker 制定了规则,强调“开发者必须掌控一切,开发者的决定就是最终决定。对于批准哪些内容加入项目,其他人没有投票权。企业参与者只有享受成果和贡献资金的荣誉头衔,但决定还是要由你自己掌握。”她对此非常坚定,而且对我可以说是知无不言、言无不尽。
Baker 是律师出身,我问她“那要怎么吸引人们加入?得设置怎样的激励措施?”她回答道,“别担心,人们肯定会加入的。只要按我的办法来,Mozilla 首先就会成为创始成员之一。”而在联盟计划公布后,果然吸引到了 Mozilla、塞班和 Adobe 的支持,各方共同成立了 SQLite 联盟。
值得一提的是,SQLite 的版权声明中还有一条:Open-Source, not Open-Contribution(开源,但是并不开放代码贡献)。因此,至今 SQLite 项目总共只有三位开发人员 D. Richard Hipp、Dan Kennedy 和 Joe Mistachkin。
构建智能手机这样的嵌入式开发是个缓慢的过程,需要长时间的迭代循环,更需要花时间等待各种功能在原型设计中一一体现,人们只能在看起来跟成品完全不同的“坯子”上进行开发。
谷歌联系了 Richard,当时的搜索巨头还跟手机或者嵌入式开发牵不上半点关系。
2005 年左右,Richard 几人正在跟 Android 开会,那时候这款如今声名大噪的操作系统还没真正出现,当时也没有 iPhone。那时候的手机下方是完整的 QEWRTY 全键盘,上方则是个较小的显示窗口。
Richard 团队使用 SQLite 进行调试:端连着手机,另一端在工作站上运行调试器。“这种感觉挺神奇的。其他人都不会干,而当我们把手机接入调试器时,电话响了。这位同事看了一眼说,‘哦,是我老婆,我得接个电话,不好意思。’我离开了房间,留他慢慢跟妻子聊天。”
当时 Richard 虽然表面上不露声色,但脑袋里却炸开了锅。“我们居然在接着公共网络的手机上调试应用程序,而且完全不耽误正常通话,这真是太令人震惊了。无论是摩托罗拉、塞班还是诺基亚,当时都没人能做到这一点。就在那个瞬间,我就知道 Android 绝对会大获成功。”
“我真的以为能写出没有 bug 的软件”
不过幸福之后,烦恼也会随之而来。
“我们曾经天真地宣传,SQLite 从不出错,至少不会搞出严重的 bug。但 Android 证明我们还是太过年轻、有时幼稚。我以前真的以为能编写出没有 bug 的软件,可一旦软件被发布到数百万台设备上时,引发的 bug 数量绝对会多到难以想象。”Richard 回忆道。
当时还在为航空电子设备制造商 Rockwell Collins 工作的 Richard,了解到了 DO-178B 的概念,他意识到其中最有价值、最关键的理念之一,就是要求实现 100% 的 MCDC 测试覆盖率。
注:MCDC,指的是确定代码修改条件的决策覆盖率。也就是说测试必须保证所生成二进制代码中的每个分支操作至少跑通一次。
受到启发后的 Richard 决定通过编写测试让 SQLite 也达到 100% 的 MCDC 覆盖率,而这花了他整整一年的时间,每周要工作 60 个小时。
“这项工作相当相当艰苦,我每天要干 12 个小时。这段经历真的让我感到厌倦,而且相信大家都听过一句老生常谈:我们用前 95% 的预算干完了 95% 的工作,再用另外 95% 的预算做完最后 5%。实际情况确实如此,把测试覆盖率推到 90% 甚至 95% 都很容易,可最后这 5% 则是难而又难,我花了大约一年时间才达成这个目标。”Richard 回忆时说道。
对于典型的发布周期,他们要运行十亿级别的测试,大约有 10 万个不同的测试用例。他们的第一项测试是用 TCL 编写的,真正 100% 覆盖的 MCDC 测试名叫 TH3,属于专有成果。Richard 本来希望把这些测试出售给航空电子设备制造商赚点钱,但一份都没卖出去。
团队有一个叫 SQL 逻辑测试的工具,目的是设法让每种数据库引擎都出现段错误,其中也包括 SQLite。“我们搞崩过 Oracle,包括 Oracle 的商用版本。我们搞崩过 DB2,尝试把我们能接触到的所有数据库并努力把它搞崩。”Richard 提到,唯一的例外就是 Postgres,它的稳定性给 Richard 留下了非常深刻的印象。
总之,提高测试覆盖率成了一项深远影响的决策,Richard 团队在接下来的八、九年里再也没遇到过任何 bug。
“我的项目听我的”
SQLite 基本上全都是 Richard 亲自动手开发的依赖项。除了 C 编译器和 libc 之类的现成方案,他甚至构建了自己的源代码控制系统和 bug 跟踪器。总之,Richard 的项目都由他来掌握。
“人们去背包旅行或徒步,表面上看是种自由,但实际上途中到底如何取决于他们的背包准备得是否充足。因此,他们讨论的自由其实就是自己到底为此付出了多少心力。”Richard 说道,“所以当我们编写自己的项目时,肯定可以享受其中的自由、不再受到其他人的约束。毕竟我们不依赖于不同供应商直接提供的现成方法。”
就像当初选择使用本来开源的 Berkeley DB 作为 SQLite v2 版本的存储引擎的话,当它被卖给甲骨文、成了双源专有模型后,本来理想的情况就变得相当被动。
SQLite 中的解析器生成器 Lemon 是多年之前 Richard 亲手编写的。“每当我需要一些无法从 Yacc 或者 GNU Bison 处获得的新型语言功能时,由于拥有对解析器生成器的掌控权,我可以随时调整 SQLite 的版本控制系统并做出自己想要的调整。”
他最初使用 CSV,因为 2000 年那会儿每个项目都在使用 CVS, 而进入 2000 年代中期后则需要更好的系统。Richard 先后研究了 Git、Mercurial,又回顾了自己的需求,突然发现“得自己写一个才行”。于是 Richard 编写了自己的版本控制系统,而现在它本身也成了独立的项目,而且效果非常好。
“因为是自己亲力亲为,所以它能够充分满足我的需求,可以跟一切原有、现有及未来将要出现的工作场景相契合。”Richard 说道,“这种自己动手方式能把命运把握在自己指尖,以摆脱第三方的方式真正拥抱自由。”
原文链接:
https://corecursive.com/066-sqlite-with-richard-hipp/