← 筆記

網格上線:任兩台消失,備份完好

2026 年 8 月 16 日 · 打造 Recilic 的筆記

Recilic 0.3.0 已經發佈:你的加密分片現在可以散佈在你擁有的 Mac 之間,支援五種語言。走到這一步的過程中,我們發現網格已經以六分之五的能力運作了兩天——而這段期間的每一次備份都回報了成功。

Recilic 的即時網格檢視:一台 MacBook 連接到七個儲存節點

八台機器,然後剩六台

測試用的網格有八個節點:這台 MacBook、一台 Mac mini,以及六台原本閒置在家裡的小機器。備份時,每個區塊會被分成 4+2 個分片,分發到六個不同的節點,因此任何兩台消失,資料仍然完整。

8 月 12 日,在同一秒鐘,所有那些小節點停止了自我廣播:

thread 'mDNS_daemon' panicked: index out of bounds:
the len is 278 but the index is 278

網路上某個裝置發出的一個格式錯誤的封包——可能是印表機、電視,誰知道——觸發了探索程式庫中的解析臭蟲,同時在每個節點上終結了那個執行緒。不是整個程序,只是回答「我在這裡」的那個執行緒。

於是每個節點繼續接受連線。每個節點繼續向自己的監控程式回報正常。而每個節點對決定分片去向的 app 而言都變成了隱形,因為那個決定是根據它能探索到什麼來做的。六個目的地中有五個悄悄地從此後每次備份中消失了兩天,而那些備份每一次都完成並說成功

本該令人難堪的部分

值得精確說明為什麼沒有人注意到。不是因為訊號微弱:而是因為根本沒有訊號。App 擁有它需要知道的一切——昨天它還看到六個節點,今天只有五個,而它對此沒有任何看法。

備份軟體的全部工作就是讓人日後相信它。「已完成」是世界上最容易回報的東西,也是最不值得信任的。

姊妹臭蟲,燃燒一個核心

在小節點沉默的同時,Mac mini 上的儲存節點 CPU 被釘在 97%——持續了五天,其中三十五小時花在核心裡面,什麼事也沒做。那台機器有四十四個網路介面:幾個真實的,加上二十個累積的 VPN 通道和 Apple 的點對點介面。探索程式庫對每一個介面都綁定了一個 socket——其中三十七個在多播埠上,相比 Linux 機器上只有三個——而其中一個 socket 就足以讓它的輪詢迴圈永遠旋轉下去。

這兩個錯誤都已在上游版本中修復,只是我們還沒更新。升級到目前的版本不需要改動任何程式碼,讓那台機器的 socket 從三十七個降到四個,CPU 從 97% 降到幾乎為零。

發佈的不是聳肩

升級相依套件修復了這個特定的事故。但它對設計缺陷毫無幫助,那個缺陷就是沒有任何東西在監看。三件事被加了進去:

節點現在會道別。一個被停止或重啟的儲存節點在結束前會撤回它的廣播。從 Mac 端測量:節點從探索中消失的時間是 1.3 秒,而不是在快取中停留長達一小時。一個被強制終止的節點——斷電、崩潰——顯然無法說任何東西,這就是為什麼還有:

Mac 在規劃前會先確認。每個目的地在備份決定佈局之前,都會被直接、平行地檢查。快取的探索記錄不再被當作一台機器仍在那裡的證據。這比預期更重要:在此之前,一個已經離開的節點不只是被跳過——它會讓整個備份失敗,因為分片仍然被寄往一個已經不存在的 socket。以前關掉一台機器就會中斷下一次備份。

而且它現在報告的是後果,不是事件。當一次備份能連到的節點比上一次少時,Recilic 會告訴你——並且告訴你代價是什麼:

⚠︎ 已到達 5/6 個節點 — 可承受的節點遺失數從 2 降至 1:p1

「一個節點離線了」不會幫到任何人。你的資料是否仍然安全是另一個問題,而且有精確的答案:六個分片分佈在五台機器上,表示其中一台持有兩個分片,因此失去那一台就會讓你恰好處在還原門檻,沒有餘裕。這才是值得印出來的那句話。當一個節點只是被另一個替換而容忍度不變時,它會如實告知,而不會大喊降級。

修復裡的臭蟲

那個警告的第一個版本從未觸發過。一個節點被停止,備份正確地排除了它並將其分片移到別處,而摘要什麼都沒說。

世代儲存庫以最新優先的順序回傳列表,而程式碼取了列表的末尾作為「上一次備份」——也就是最舊的那個,來自這個網格存在之前,其單一節點是今天的子集。於是檢查盡責地將現在與時間起點做比較,發現沒有問題。每個單元測試都通過了,因為它們測的是比較邏輯而不是比較對象的選擇。

一個看起來跟正確答案一模一樣的錯誤答案。選擇前一代現在屬於儲存庫的職責,因為只有它知道自己的提交順序,而覆蓋這個邏輯的測試是透過重新引入臭蟲並看著它失敗來驗證的——這是相信一個測試的唯一理由。

仍然成立的事

這兩個修復都發生在起飛之前。一台在備份開始時確實在場、卻在進行到 60% 時消失的機器——螢幕蓋上、電源排插關掉——仍然會讓那個世代失敗,而不是用五個分片完成然後告訴你。資料是安全的;程式碼比數學更嚴格。這個問題已記錄為 issue 16,是下一步。

0.3.0

除了網格的改進:相同的內容現在只儲存一次,因此對未變更檔案的第二次備份不會傳輸任何東西,而被中斷的備份會從已經傳完的部分繼續。介面支援英文、繁體中文、簡體中文、日文和韓文。App 現在也在整個歐盟銷售,這需要通過它自己的商家身份審查。

眼尖的讀者也許已經注意到截圖:八個節點裡有六個不是 Mac,而是 Raspberry Pi 5 和 Intel N100 這類迷你主機。上面跑的是與 app 並行開發、以 Rust 寫成的純儲存節點——只保存密文、回應持有證明,除此之外什麼都不做。它從合併那天起就一直撐著家裡這張網格;我們正在評估最合適的發布方式。0.3.0 不依賴它——app 單獨就是完整的。

還原演練仍然走完整個流程——讀取、解碼、解密、驗證——因為一個你從未還原過的備份只是一個假說。

Recilic,Mac App Store · $29.99,無訂閱制。