vatt'ghern jaskier's ballads
本文 1 個互動圖表在手機上以重點摘要呈現,互動版請以桌面瀏覽器開啟。

一個首頁寫著「Full ACID」的資料庫,測到最後一個候選版本,仍然會丟掉已經回報成功的寫入。

Full ACID 的資料庫,被找出 96 個問題

ParticleDB 是一套多模型資料庫,報告的開頭這樣介紹它:「ParticleDB is a multi-model database designed for AI workloads.」2026 年 10 月 31 日,Kyle Kingsbury 發表了 Jepsen 對它的測試報告,結論是首頁上的「Full ACID」宣稱「somewhat premature」。這份報告由 Orkes 出資,依 Jepsen 的倫理政策進行。它值得一讀的地方,不在於又有一套資料庫出了 bug,而在於 bug 的分布方式:大部分問題用不著任何故障注入,一台伺服器、一個 client 就能重現,而修了一輪又一輪之後,最後一個測試版本仍然掉資料。這兩件事要放在一起解釋,並不容易。

首頁寫著 Full ACID,報告列出 96 項問題

先看宣稱本身。報告引述 ParticleDB 的首頁:「Full ACID. 159K TPS.」首頁同時說這套系統經過 TLA+ 證明,報告的原話是 ParticleDB 的首頁宣稱它「formally proven」。接著報告補了一句:「However, during our collaboration no TLA+ specification was available.」合作期間,沒有任何 TLA+ 規格可以拿來對照。到了文件章節,報告又寫道:「The TLA+ proof was not published, and in any event did not prevent disaster.」證明沒有公開,就算有,也沒擋住問題。

首頁宣稱Full ACID. 159K TPS.
報告所見測試 1.1.4 至 1.1.18.11.rc-22,列出 96 項問題;結論是「somewhat premature」。
首頁宣稱formally proven(TLA+ 證明)
報告所見合作期間沒有 TLA+ 規格可用;證明沒有公開。
網站宣稱1087x faster than PostgreSQL
報告所見報告指出實測遠不及這個數字,且一小時的測試中吞吐量隨時間下降、延遲上升。
左欄是 ParticleDB 自己的說法,右欄是 Jepsen 報告的對應段落。第三列的實測描述來自報告的未來工作一節,本文只轉述方向,不引用數字。

測試環境也要先交代清楚,因為它決定了報告能說什麼、不能說什麼。Jepsen 在 Debian 13 的單一節點上跑 ParticleDB,容器與 EC2 虛擬機都有。報告寫明:「The builds Orkes provided did not support replication, so this report covers only single-node behavior.」Orkes 提供的版本不支援複寫,所以整份報告談的只是單機行為。測試工具可以殺掉 ParticleDB 行程、用 LazyFS 模擬未 fsync 的寫入遺失,也可以截斷或破壞磁碟檔案。交易模式涵蓋 fast、occ、zero-copy-occ、table-2pl,WAL 同步模式則有 sync、groupsync、nosync。

然後是第一個讓人停下來的數字。報告說:「We found 96 issues with ParticleDB」,緊接著是「All but three of these issues occurred in healthy, single-node instances of ParticleDB.」九十六項裡,只有三項不是出現在健康的單節點上。

93 項:健康的單一節點,無故障 3 項:出現在有故障的情況 一格代表一項問題,共 96 格。 哪三項是故障下的,圖上不指認, 以報告的說法為準。
96 格中,深色 93 格出現在健康的單節點上;亮色 3 格不是。報告沒有指認這三項是哪些。

如果你熟悉 Jepsen 以往的報告,這個比例本身就是異常。分散式資料庫的 bug 通常要靠網路分割、時鐘偏移、行程當機才引得出來,而這裡的多數問題連故障都不需要。同一份報告的另一個事實又把畫面弄複雜了:到 1.1.18.11.rc-22,報告寫的是「all but ten of those issues appeared resolved」,除了十項之外都已解決。九十三項不需故障的問題大多修好了,最後一個版本還在掉資料。三個說法可以拿來解釋這種局面,下面逐一檢驗。

