天天看點

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

作者:CSDN

【CSDN 編者按】Meta運作着世界上最大規模的MySQL部署之一。該部署驅動着社交圖譜以及許多其他服務,如消息、廣告和動态。在過去幾年中,他們實施了MySQL Raft,這是一個與MySQL內建的Raft共識引擎,用于建構複制狀态機。目前已大部分部署遷移至MySQL Raft,并計劃完全用其替代目前的MySQL半同步複制。

原文連結:https://engineering.fb.com/2023/05/16/data-infrastructure/mysql-raft-meta/

未經授權,禁止轉載!

作者 | Anirban Rahut、Abhinav Sharma、Yichen Shen、Ahsanul Haque翻譯 | ChatGPT 責編 | 夢依丹出品 | CSDN(ID:CSDNnews)

MySQL Raft是MySQL資料庫中一種基于Raft協定的分布式一緻性複制機制。近日,Meta技術團隊分享了他們基于Raft協定在資料庫基礎設施方面的實踐與創新,并打算取代當下使用的MySQL半同步資料庫(原文是用semisynchronous databases)。本文借助ChatGPT,進行了編譯整理。

Meta運作着世界上最大規模的MySQL部署之一。該部署驅動着社交圖譜以及許多其他服務,如消息、廣告和動态。在過去幾年中,他們實施了MySQL Raft,這是一個與MySQL內建的Raft共識引擎,用于建構複制狀态機。目前已大部分部署遷移至MySQL Raft,并計劃完全用其替代目前的MySQL半同步複制。這也給Meta的MySQL部署帶來了顯著的成效,包括更高的可靠性、可證明的安全性、故障轉移時間的顯著改善以及操作簡便性,同時具有相等或可比較的寫入性能。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

遷移背景

為了實作高可用性、容錯性和讀取擴充性,Meta的MySQL資料存儲是一個大規模分片的地理複制部署,擁有數百萬個分片,儲存着PB級别的資料。該部署包括數千台機器,在多個洲際區域和資料中心運作。

以前,他們的複制解決方案是使用MySQL半同步(semisync)複制協定。這是一種僅限于資料路徑的協定。MySQL主伺服器會使用半同步複制将資料寫入兩個日志記錄副本(logtailers),這些副本位于主要區域之外但不在主伺服器故障域内。這兩個 日志記錄副本将充當半同步ACKer(ACK 是對主伺服器發出的事務已被本地寫入進行确認)。這将使得資料路徑具有非常低延遲的(亞毫秒級)送出,并為寫操作提供高可用性/耐久性。普通的MySQL主-從異步複制則用于向其他區域進行更廣泛的分發。

控制平面操作(例如晉升、故障轉移和成員變更)由一組Python守護程式負責執行(以下簡稱自動化)。自動化将執行必要的編排工作,以在故障轉移位置上晉升新的MySQL伺服器作為主伺服器。自動化還會将以前的主伺服器和剩餘的從伺服器指向新的主伺服器進行複制。成員變更操作由另一個名為MySQL池掃描器(MPS)的自動化程式編排執行。要添加新成員,MPS将把新副本指向主伺服器并将其添加到服務發現存儲中。故障轉移是一項更複雜的操作,在此過程中,logtailers的尾部線程(半同步 ACKer)将被關閉以限制先前死亡的主伺服器。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

為什麼需要MySQL Raft?

過去,為了確定安全并避免在複雜的晉升和故障轉移操作期間資料丢失,幾個自動化守護程式和腳本會使用鎖定、編排步驟、圍欄機制和SMC(服務發現系統)。這是一個分布式設定,并且很難以原子方式完成。随着越來越多的邊角情況需要修補,自動化變得更加複雜和難以維護。

基于此,Meta技術團隊決定采取完全不同的方法。他們增強了MySQL并使其成為真正的分布式系統。意識到控制平面操作如晉升和成員更改是大多數問題的觸發器,團隊希望控制平面和資料平面操作成為相同複制日志的一部分。為此,他們使用了衆所周知的共識協定Raft。這就意味着成員身份和上司力真實性來源于伺服器(mysqld)内部。這是引入Raft最大貢獻之一,因為它使得在MySQL伺服器中進行晉升和成員更改時能夠證明正确性(安全屬性)。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

