DDIA 導讀 CH 6 — 複寫 (下)

2026年10月12日

💎 加入 E+ 會員方案 與超過千位工程師一同在社群成長,並獲得更多深度的軟體前後端學習資源

DDIA 導讀 CH 6 — 複寫 (上) 中討論了資料系統中的複寫概念,以及單主節點複寫這個最基本的複寫架構。在 DDIA 第六章的後半段,作者進一步討論了多主節點 (multi-leader replication) 與無主節點 (leaderless replication) 的複寫方式。

多主節點複寫

單主節點複寫的主要缺點之一,是所有的寫入都需要透過單一的主節點;這導致如果該主節點發生故障或無法連線,就無法寫入任何新內容到資料庫中。試想,假如今天在亞洲的副本資料庫運作良好,但因為在美洲的主資料庫連不上,這時就會變得明明眼前的資料庫沒事,結果卻無法寫入的尷尬情況。

這個狀況也是多主節點複寫會出現的原因之一,只有一個主資料庫時,可能會因為單一節點問題卡住,那麼如果多幾個能接受寫入的節點,也許就能夠解決這個問題。

簡化來說,單主節點複寫是像這樣:

寫入 → 只能進主資料庫

讀取 → 可以讀主庫或從庫

對比起來,多主節點複寫則會是這樣:

寫入 → 可以進主資料庫 A,也可以進主資料庫 B,也可以進主資料庫 C

讀取 → 也可以從這些節點讀

每個能接受寫入的節點,都可以算是主資料庫;當某個主資料庫收到寫入請求後,會再把變更同步到其他的主資料庫。因此,從定義上來看,某個主資料庫同時也會作為副本資料庫存在。

特別注意,從架構上來看,通常多區域部署的系統中,每個區域會有一個主資料庫,搭配多個只能讀不能寫的副本資料庫。這是因為,這時用這種架構會讓整體的複雜度比較低。因此,通常會是由區域的主資料庫,去同步其他區域的主資料庫,然後再回來把變更同步到區域內的副本資料庫。

image

多主節點複寫的優點

對比起單主節點複寫,多主節點複寫有多個優點。第一個是效能會比較好。如果只有單主節點,跨區域的寫入會要經過比較長的網路傳輸,例如某個在台灣的寫入請求,要傳送給在美國的主資料庫,因為物理距離比較長,延遲會因而提升。然而,如果在亞洲區就有一個主資料庫,在台灣的寫入請求不用發給美洲區的,而是就近發給亞洲區的主資料庫,延遲能被降低。

第二個優點是對於故障的容忍比較高。在單主節點的模式下,如果主資料庫所在的區域出事故,系統必須要做跨地區的故障轉移,把另一個地區的副本資料庫升為主資料庫,這個過程會比較複雜。對比之下,在多主節點的模式下,如果某個區域故障,其他區域的主節點仍能繼續接受寫入,因此整個系統不一定會像單主節點架構一樣停止寫入。這種系統韌性對於要求高可用性的場景,會特別有價值。

第三個優點是對跨區域網路故障的容忍能力比較高。在單主節點架構下,跨地區網路會比較敏感,當其他地區使用者想要寫入時,需要跨區域找到主資料庫;而因為跨區的緣故,在傳輸上會經過比較長的路徑,也因此可能比較容易遇到問題。多主節點雖然仍有跨區的同步,但主要會出現在跨區域主節點之間的同步上,副本節點在跟主節點同步時,因為是留在同一區域,所以同步上相對來說不會那麼敏感。

多主節點複寫的難題

雖然上面談到多主節點複寫有許多優點,但是在實務上也有不可避免的難題,其中「一致性」是最大的挑戰。

書中提到銀行轉帳的例子,假如今天某個帳戶中有 100 元,在 A 地與 B 地都有主資料庫;因為複製會有延遲,A 地與 B 地在當下看到餘額都是 100 元。這時,如果兩個地方都有提款 80 元的寫入,就可能出現主資料庫 A 覺得沒問題,因為 80 小於 100;主資料庫 B 也有同樣的判斷,所以沒問題。

這時雖然兩邊都沒問題,但如果合在一起,兩筆寫入就會變成 100 - 80 - 80 也就是 -60,這個不合理的結果。甚至 -60 也不一定是最終結果 (如果採用最後寫入者勝出的衝突解決機制),但這邊的重點在於系統讓兩筆 80 的寫入都成立 (但實際不應該如此)。