報告摘要把問題放在兩端:一端是 pedestrian 的當機、死結與資料遺失,另一端是它稱為 piquant 的那些,原文列的是「partially-invisible rows which could not be deleted」和 WHERE 4 = 5,接著還有被丟棄後以變形樣貌重新出現的資料表、被搞混的欄位,以及變成整數的字串。這些在摘要裡只佔一行,卻最能說明問題的性質。一個 4 = 5 的等式比較竟然會回傳資料,表示查詢引擎連最基本的述詞求值都有漏洞;一批刪不掉、只有一部分看得見的列,則表示儲存層與查詢層對「這一列存不存在」的看法不一致。而報告同時說:「Most issues required just a single server, single client, and no faults.」合理的推測是,照文件開一個實例、寫幾筆資料的人,就有機會碰到其中一部分,不需要刻意設計的故障情境。

假說一:只是早期版本太粗糙,修完就好

這是最直覺的解釋,證據也確實站得住一半。早期版本的問題粗糙到令人意外。WHERE 4 = 5 會回傳主鍵為 5 的那一列(#18),因為 1.1.4 到 1.1.17 把任何等式比較都當成主鍵查詢,直到 1.1.18.4 才修。NOT NULL(#8)在 1.1.4 到 1.1.17 被忽略,1.1.18.4 才開始強制;UNIQUE(#9)一路被忽略到 1.1.18.4,1.1.18.6 才部分生效。巢狀 BEGIN(#44)從 1.1.4 到 1.1.18.9 都會洗掉外層交易的寫入,報告的說法是「Any writes performed by the enclosing transaction would be lost.」1.1.17 到 1.1.18.4 之間,被中止的交易寫入仍然留了下來(#43)。刪掉的資料表還會留下影子,報告寫道「it left a shadow of the table behind, whose rows would reappear in later tables with the same name」(#46),連浮點數都被改掉,18.83 變成 19。

這些問題幾乎都在報告記載的版本裡被修掉了。下面這張圖把報告裡有明確版本範圍的十三項放在同一條版本軸上,拖動滑桿可以看到某個版本還活著哪些問題。

拖動滑桿選擇版本檢查點 · 9 個版本 × 13 項問題

1.1.18.11.rc-22
1.1.4 1.1.15 1.1.17 1.1.18.4 1.1.18.9 rc-1 rc-7 rc-18 rc-22 #18 WHERE 4 = 5 #8 NOT NULL 被忽略 #9 UNIQUE 被忽略 #37 字串當 8 位元整數 #44 巢狀 BEGIN #47 浮點 WHERE 不匹配 #43 中止的交易仍寫入 #70 table-2pl 掉寫入 #73 G-single #110 掉已確認寫入 #107 殺行程後 Lost Update #108 WAL 位元翻轉 #112 WAL 區塊錯置 查詢與約束語意 交易與寫入遺失 磁碟損毀下的持久性 淡色 = 該版本沒有被記載

在 1.1.18.11.rc-22:13 項樣本中仍有 5 項被記載(交易 3、持久性 2、查詢語意 0)。

十三項是我從報告 96 項中挑出、版本範圍寫得明確的樣本,不是全部。橫條是報告記載的出現到修復範圍;#107、#108、#112 在 rc-22 之後的修復只是 Orkes 的說法,Jepsen 未測。

把滑桿從左拖到右,會看到一個明顯的位移:深色的查詢與約束問題在 1.1.18.9 之後就消失了,留下來的全是交易與持久性。這支持假說一的前半段,早期版本的確粗糙,而且大多被修掉了。但它同時顯示後半段不成立。報告的總結寫得很直接:「While 1.1.18.11.rc-22 was significantly safer than 1.1.4, we were still finding new issues.」比 1.1.4 安全得多,卻還在找到新問題。

還有一個定位上的爭議。Orkes 事後把 1.1.4 到 rc-22 稱為「unsupported pre-release builds」,並說這些交易模式是「experimental」。報告的回應是,測試當時的文件並沒有這樣寫,這個說法難以成立。合理的推測是,如果「早期版本」只是一個事後貼上的標籤,它就無法解釋為什麼首頁在測試期間同時掛著「Full ACID」。

這條版本軸的來歷也要交代。報告寫的是:「Orkes engaged Jepsen to test these versions of ParticleDB, beginning with 1.1.4.」委託從 1.1.4 就開始,所以版本序列同時是廠商在合作期間陸續出新版的紀錄。合理的推測是,圖上那些被「修掉」的問題,有不少是在 Jepsen 回報之後才處理的,而不是廠商在發佈前自己找到的;報告沒有逐項說明這一點,這裡只是從時間順序推出來的。資助的安排也是同一類背景:「This research was funded by Orkes, Inc., and conducted in accordance with the Jepsen ethics policy.」被測的一方出錢,報告用倫理政策這句話交代處理方式,讀者可以自己決定要給這個安排多少信任。至少從結論看不出被軟化,報告對已測版本的建議仍是停止部署並遷移。

於是假說一只能算部分成立:粗糙的問題是真的,也確實在減少。但一個「修完就好」的故事,需要最後一個版本是乾淨的,而它不是。

假說二:只有碰上故障才會掉資料

退一步,也許那些嚴重的問題都藏在故障裡,正常運作時資料庫是安全的。報告裡確實有幾項這類發現。WAL 位元翻轉(#108)的案例中,ParticleDB 發現資料檔已損毀,卻照樣啟動並繼續對 client 提供資料:「ParticleDB would discover that its data files were corrupt, then start up anyway, serving data to clients.」一次測試讀到的 44 個元素,在重新啟動之後消失了。把 .wal 檔的 13 個 4 KB 區塊洗亂(#112),rc-22 的反應是忘掉所有資料表,並且(報告用的字眼是 apparently)刪空 WAL。殺行程(#107)則在 rc-18 上引出內部異常、P4(Lost Update)與 G-single。

這些都是持久性的問題,也都是最容易讓人直覺判為「嚴重」的一類。不過數字說的是另一回事:三項。其餘九十三項發生在健康的單機上。更關鍵的是,不靠故障也能掉資料。#110 在 rc-18 到 rc-22 之間,報告的說法是 occ-v3、zero-copy-occ、table-2pl 與 serializable-ssi 都「would occasionally discard acknowledged writes」,也就是偶爾丟棄已經確認的寫入;一次測試中,大約兩萬個 key 有 31 個丟了寫入。預設的 occ 模式,報告的結論是「regularly lost data in normal operation」。

稀有程度也值得一提。新加的 serializable 模式「appeared significantly safer」,但仍然在正常運作下讓 stale read(#109)出現,報告說大約每 300,000 個交易一次,條件是約每秒 80 個交易、十個 client。照這個速率推算,大約是一個小時一次,這是我的換算,不是報告的數字。頻率低,並不等於要加故障才會出現。

假說二因此也只對一部分成立。故障確實放大傷害,但最後一個版本掉資料的主因,是平常運作下就會發生的事。

假說三:壞在某一個交易模式

摘要對預設模式的描述相當直接:「ParticleDB continued to lose committed writes during normal operation with the default `occ` transaction mode」,也就是直到最後的測試,預設的 occ 仍然在正常運作下丟掉已提交的寫入(#110)。對一個宣稱 Full ACID 的系統,預設值是多數使用者實際會跑的設定,這一點比任何選配模式的表現都重要。而第 1.1 節指出了另一個不利的事實:「the documentation did not explain what these modes actually guaranteed」,文件沒有說明這些模式究竟保證什麼。想主動換成更強模式的人,手上沒有可靠的依據可以判斷該換哪一個。這也是為什麼下面的矩陣只能照報告點名的模式來畫,而不能靠文件去補空白:文件本身就沒有把每個模式該擋掉哪些異常寫清楚。

還有一種可能:問題集中在某個實作得不好的模式,只要避開它就安全。這個假說在文件面上就有麻煩。報告指出,操作手冊把模式對應到一致性模型:occ-v3 對應 Snapshot Isolation,serializable-ssi 對應 Serializable,table-2pl 對應 Strong Serializable。但後來的文件說 occ-v3 和 strict-serializable 是「earlier names」,報告因此寫道:「It is not clear whether these modes were removed or simply renamed.」到了 rc-22,table-2pl 與 serializable-ssi 已經不在了。你想避開的那個模式,可能在下一版就換了名字,或者消失。

就算只看報告點名的案例,異常也不是落在單一模式上。

occ (預設) occ-v3 zero-copy -occ table-2pl serializable -ssi strict- serializable #70 掉已提交寫入(rc-1 至 rc-6) #73 G-single(rc-1 至 rc-22) #110 掉已確認寫入(rc-18 至 rc-22) #96 內部一致性異常(rc-9.2) #106 Read Skew(rc-19 修復) #109 stale read(rc-18) #107 殺行程後異常(rc-18)
實心圓表示報告把該問題歸在該模式;空心圓表示報告沒有點名,不代表那個模式安全。

#110 一列有五個實心圓:預設的 occ 加上另外四個模式都被點名。如果掉寫入只是某個模式的實作失誤,這一列不會長這樣。矩陣裡另一個值得看的是最後兩列,#109 與 #107 都落在 strict-serializable,那是 rc-18 才加入的新模式。

這裡要小心一個陷阱:空心圓不是證明。報告沒有點名某個模式,可能是沒測到,也可能是真的沒事。矩陣能支持的只有負面的結論,就是「只要避開某一個模式就安全」這個說法,在報告的證據下站不住。

剩下的解釋落在流程,但證據只到這裡

三個假說都被削掉一塊,剩下的問題變成:什麼樣的開發與品質流程,會同時產生粗糙的早期 bug、不斷冒出的新 bug,以及一份對不上實況的文件?報告在品質保證一節給了幾條線索。Orkes 說自己跑過 Jepsen 的 Postgres 測試框架,也用過 SQLancer;可是報告說,同一套框架一碰到 ParticleDB 1.1.4 就立刻失敗,幾乎每個被測的功能都出現基本錯誤。報告的說法是「Our findings suggest structural deficiencies in the ParticleDB QA process」,並以「Perhaps engineers entrusted Large Language Models with the work of testing.」推測測試工作可能交給了 LLM。

報告的下一節把話說得更完整,也更謹慎。它指出 LLM 讓小團隊能快速建出複雜的分散式 SQL 資料庫,但品質為此付出代價:ParticleDB 有許多正確性錯誤,工具還反覆宣稱修好了其實沒修好的東西。Orkes 能解釋大多數 Conductor 的 bug,卻似乎說不清楚幾乎每一項 ParticleDB 問題的成因與修法,新版本出現時也沒有 changelog。這些描述來自報告,歸因也屬於報告。報告沒有證明「使用 LLM」與「這些 bug」之間的因果,本文也不替它補上這一環;它提出的是一個需要被承認和緩解的取捨。

點選一種解釋,查看支持與不利的證據 · 4 種解釋

支持的證據

  • #18、#8、#9、#44 等查詢與約束問題在 1.1.18.9 之前就修掉。
  • 報告:到 rc-22,除了十項之外都已解決。

不利或未決

  • 報告:rc-22 仍在找到新問題;#110 在預設 occ 下規律掉資料。
  • 測試期間首頁仍寫著 Full ACID,文件沒有標示預發行。

部分成立:描述了趨勢,卻解釋不了最後一個版本。

互動圖表

四種解釋都只得到部分支持:早期粗糙解釋不了 rc-22 仍掉資料,故障論解釋不了正常運作下的丟寫入,單一模式論被矩陣推翻,流程論與 LLM 論缺少因果證據。

所以收斂的結果很有限。四種解釋裡,可以直接排除的是「只要避開某個模式」,因為 #110 一列五個實心圓擺在那裡。「早期版本粗糙」與「要有故障才壞」各解釋了一部分。流程與工具的解釋最貼近整體圖像:廣泛的基本錯誤、修復後又冒出新錯誤、文件與實況不一致。但這是「合理的推測」,而不是報告的發現,報告對這一點的語氣也一直是保留的。

效能宣稱也沒有撐住。報告記下的說法是 ParticleDB 自稱「1087x faster than PostgreSQL」,實測的結論是「In our tests ParticleDB was nowhere near this fast」,並且「over the course of an hour we observed a linear decline in throughput and a significant increase in median latencies」。吞吐量在一小時內線性下降、中位延遲明顯上升,這比單純的「不夠快」更值得留意,因為它描述的是速度隨執行時間惡化。報告在這一段沒有解釋原因,本文也不做推測。

把這些放回自己的選型,可以整理出幾個檢查點,這是本文的歸納,不是報告列出的清單:預設模式在獨立測試裡的表現、文件有沒有說明各模式保證什麼、宣稱的證明有沒有規格可看、測試涵蓋的是單機還是含複寫。ParticleDB 在這四點上依序是:預設 occ 掉已提交的寫入、文件沒有說明、合作期間沒有規格、複寫尚未測試。年輕的資料庫不必然都是這樣,但這四個問題,比首頁上的數字更容易在採用之前問清楚。

「除了十項之外都已解決」這個數字也要小心讀。原文用的字眼是 appeared resolved,意思是看起來已經解決,並非確認解決;報告同時說明 Jepsen 沒有評估 rc-22 之後的任何版本。所以這個數字是截至 rc-22 的觀察。至於剩下的十項是哪些,我讀到的報告段落沒有逐一列出,文中因此不點名,也不替它們編造清單。合理的推測是,「十項」只描述已知問題的存量,而不是之後不會再有新問題的保證,因為報告自己寫到 rc-22 時仍在找到新的問題,#112 就是在 rc-22 上才記錄到的。

還有一些問題報告自己就標成未解。複寫系統沒測過,報告寫的是「The replication system remains to be tested」;Orkes 提供的版本本來就不支援複寫。多數測試中資料表整個放在記憶體,磁碟儲存需要更多測試;Redis 與 HTTP API、時間與地理空間查詢、物化檢視、向量搜尋、多租戶也都沒碰。Python 與 Rust 的預存程序(Particles)正在加入,報告說值得調查。

最後是版本之後的事。Orkes 說 #109 在 1.1.19-rc.10 不再出現;#107、#108、#112 在 1.1.19-rc.12 已解決;#110 與 #73 則在 1.1.19-rc.13 修好。報告的說法是「Orkes claims that all issues from this report have been addressed as of version 1.1.19-rc.13」,並且明白寫下:「Jepsen has not evaluated versions of ParticleDB after 1.1.18.11.rc-22」。這些修復都沒有被獨立驗證,包括 #108 的「偵測位元翻轉並拒絕啟動」。報告對已測版本的使用者給的建議是停止部署、遷移到其他資料庫,並盡可能用更可靠的來源檢查或重建資料庫狀態,同時註明 Jepsen 無法證明沒有 bug。相關的當日摘要可以到今日 roundup 對照。

Take-away:看到資料庫宣稱 ACID,先查它被獨立測過的版本與模式,再確認預設模式是哪一個——在這份報告的 rc-22 上,掉資料的正是預設的 occ。