Raft庫和MySQL Raft插件

Meta團隊基于Apache Kudu實作了MySQL Raft,針對MySQL和他們的部署需求進行了大量增強,并将這個分支作為開源項目kuduraft釋出。

kuduraft的一些核心功能包括:

  • FlexiRaft - 支援兩個不同交叉仲裁:資料仲裁和上司者選舉仲裁
  • 代理(Proxying) - 能夠使用代理中間節點來減少網絡帶寬
  • 壓縮(Proxying ) - 在分發之前對二進制日志(事務)有效載荷進行一次壓縮
  • 日志抽象化 - 支援不同的實體日志檔案實
  • 主要禁止(Primary ban) -臨時阻止某些實體成為主要實體的能力

為了與Raft進行接口互動,他們還對MySQL複制進行相對大的更改,并建立了一個名為MyRaft的新的閉源MySQL插件MyRaft。MySQL将通過插件API與MyRaft進行接口互動(類似的API也用于半同步),同時他們還為MyRaft建立了一個單獨的API,用于與MySQL伺服器進行接口互動(回調)。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎
替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

MySQL Raft複制拓撲結構

在MySQL Raft的複制拓撲中,使用Raft協定的MySQL執行個體形成一個環狀結構,每個執行個體在不同的地區。Raft環将由幾個位于不同地區的MySQL執行個體(圖中有四個)組成。這些地區之間的通信往返時間(RTT)在10到100毫秒之間。其中幾個MySQL執行個體(通常是三個)充當主節點,處理寫入操作,而其餘的執行個體充當隻讀副本,用于處理讀取操作。在Meta的MySQL部署中,對于送出操作的延遲要求非常低,因為使用MySQL作為存儲的服務需要快速的寫入能力。

為了在FlexiRaft配置中為了滿足低延遲送出要求,Meta采用了區域内送出的方式(即單區域動态模式)。為了實作該目标,每個具備主節點能力的區域将增加兩個日志追随者(也稱為見證者或僅記錄實體)。寫入操作的資料法定人數設為2/3,即需要從1個MySQL和2個日志追随者中獲得2個ACK。Raft仍然負責管理和運作跨所有實體的複制日志,包括1個具備主節點能力的MySQL加上2個日志追随者的組合,乘以3個區域,再加上3個區域中的非主節點能力的MySQL,總共有12個實體。

Raft角色:在Raft協定中,有三種角色:上司者(Leader)、追随者(Follower)和學習者(Learner)。上司者是在複制日志中擔任上司者的角色,同時也是MySQL中的主節點,負責接收用戶端的寫入操作。追随者是環中的投票成員,從上司者那裡被動地接收消息(AppendEntries)。從MySQL的角度來看,追随者是一個副本,會将事務應用到自己的引擎中。它不允許使用者連接配接進行直接寫入操作(設定為read_only=1)。學習者是環中的非投票成員,例如,在非主節點能力的區域中的三個MySQL執行個體。在MySQL的角度來看,學習者也是一個副本。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎
替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

複制日志

MySQL一直以來都使用二進制日志格式進行複制。這種格式對于MySQL的複制非常重要,是以Meta團隊決定保留該格式。從Raft的角度來看,通過對kuduraft進行日志抽象和改進,實作了将二進制日志作為複制日志的方式。MySQL的事務會被編碼為一系列事件,比如Update Rows事件,每個事務都有開始和結束時間。二進制日志還包含适當的标頭,并通常以結束事件(Rotate事件)作為結尾。

