Techapple.com
新聞技術詳解

Tailscale 追查 16 年 SQLite 隱藏 Bug:WAL-Reset 數據競態令資料庫反覆損毀

網絡服務商 Tailscale 公開了一次歷時半年的資料庫故障調查,最終在 SQLite 核心程式碼中找出一個估計存在至少 16 年的隱藏錯誤,並命名為「WAL-Reset bug」。該錯誤屬於檢查點(checkpoint)與寫入交易之間的罕見數據競態,會令部分頁面在沒有錯誤提示下永久遺失,造成資料庫損毀。Tailscale 在六個月內遭遇 19 次資料庫損毀,最終與 SQLite 開發團隊合作鎖定並修復問題。

重點一覽

  • Tailscale 六個月內經歷 19 次 SQLite 資料庫損毀,原因指向一個存在至少 16 年的隱藏錯誤
  • 錯誤屬檢查點與寫入交易之間的數據競態,部分頁面被誤認為已寫入而永久遺失
  • SQLite 開發團隊命名為「WAL-Reset bug」,因罕見程度需要刻意加入觸發條件才能在測試中重現
  • 修復隨 SQLite 3.51.3 發佈,部署後 Tailscale 連續四個月無資料庫事故

半年 19 次損毀

Tailscale 自 2022 年起以 SQLite 作為主要資料庫,每個協調伺服器分片(shard)由單一 Go 程序獨佔存取,屬 SQLite 的標準用法。2025 年 8 月起,備份讀取管道開始報告資料庫錯誤,PRAGMA integrity_check 確認資料庫確實損毀。團隊起初無法找到共同觸發條件,亦無法在測試環境重現,只能在生產環境部署被動式監測工具蒐集診斷資料。六個月內,團隊共處理 19 次獨立損毀事件。

交易記錄管線的線索

為縮短恢復時間,Tailscale 建立了交易記錄管道,將每個修改資料庫的 SQL 語句串流到獨立記錄檔。這套系統意外揭露關鍵線索:有兩次事件中,交易記錄無法完整重播,一個已經提交的寫入在後續交易中竟然「消失」,而系統完全沒有回報錯誤。這在單一寫入者的 SQLite 架構中理論上不應該發生。

WAL-Reset bug

Tailscale 與 SQLite 開發團隊合作,後者為此建立了一個虛擬檔案系統層的除錯工具(tmstmpvfs shim),成功鎖定根因:檢查點程序與寫入交易之間存在罕見的數據競態。當寫入發生在檢查點的特定時刻,檢查點會誤以為部分頁面已從 WAL 記錄複製到主資料庫檔案,但實際上並未複製,導致這些頁面的資料永久遺失,資料庫隨之損毀。SQLite 團隊估計此錯誤已存在至少 16 年,由於太罕見,需要在測試環境刻意加入觸發條件才能重現。修復方式是為檢查點函數加入額外檢查,偵測 WAL 被另一個執行緒重設的情況。

修復過程與教訓

修復最初隨 SQLite 3.52.0 發佈,但該版本同時引入另一個與過期表達式索引相關的錯誤,造成誤報損毀,版本其後被撤回,改為發佈僅包含 WAL-Reset 修復的 3.51.3。Tailscale 部署修復後兩個月,專為偵測此競態而加入的警告終於觸發,證實該錯誤確實存在於其生產環境;此後連續四個月再無資料庫事故。Tailscale 在文章中總結,以非標準方式運行「沉悶但可靠」的技術本身存在風險,團隊手動控制檢查點程序並以進取速度執行,偏離了最常被驗證的運行路徑。

資料來源:Tailscale Blog

TechApple.com 編輯部

堅持製作專業科技內容,全員擁有多種不同技術知識的特異科技媒體團隊。 電郵:editor@techapple.com