如果要避免衝突,就需要在寫入時有一個協調機制進行跨區域的溝通;然而,有跨區域的溝通就代表延遲需要增加。由於這種問題是分散式系統的基本限制,如果想要選擇多主節點複寫,不能不面對。因此,在實務上做工程決策時,需要回過頭來問對眼前的系統來說,什麼最重要? 是低延遲比較重要,還是跨地區一致性比較重要?

在實務上,如果某個場景需要有強制的全域一致性,就相對不適合選擇多主節點複寫。例如上面提到的銀行帳戶餘額不能為負,或者在電商中的庫存不能為負,又或是搶票系統中一張票不能被多個人買,這些場景在多主節點複寫下,如果出現不一致,通常成本會高於獲得的好處。

多主節點複寫如何同步資料?

在了解多主節點複寫的優點與難題後,書中進一步談了這個模式下,如何同步資料。在書中使用「複寫拓撲 Replication Topology」這個詞,所謂的拓撲是指變更在節點之間如何傳播。常見的多主節點拓撲方式包含全對全 (all-to-all)、環狀 (circular)、星狀 (star),其中又屬全對全的方式最為通用。

image

從上圖中可以看到,全對全的方式,是每個主資料庫,會把寫入直接傳給其他主資料庫,這樣的做法好處是整體系統容錯率高。因為每個節點之間有直接路徑,所以如果某一條節點間的連線出問題,其他節點仍是通的,不會被卡住。

但全對全的節點連線數跟複雜度都比較高,每個節點要管理的同步對象比較多。除此之外,也會遇到資料同步順序的問題。因為不同的主資料庫通常在不同區域,網路傳輸的時間會因此不同,這就可能導致客戶端對主資料庫 A 寫入新資料,然後客戶端再對主資料庫 B 更新該筆資料,結果因為主資料庫 B 還沒同步到該筆資料,所以出現先更新後新增的因果顛倒問題。

環狀拓撲則是每個節點只會把變更同步到下一個節點。對比起全對全,這種方式的複雜度低很多,每個節點只需跟前一個節點與下一個節點溝通。只是如果今天某個節點出事故,在拓撲尚未重新配置以前,整個環就斷掉,後面的節點都會收不到前面的變更。從系統的角度來看,這種做法相對比較脆弱。

星狀拓撲則是有一個中心節點,不管哪個節點有變更,都先同步到中心節點,再由中心節點把變更轉發出去。這種做法下,除了中心節點以外的節點,複雜度都比較低,只需要管理跟中心節點的溝通即可。但如果中心節點故障,而且系統沒有立即完成故障轉移,整個系統的變更同步就會卡住;換言之,這種做法存在單點故障 (single point of failure) 的風險。

在上面的討論中可以看到,在不同的拓撲方式選擇中,會有分散式系統常見的取捨。當選擇越簡單的方式 (例如環狀拓撲),管理成本會越低,但是故障出問題時會沒有替代路徑;反之,選擇對於故障容錯率高的方案,管理的複雜度也會更高。

備註:在這個章節,作者有進一步討論多主節點複寫在衝突解決上的細節,包含 CRDT 等概念。由於篇幅關係,加上我們先前在 本地優先 (local-first) 的軟體設計 與 後端系統設計 — 設計即時共編文件系統 (Collaborative Editor) 有談過類似概念,這篇摘要不會討論那部分,推薦可以回顧先前的主題文,或者實際讀《DDIA》在這部分的解說。

後半篇將進一步介紹無主節點複寫 (leaderless replication),這部分內容僅供 E+ 會員 閱讀。


加入 E+ 會員方案

如果你覺得這篇分享有幫助,想閱讀更深入的內容,歡迎加入 E+ 會員。除了有會員專屬的深度文與影片,探討前後端開發、AI 工程、職涯發展,同時有 Discord 社群一同交流與成長。

許多 E+ 會員透過所任職公司的教育訓練補助 (E+ 會開立有統編的發票),不用花自己的錢,也能每週透過深度主題文與社群交流,拓展技術視野、加速職涯成長。

🧵 如果你想收到最即時的內容更新,可以在 Facebook、Instagram 上追蹤我們