領導者選舉(leader election)
許多分散式任務只要「恰好有一個節點在主導」就會簡單得多——一個協調者來發放鎖、一個節點來決定更新的順序、一個地方來打破平手。但你不能就這麼指派一個永久的老大,因為在分散式系統裡,老大隨時可能當掉(部分失效)。領導者選舉就是這樣一套程序:一群平等的節點,在現任領導者失效後或在啟動時,自動地、在沒有任何中央權威的情況下,對「由它們之中的哪一個來當新領導者」取得共識。
一個簡單而經典的例子是霸凌(Bully)演算法。每個節點都有一個唯一的 id 編號,規則是「最大的 id 獲勝」。當某個節點察覺領導者沒有回應時,它向所有 id 比自己大的節點送出選舉訊息。如果它們都沒回答(它們也掛了),它就宣告自己是領導者、並向所有人公告。如果有一個 id 較大的節點回答了,那個節點就以同樣方式接手這場選舉,最終讓「還活著的最大 id」成為贏家——它把較小的那些霸凌到一邊去。其他演算法(例如環形演算法)則改成讓一個訊息繞著一個邏輯環傳遞。不論方法為何,目標都一樣:以「所有人對同一個領導者取得共識」收場。
為什麼重要,以及微妙的危險:領導者選舉是讓「以協調者為核心」的設計在協調者死掉時仍能存活的復原機制——它出現在 Raft 這類共識系統裡、出現在叢集管理器裡、出現在分散式資料庫裡。經典的陷阱是腦裂(split-brain):如果網路分裂了,兩半可能各自認為舊領導者沒了、各自選出自己的領導者,最後落得兩個互相不一致、把共享狀態弄壞的領導者。這正是為什麼穩健的選舉通常要求一個多數(一個法定人數/quorum)對新領導者取得同意——少數那一側根本選不出領導者,這以犧牲那一側的可用性為代價、換來系統的安全。
五個資料庫副本的 id 是 1 到 5;節點 5 是領導者。節點 5 當機了。節點 3 察覺到,向 4 和 5 送出選舉訊息;4 回覆並接手,卻得不到 5 的回覆,於是節點 4 宣告自己是領導者、並通知所有人。這個群組現在又有了一個取得共識的單一領導者,全程不需人為介入。
領導者死後,倖存者自動對一個新的取得共識。當心同時選出兩個(腦裂)。
危險的失效是腦裂:一個網路分裂讓兩個子群組各自選出一個領導者。要求一個多數法定人數可防止這件事——少數永遠湊不出一個領導者,於是絕不會出現超過一個。