為了滿足Raft的需求,Meta不得不調整MySQL内部日志的管理方式。在主節點上,Raft會将日志寫入binlog,與标準MySQL的操作方式幾乎沒有差別。而在副本中,Raft同樣将資料寫入binlog,而不是像标準MySQL那樣寫入單獨的relay log。這種調整使得Raft更加簡化,因為它隻需要關注一個命名空間下的日志檔案。如果某個副本被提升為上司者,它可以無縫地從自己的曆史記錄中擷取事務,并向滞後的成員發送事務。副本的應用程式線程會從binlog中擷取事務,并将其應用于資料庫引擎。在此過程中,還會建立一個名為"apply log"的新日志檔案,該檔案在副本的崩潰恢複方面起着重要作用,但它并非可複制的日志檔案。

簡言之:

在标準的MySQL中:

  • 主節點将寫入binlog并将其發送到副本。
  • 副本接收relay log并将事務應用于引擎。在應用期間,會建立一個新的僅限副本的binlog。

在MySQL Raft中:

  • 主節點通過Raft寫入binlog,并且Raft将binlog發送給跟随者/副本。
  • 跟随者/副本接收binlog并将事務應用于引擎。在應用期間建立一個apply log。
  • 從Raft角度來看,Binlog是複制日志。
替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

使用Raft在MySQL主節點上編寫事務

使用Raft在MySQL主節點上編寫事務的過程如下:首先,事務将在資料庫引擎中準備。這一過程将在使用者連接配接的線程中進行。準備事務的行為涉及與存儲引擎(如InnoDB或MyRocks)的互動,并生成用于該事務的記憶體中的binlog負載。

在送出時,寫入操作将通過組送出/有序送出流程傳遞。GTID(全局事務辨別符)将被配置設定,然後Raft将為該事務配置設定一個OpId(term:index)。此時,Raft将對該事務進行壓縮,并将其存儲到其LogCache中,并通過binlog檔案寫入該事務。它将異步地開始向其他跟随者發送事務以擷取ACK并達成共識。

請注意,term和index是Raft中的概念,用于唯一辨別和順序化事務。

當事務送出時,Raft會通過投票達成共識,并解除使用者線程的阻塞。送出的事務将繼續在引擎中執行,并傳回結果給用戶端。同時,Raft會異步地将送出标記發送給其他跟随者,以便它們也可以應用相同的事務。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎
替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

崩潰恢複

崩潰恢複是與Raft協定無縫協作的關鍵部分。在事務的生命周期中,可能會發生崩潰,是以必須確定成員之間的一緻性。以下是他們在崩潰恢複方面的關鍵思路:

  • 事務未重新整理到binlog:如果事務在崩潰之前尚未重新整理到binlog中,意味着該事務的記憶體負載(在mysqld程序記憶體中作為記憶體緩沖區)将丢失。當程序重新啟動時,引擎中準備好的事務将被復原。由于Raft日志中沒有未送出的額外事務,是以不需要與其他成員進行調和。
  • 事務已重新整理到binlog但未到達其他成員:在這種情況下,MySQL充當交易協調器,并在參與者之間運作兩階段送出協定,該協定介于引擎和複制binlog之間。在崩潰恢複期間,引擎中準備好的交易将被復原(引擎尚未送出)。Raft協定将經曆故障轉移,并選出新的上司者。新上司者在其binlog中不會有此交易記錄,是以在前任上司者加入環時,通過推送No-Op消息來截斷該交易記錄,以實作更高的任期。
  • 事務已重新整理到binlog并傳遞給下一個上司者,但目前上司者在送出給引擎之前崩潰:與上述第2點類似,引擎中準備好的交易将被復原。前任上司者将作為追随者加入Raft環。在這種情況下,新的上司者将在其binlog中具有此交易記錄,并且不會發生截斷,因為日志比對。當新的上司者發送送出标記時,該事務将重新開始應用。

這些措施確定了崩潰恢複的一緻性,并保證了事務的正确性。通過與Raft協定的內建,MySQL在高可用性和容錯性方面取得了顯著的進展,使資料庫能夠在崩潰情況下保持穩定運作,并能夠快速恢複。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

Raft狀态機轉換

