去年年底,Tailscale 的 uptime开始变得不稳定。19 次独立的数据库损坏事件,横跨六个月——每次都是同一个 SQLite bug 在作祟。
Tailscale 控制平面内部用 SQLite 存储每个 tailnet 的配置元数据。每个 shard 由一个 Go 进程独占访问数据库,这是 SQLite 推荐的单写入者架构。他们从 2022 年就开始用这套方案,一直相安无事。
直到 2025 年 8 月,一个读取 S3 备份的数据管道报了错。运行 PRAGMA integrity_check 后发现数据库确实损坏了。修复了,查了原因,没找到。然后它又发生了。再来一次。再来一次。

“这个 bug 抵御了我们所有的初步排查。” Tailscale 团队检查了所有近来改动——没有相关的。重新审查了所有 SQLite 交互代码——没发现问题。损坏事件之间没有共同因素:不是同一个 shard,不是同一个客户,不是同一个功能,不是同一个时间段,不是同一个负载水平。
无法复现,只能靠被动遥测。有时几小时一次,有时几周一次。最长的一次平静期是六周——然后就又来了。
最终,Tailscale 资助了一个开源的 SQLite VFS shim 来隔离竞态条件。这个工具帮助他们定位到了 SQLite 中一个存在了 16 年的 WAL-reset 数据竞争 bug。更意外的是,在修复过程中还发现了第二个 bug:一个陈旧的表达式索引 bug。
Antithesis(一个确定性模拟测试平台)随后也发表了一篇博客,详细分析了这个 WAL-reset bug 的技术细节,包括如何在确定性环境下复现它。

HN 上的讨论集中在几个点上。有人赞赏 Tailscale 的透明度——“把这种事公开写出来需要勇气。” 有人对 SQLite 有 16 年的 bug 感到惊讶,但更多人指出这恰恰证明了 SQLite 的可靠性:如此罕见的竞态条件,在如此大规模部署下才暴露出来。还有人讨论了 Tailscale 资助开源调试工具的做法——“这是公司资助开源的绝佳范例。”
参考来源: