本文為 Design Data Intensive Applications 的書摘 + 個人心得。
Multi-Leader Replication
在 leader-base (Leaders and Followers) 的架構下有個主要的缺點,就是只有一個 leader,所有的寫入必須通過它,當你不能連到它時就代表你不能寫資料到資料庫裡了,既然這樣,會有自然的想法是:多建幾個 leader 不就行了?Replication 依舊會發生,我們稱這為 multi-leader replication (也稱為 master/master 或 active/active replication),每一個 leader 同時也是 follower 。
Use Cases for Multi-Leader Replication
這裡首先要強調的是,再單一一個資料中心搞 multi-leader 設定非常罕見,因為 multi-leader 帶來的好處遠低於額外增加的複雜性,但還是有些場景適合使用。
Multi-datacenter operation
想像一下你在多個地區有資料中心,user 在使用時能選擇就近的資料中心來讀寫 (降低 Latency ),每一個資料中心都是基本的 leader-base replication,其設定如下圖:
讓我們比較一下 leader-base 和 multi-leader 的差別吧:
Performance
寫入到 local 的資料中心就是會比不知道在哪的資料中心快,multi-leader 的 performance 或許會比較好。
Tolerance of data center outages
可容許資料中心掛掉,在 leader-base 設定下必須等到 failover 後才能再次做寫入,再 multi-leader 設定下可由別的資料中心接手,當壞掉資料中心上線後會自行完成 catch up。
Tolerance of network problems
跟上面那點類似,leader-base 對網路的問題較敏感。
雖然 multi-leader 有以上這些好處,但它有個很大的缺點就是如果有 2 個人同時修改資料然後造成寫入衝突,這個一會講;另外還有一個要留意的小陷阱就是有些資料庫的功能會無法正常作用,例如自動跳號的 key、 triggers 和欄位限制。
Clients with offline operation
一個適合使用 multi-leader 的場景就是你的應用軟體可能會在無網路的狀況下工作。
舉例來說,想像一下有一個行事曆的 app 會在你的桌機、iPad、筆電、手機上執行,不管在有無網路的情況下你都能在這個 app 安排行程 (製造寫入的 request),所以在每次有網路時,你得跟 server 和其他裝置做同步。
在這個例子下,每一個裝置都可視為一個 leader (負責處理寫入需求),然後它會執行 asynchronous (非同步) multi-leader replication 進程 (做各裝置的同步),這個 replication lag 可能會長達幾天之久。
Collaborative editing
另一個場景是協同編輯,就是工作常用到的 Google Docs 啦!這裡可以想像每個 user 的瀏覽器都是 leader,然後你得跟其他 leader 跟 server 做 replication,所以怎麼解決資料衝突是必須的,如果你想保證資料不衝突,每個人都得等前一個人編輯完文件才行 (鎖住文件),這樣挺蠢的。
Handling Write Conflicts
下圖為一個資料衝突的例子,User 1 和 User 2 都在同時編輯 wiki 頁面。
Conflict avoidance
最棒的解衝突方式就是避免它!
例如上面那個 wiki 例子,若我們知道 User 1 和 User 2 都是來自同一個地區,我們可以將他們導到同一個資料中心,因為只有一個 leader 所以也就沒有痛苦的衝突了。
Converging toward a consistent state
但該面對的總是要面對,在 leader-base 設定中,資料的寫入是有一定順序的,但在 multi-leader 可能就不會這麼清楚,因為對每個資料中心來說,他們的順序都是對的,因為所有的 replica 最終要趨於一致,所以我們就來介紹幾個簡單的解衝突方式吧:
- 給每一個寫入一個獨特的 ID,例如 UUID, timestamp, 長的隨機數, hash 值等等,然後挑個最大值來用,捨棄其他的值,這個技巧稱為 last write wins (LWW) ,LWW 容易造成資料遺失,我們在之後會做更詳細的介紹。
- 給每一個 replica 獨特的 ID,然後做跟上面一樣的事,但這可能會造成更大的資料遺失。
- 合併衝突的資料,如圖 5-7 就把值合併為 B/C。
- 記錄衝突的資料點,然後儲存起來,之後某個時間點用客製的程式解衝突,或者跳出視窗叫 user 解。
Multi-Leader Replication Topologies
下圖的 [c] all-to-all topology 是最常被使用的 replication topology,不同的資料庫支援的程度不同,像 MySQL 預設是支援 [a] circular topology。
Circular 和 Star topology 最大的問題就是當一個 leader 壞掉時,會造成其他節點間的 replication 訊息中斷,所以像 All-to-all 那樣緊湊的連線就能避免此問題發生。
但 All-to-all 還是有他的缺點,如下圖:
我們的 update 是依賴於 insert 後的資料,Leader 2 接收資料的順序有誤,所以發生問題,這個問題類似 Leaders and Followers 提過的 Consistent Prefix Reads;為了解這個問題,我們可以使用稱為 version vectors 的技巧,這個我們在之後的 Leaderless 中會說明。