Raft啟動狀态機轉換是在故障轉移和正常維護操作中觸發的一項重要任務。一旦Raft選舉出新的上司者,MyRaft插件會嘗試将相應的MySQL執行個體切換到主模式。為了完成這個轉換,插件需要執行一系列協調步驟。

這些步驟涉及從Raft到MySQL的回調操作。它們包括中止正在進行的事務,復原GTID(全局事務辨別符),從應用日志切換到binlog,并設定正确的read_only屬性。這一過程相當複雜,并且目前沒有開源的實作可用。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

FlexiRaft

在傳統的Raft協定中,隻有一個全局仲裁者(leader)來處理資料路徑決策。然而,在Meta這樣的大規模環境中,環的規模很大,而資料路徑決策需要更小的仲裁範圍。由于Raft協定和Apache Kudu都隻支援單個全局仲裁者,無法很好地适應Meta的需求。

為了解決這個問題,Meta團隊借鑒了Flexible Paxos的一些思路,并創新性地引入了FlexiRaft。FlexiRaft是對傳統Raft協定的改進,以支援更靈活的仲裁機制。

在高層次上,FlexiRaft在資料送出仲裁方面具有靈活性(較小的範圍),同時對上司者選舉仲裁産生較大的影響(更大的範圍)。通過遵循仲裁交集的可證明保證,FlexiRaft確定了Raft協定中最長日志規則的執行和适當的仲裁交集,進而提供了可證明的安全性。

FlexiRaft支援單區域動态模式,其中成員根據地理區域進行分組。在此模式下,目前的資料送出仲裁取決于目前的上司者(是以稱為“單區域動态”)。資料仲裁由上司者所在地區的投票人數多數派決定。在選舉過程中,如果術語連續,則候選人将與最後已知上司者所在地區相交。FlexiRaft還確定獲得候選人所在地區的法定人數,否則随後的No-Op消息可能會被阻塞。在極少情況下,如果術語不連續,FlexiRaft會嘗試找出一組需要與之相交以實作安全性增長的地區;或者在最壞情況下,回退到Flexible Paxos中的N個區域交叉點案例。由于預選和模拟選舉的引入,術語間隙的發生非常罕見。

這些機制使得FlexiRaft在資料送出仲裁和上司者選舉仲裁方面具有靈活性和可證明的安全性,進而更好地适應大規模環境下的需求。它允許更準确地控制資料路徑決策的範圍,并提供了強大的一緻性保證。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

控制平面操作(促銷和會員變更)

為了将晉升(即上司者更改)和會員變更事件序列化到MySQL的二進制日志中,Meta團隊對MySQL二進制日志格式的Rotate Event(旋轉事件)和Metadata Event(中繼資料事件)進行了修改。這些事件被用來攜帶Raft協定中的No-Op消息(無操作消息)以及添加成員/删除成員操作的等效内容。由于Apache Kudu不支援聯合共識(即同時處理多個成員變更),是以他們隻允許逐個進行成員變更。在一輪中,隻能通過一個實體來改變成員身份,以遵守隐式法定交集規則。

通過修改MySQL的二進制日志格式,Meta團隊成功地将Raft協定中的晉升和會員變更事件與MySQL的二進制日志進行了內建,以確定一緻性和可靠性。這樣可以将這些操作持久化并進行複制,進而在叢集中保持一緻的狀态。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

自動化

通過實施MySQL Raft,Meta為MySQL部署實作了非常清晰的職責分離。MySQL伺服器負責通過Raft的複制狀态機確定安全性,以提供無資料丢失的保證。這個責任被直接內建到伺服器本身中。

為了管理和監控叢集的運作狀況,他們還使用了自動化工具,如Python腳本和守護程序。這些工具負責啟動控制平面操作,并監視叢集的健康狀态。它們能夠在維護期間或在檢測到主機故障時自動執行成員替換或更新等操作。有時,自動化工具還可以根據需要修改MySQL拓撲的區域布置方式。

