去年8月到今年上半年,Tailscale的状态页断断续续亮了六个月。背后是同一个原因反复发作:公司控制面里的SQLite数据库莫名其妙损坏,一共出了19次,每次都要停机修数据库。8月12日,Tailscale发博客说,他们终于把这事儿查到底了——根子是SQLite内部一个存在16年的缺陷,跟WAL(write-ahead log)的重置逻辑有关。

这事有意思的地方不在于"又一起线上事故",而在于它咬的是SQLite。这是被苹果、安卓、无数嵌入式系统和云基础设施用了近二十年的数据库引擎,业内一贯的评价是"无聊但可靠"。无聊到几乎没人觉得它核心逻辑里还能藏着没被发现的漏洞。

六个月,19次故障,用户看到的是什么

Tailscale的控制面按租户(tailnet)拆成多个内部shard,每个shard由单个Go进程独占访问一个SQLite数据库——这正是SQLite官方推荐的单写者用法,不是什么野路子架构。公司从2022年开始用SQLite,备份管道从2023年初起每几分钟做一次快照,一直平稳运行到去年8月,数据管道第一次报错说某个备份损坏了。

这场故障留下的三个数字 19 次独立损坏事件 6个月+ 从首次报错到定位根因 16年 Tailscale称缺陷已存在时长

对用户来说,损坏本身伤不到隐私——SQLite数据库里存的是租户的配置元数据,新加的设备、改过的权限,不涉及私钥和网络流量。但每次损坏都得停机修复,早期恢复要一个多小时。已经在线的设备之间还能互联,但学不到网络变更;新上线的设备直接连不上,Web控制台和API也会跟着断。多数shard和租户从没被波及,可状态页上的全局事件挂出来,照样让没受影响的人也觉得这家公司"最近不太稳"。

一场没有指纹的追凶

排查的难点在于这个bug没有规律。不挑shard,不挑客户,不挑负载高低,有时事故隔几小时一次,有时隔几周才来一次。Tailscale把最近改动、老代码全翻了一遍,没找到问题;想复现,连触发条件都摸不着,只能在生产环境里挂满取证用的诊断代码,守着等它自己发作。

  • 风险.损坏没有固定触发条件,意味着传统的"复现—修复—验证"闭环根本跑不起来,只能靠被动蹲守和事后拆解,这也是六个月才定位问题的直接原因。

Tailscale后来找了SQLite官方的付费技术支持,双方一起排了几个嫌疑:POSIX锁被意外释放、SQLite管理的内存被误用、多线程访问违反了线程安全设定。一个个排除,始终没撞上真正的元凶,直到工程师做了一件"不得已"的事——给数据库搭了一条事务日志管道,把每一条修改语句单独记下来,万一数据库再损坏,就靠重放日志恢复,不用回滚到旧备份丢数据。

这条管道意外成了破案关键。有两次,日志重放不干净——某个事务明明提交成功了,写进去的数据却对后续事务"隐身",既不报错也不留痕。这在SQLite的设计里本该是不可能发生的事:它是单写者、可串行化事务的数据库,历史应该是完全线性、可确定重放的。

一次写入悄悄消失,连报错都没有——这在SQLite的设计里本该不可能。

顺着这条线,怀疑落到了checkpoint(检查点)——SQLite把WAL文件里的新页面写回主数据库文件的过程。监控数据显示,故障期间SQLite"报告"从WAL文件里拷贝的页数,比WAL文件里实际存在的页数还多。WAL里明明只有10页,checkpoint却说自己拷了20页。SQLite的开发者专门做了一个叫tmstmpvfs的调试外壳,包在文件系统层外面,给checkpoint过程加了追踪日志,才把这条线一步步理清。

追凶路径:五步逼近checkpoint 完整性检查 报错损坏 排除线程/ 内存假设 事务重放 发现异常 checkpoint 页数超标 锁定 WAL重置

"16年缺陷"这个说法,谁来担保

到这里,信息交付已经完成——但有一个缺口需要说清楚。Tailscale博客里没有给出具体的SQLite版本区间、没有指向任何一条上游commit,也没有链接到SQLite官方论坛的确认帖。目前公开渠道能查到的,只有Tailscale自己这一份陈述。

这不是说他们在编故事——他们花了六个月、拉了SQLite官方的付费支持团队一起排查,取证链条相当扎实。但"16年"这个数字目前只是单方叙述,还没有变成一份可以被第三方复核的公告或补丁记录。凑巧的是,SQLite的WAL模式差不多也是十几年前引入的核心特性,如果缺陷真的和WAL重置逻辑绑在一起,"16年"这个年头对得上WAL的年纪——但这只是逻辑上说得通,不等于证据。

  • 结论.一份详尽的事故复盘,如果缺了上游的独立确认,就只能算"高度可信的单方陈述",还不是行业级的安全通告。

我更在意的是这件事对其他公司的提醒。凡是拿SQLite做单写者、大规模生产部署的团队——不管是CLI工具、边缘计算,还是别的什么控制面——都该把这篇博客当一次免费的压力测试报告来读:"无聊技术"不等于零风险,规模足够大,再小概率的缺陷也会在你身上兑现。孔子说"人无远虑,必有近忧",放在系统工程里倒过来也成立:没查到的远虑,总会变成半年内接踵而至的近忧。

接下来真正值得盯的,不是Tailscale后续故障率有没有降下来——公司自己有动力把这条曲线画好看,这一点不用怀疑。该盯的是SQLite官方是否会就此发一条changelog或补丁说明,把"16年缺陷"这件事从Tailscale的一家之言,变成整个生态都能引用的公开记录。这一步补上之前,这场六个月的追凶故事,严格说还没有真正结案。