适應Raft協定所帶來的變化,并将這些變化反映到自動化工具中,是一項龐大的工作,需要多年的開發和推出。這是一個長期的過程,需要不斷地優化和改進,以確定自動化工具與MySQL Raft的要求保持一緻,并能夠可靠地管理和維護整個部署。

在長時間維護事件期間,自動化工具會在Raft上設定上司禁止資訊。Raft将阻止這些被禁止的實體成為上司者,或在意外選舉時及時撤離它們。自動化工具還會将上司權轉移到其他區域,遠離被禁止的區域。這樣做的目的是確定在維護期間,被禁止的實體不會幹擾系統的正常運作,并将上司權轉移到可靠的區域,以確定叢集的穩定性和可用性。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

MySQL Raft 推出的經驗與挑戰

在将Raft推廣到整個機群的整個過程中,團隊積累了大量寶貴的經驗和教訓。最初他們在MySQL 5.6上開發了Raft,随後遷移到MySQL 8.0。

其中一個關鍵的經驗教訓是,盡管Raft協定可以相對容易地確定正确性,但它本身并不能很好地解決可用性問題。由于他們的MySQL資料仲裁非常小(區域内的三個成員中的兩個),若區域内出現兩個故障實體,将會破壞仲裁并導緻可用性降低。MySQL機群每天都面臨相當多的變動(如維護、主機故障、平衡操作),是以及時、正确地進行成員變更對于保持持續可用性至關重要。推出過程中,團隊将主要精力放在及時進行日志傳輸和MySQL替換上,以確定Raft仲裁保持健康。

Meta團隊不得不增強kuduraft以使其更加健壯可用。這些改進并非核心協定的一部分,但可以視為工程附加元件。Kuduraft支援預選舉,但僅在故障轉移期間進行。在上司權的平穩轉移期間,指定的候選人直接進入真正的選舉,并提高任期。這就會給上司者帶來困擾(kuduraft不會自動下台)。為解決此問題,Meta添加了模拟選舉功能,類似于預先選舉,但僅在上司權平穩轉移時發生。由于這是異步操作,是以它沒有增加晉升停機時間。模拟選舉将消除真實選舉部分成功并被卡住的情況。

處理拜占庭故障:根據Raft協定,成員清單是由Raft自身認可的。然而,在引入新成員或因自動化競争而導緻兩個不同的Raft環交叉的過程中,可能會出現一些異常情況。這些異常情況會導緻出現僵屍成員節點,這些節點需要被清除并與其他成員節點停止通信。為了解決這個問題,團隊實作了一個功能來阻止這些僵屍成員向環發送RPC請求,進而防止它們對系統造成幹擾。這種處理方式可以被視為對拜占庭行為的一種應對方式。一旦團隊注意到在他們的部署中發生了這些罕見事件,他們對Raft實作進行了改進,以增強系統的穩定性和可靠性。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

MySQL Raft推出後的監控

推出MySQL Raft時,一個重要目标是減少on-call人員的操作複雜性,以便工程師可以更輕松地定位和解決問題。為此,團隊建立了多個監控儀表闆、CLI工具和scuba表來監視Raft的狀态。在MySQL中增加了大量的日志記錄,特别是在晉升和成員更改方面。團隊還建立了用于環的法定人數和投票報告的CLI工具,可以快速識别環不可用(法定人數不足)的時間和原因。在工具化和自動化基礎設施方面的投資與伺服器變更的推出密切相關,并且可能比伺服器變更本身更具挑戰性。然而,這項投資帶來了巨大的回報,并大大減少了運維和入職過程中遇到的困難。這樣的投資使得團隊能夠更高效地管理和監控Raft,并及時解決潛在的問題。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

Quorum Fixer

盡管并不希望發生這種情況,但有時自動化無法及時檢測到環中的不健康執行個體或日志記錄器,并進行及時替換。這可能是由于檢測不足、工作隊列過載或缺乏備用主機容量等原因造成的。盡管這種情況不常見,因為團隊在部署過程中采取了适當的放置政策來隔離關鍵群集實體的故障域,但仍然可能發生意外情況。

為此,Meta開發了Quorum Fixer,這是一個用 Python 編寫的手動修複工具,旨在解決可能導緻可用性下降的拆分情況。它在環中禁止寫操作,并進行離線檢查以确定最長日志實體。然後,它會強制更改 Raft 中的上司者選舉的法定人數期望值,進而選擇該實體作為上司者。一旦成功晉升,我們将法定人數期望值重置回原來的狀态,通常可以使環恢複正常。

我們有意決定不自動運作此工具,因為我們希望能夠發現所有的群集損失情況并修複其中的錯誤,而不是讓自動化默默地解決問題。是以,Quorum Fixer 提供了一種手動的方式來處理這些情況。通過使用該工具,我們能夠更加積極地識别并解決生産環境中的問題。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

釋出MySQL Raft

推出MySQL Raft對于大規模部署來說确實是具有挑戰性。為了應對這個問題,Meta團隊還開發了一個名為"enable-raft"的工具,使用Python編寫。該工具的目的是協調從半同步到Raft的過渡過程,并在每個實體上加載插件并設定适當的配置(例如MySQL系統變量)。這個過程中需要短暫的停機時間來完成環境的轉換。

通過多次改進,enable-raft已變得非常穩健,并且能夠快速擴充Raft功能。他們已經成功地使用這個工具來安全地推出Raft,并将其應用于Meta的部署中。該工具在過渡過程中發揮了重要作用,它簡化了從半同步到Raft的切換,并在整個部署中保持穩定性。它是Meta團隊成功實施Raft的關鍵組成部分。

在進行MySQL核心複制管道的更改過程中,測試是非常重要的,因為資料安全性是一個關鍵問題。為了建立信心并確定變更的正确性,我們采用了大量的影子測試和故障注入。通過影子測試和故障注入以及長時間運作的資料正确性檢查,我們能夠更好地評估和驗證MySQL核心複制管道的更改,確定其在生産環境中的可靠性和安全性。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

性能表現

通過優化Raft實作,他們實作了與semisync相當的寫入路徑延遲表現,盡管semisync機制稍微簡單一些。團隊確定在Raft中承擔額外職責時不增加任何CPU負載,使其能夠處理許多之前不屬于伺服器二進制檔案的任務。

Raft大大改善了晉升和故障轉移的時間。在整個叢集中,優雅的上司權轉移占據了絕大部分比例,并且通常可以在300毫秒内完成。相比之下,在semisync設定中,由于服務發現存儲将是真實來源,用戶端需要更長的時間來注意到晉升的完成,進而導緻使用者在片段上的停機時間更長。

在故障轉移方面,Raft通常可以在2秒内完成。通過每500毫秒進行心跳檢測和Raft健康狀況,并在連續三個心跳失敗後開始選舉新的上司者。相比之下,在semisync環境中,這個過程需要進行編排并耗費20至40秒的時間。是以,在故障轉移情況下,Raft可以将停機時間縮短10倍。

總之,通過這些性能優化措施,團隊成功地改進了Raft的寫入路徑延遲表現,縮短了晉升和故障轉移的時間,使得在整個叢集中的上司權轉移更加快速和優雅。

替代MySQL半同步,Meta技術團隊推出MySQL Raft共識引擎

未來計劃

接下來,Raft将專注于增強MySQL服務功能,實作對MySQL一緻性的無需幹預管理。通過支援可配置法定人數的FlexiRaft,服務所有者可以選擇在入門時是否需要特定地理位置的複制副本,權衡一緻性和延遲。這将為MySQL使用者提供更多靈活性和選擇。

Raft還計劃利用代理功能來節省跨大西洋的網絡帶寬。通過僅在美國複制到歐洲一次,然後使用Raft的代理功能進行分發,雖然會增加一些延遲,但可以大大減少橫跨大西洋的傳輸時間。此外,團隊還在探索無上司協定(如Epaxos)和解耦日志與狀态機的非內建日志設定,以進一步提升部署和服務的效能和靈活性。

繼續閱讀