Facebook是如何從簡單的數據庫分片擴展到分佈式分片通用平臺?

多年來,Facebook已從一種基本的Web服務器體系結構演變爲一個複雜的體系結構,其中包含成千上萬的服務在後臺運行。擴展Facebook產品所需的各種後端服務並不是一件容易的事。而且發現我們的許多團隊正在構建具有重疊功能的自定義分片解決方案。爲了解決此問題,我們將Shard Manager構建爲通用平臺,以促進可靠分片應用程序的有效開發和操作。

使用分片擴展服務的概念並不新鮮。但是,據我們所知,我們是業界唯一在我們的規模上獲得廣泛採用的通用分片平臺。Shard Manager管理生產中成百上千個應用程序中成千上萬個服務器上託管的數千萬個分片。

多年來,Facebook已從一種基本的Web服務器體系結構演變爲一個複雜的體系結構,其中包含成千上萬的服務在後臺運行。擴展Facebook產品所需的各種後端服務並不是一件容易的事。而且發現我們的許多團隊正在構建具有重疊功能的自定義分片解決方案。爲了解決此問題,我們將Shard Manager構建爲通用平臺,以促進可靠分片應用程序的有效開發和操作。

使用分片擴展服務的概念並不新鮮。但是,據我們所知,我們是業界唯一在我們的規模上獲得廣泛採用的通用分片平臺。Shard Manager管理生產中成百上千個應用程序中成千上萬個服務器上託管的數千萬個分片。

https://engineering.fb.com/wp-content/uploads/2020/08/SHARD_manager_hero_01.jpg

分片簡介

人們熟悉分片作爲擴展服務以支持高吞吐量的一種方式。下圖說明了典型Web堆棧的縮放比例。Web層通常是無狀態的,並且易於擴展。由於任何服務器都可以處理任何請求,因此可以使用多種通信量路由策略,例如輪循或隨機。

https://engineering.fb.com/wp-content/uploads/2020/08/SHARD_manager-01.jpg?w=916

另一方面,縮放數據庫部分由於其狀態是不平凡的。我們需要應用一種方案來確定性地跨服務器分佈數據。像散列這樣的簡單散列方案hash(data_key) % num_servers 可以散佈數據,但是當按比例添加服務器時,存在將數據混排的問題。一致性哈希通過僅將一小部分數據從現有服務器重新分配到新服務器來解決此問題。但是,此方案要求應用程序具有細粒度的鍵才能使統計負載平衡有效。由於其本質,一致性哈希支持基於約束的分配的能力(例如,應將歐洲聯盟用戶的數據存儲在歐洲數據中心以降低延遲)。結果,只有某些類型的應用程序(例如分佈式緩存)才採用此方案。

一種替代方案是將數據顯式分區爲分配給服務器的分片。數十億用戶的數據存儲在許多數據庫實例中,每個實例都可以視爲一個分片。爲了提高容錯能力,每個數據庫分片可以具有多個副本(又名副本),每個副本都可以發揮不同的作用 (例如,主要或次要),具體取決於一致性要求。

明確分配給服務器的分片具有合併各種約束(例如,哈希解決方案無法支持的位置首選項)的能力。我們發現分片方法比散列方法更靈活,並且適合更廣泛的分佈式應用程序的需求。

採用這種分片方法的應用程序通常需要某些分片管理功能才能可靠地大規模運行。最基本的功能是故障轉移功能。如果發生硬件或軟件故障,系統可以將客戶端流量從故障服務器轉移開,甚至可能需要在運行狀況良好的服務器上重建受影響的副本。在大型數據中心中,服務器始終計劃停機以執行硬件或軟件維護。分片管理系統需要通過主動將副本從服務器上移開以確保每個分片具有足夠的正常副本,以便在必要時將其刪除。

另外,可能不均勻且不斷變化的分片負載需要負載平衡,這意味着必須動態調整每個服務器主機的分片集,以實現統一的資源利用率並提高整體資源效率和服務可靠性。最後,客戶端流量的波動需要分片擴展,系統在每個分片的基礎上動態調整複製因子,以確保其平均每個副本負載保持最佳狀態。

我們發現,Facebook的不同服務團隊已經在構建自己的自定義解決方案,以實現不同程度的完整性。常見的情況是,服務能夠處理故障轉移,但是負載平衡的形式非常有限。這導致次優的可靠性和較高的操作開銷。這就是爲什麼我們將Shard Manager設計爲通用的分片管理平臺的原因。

使用分片管理器將分片作爲平臺

多年來,已將數百個分片應用程序構建或遷移到Shard Manager上,具有歷史超增長的上十萬個服務器上總共有上千萬個分片副本,這些應用程序有助於各種面向用戶的產品(包括Facebook應用程序,Messenger,WhatsApp和Instagram)的平穩運行。

首先,與Shard Manager集成意味着簡單地實現一個由add_shard 和原語組成的小而直接的界面drop_shard 。其次,每個應用程序都可以通過基於意圖的規範來聲明其可靠性和效率要求。第三,使用通用約束優化求解器使Shard Manager能夠提供通用的負載平衡功能,並輕鬆添加對新平衡策略的支持。

最後但並非最不重要的一點是,通過完全集成到包括容量和容器管理在內的整個基礎架構生態系統中,Shard Manager不僅支持分片應用程序的高效開發,而且還支持分片應用程序的安全運行,因此提供了端到端解決方案,這是同類平臺所沒有的提供。與類似的平臺(例如基於Hex的Apache Helix)(包括基於Paxos的存儲系統用例)相比,Shard Manager支持更復雜的用例。

Shard Manager應用程序的類型

我們在Shard Manager上抽象了應用程序的通用性,並將它們分爲三種類型:僅主,僅次和主次。

僅主Primary only:

主副本**:**每個分片都有一個副本,稱爲主副本。這些類型的應用程序通常將狀態存儲在外部系統中,例如數據庫和數據倉庫。一個常見的範例是,每個分片代表一個工作程序,該工作程序使用諸如批處理之類的可選優化來獲取指定的數據,對其進行處理,有選擇地服務於客戶端請求並回寫結果。流處理是一個真實的示例,它處理來自輸入流的數據並將結果寫入輸出流。Shard Manager提供了至多一項主要保證,以幫助防止由於重複數據處理而導致的數據不一致,就像傳統的基於ZooKeeper鎖的方法一樣。

僅次Secondaries only:

節點**:**每個分片具有多個角色相同的副本,稱爲輔助節點。來自多個副本的冗餘提供了更好的容錯能力。此外,可以根據工作負載調整複製因子:熱分片可以具有更多副本來分散負載。通常,這些類型的應用程序是隻讀的,沒有很強的一致性要求。他們從外部存儲系統中獲取數據,可選地處理數據,在本地緩存結果,並根據本地數據提供查詢。一個真實的例子是機器學習推理系統,該系統從遠程存儲中下載經過訓練的模型並服務於推理請求。

主次

節點**:**每個分片具有主次節點兩個角色的多個副本。這些類型的應用程序通常是對數據一致性和持久性有嚴格要求的存儲系統,其中主副本接受寫請求並驅動所有副本之間的複製,而輔助副本提供冗餘,並且可以選擇提供讀取以減少主副本上的負載。一個示例是ZippyDB,它是具有基於Paxos的複製的全局鍵值存儲。

我們發現以上三種類型可以在Facebook上對大多數分片應用程序建模,截至2020年8月的百分比分佈如下所示。由於架構的簡單性和與傳統ZooKeeper基於鎖的解決方案的概念相似性,百分之六十七的應用程序是僅主的應用程序。但是,就服務器數量而言,僅主的應用程序僅佔17%,這意味着僅主的應用程序平均比其他兩種類型的應用程序小。

https://engineering.fb.com/wp-content/uploads/2020/08/SHARD_manager-04.jpg?w=916

使用Shard Manager構建應用程序

在應用程序所有者決定如何將其工作負載/數據切成分片以及哪種應用程序類型適合其需求之後,無論用例如何,在Shard Manager上構建分片應用程序都需要執行三個簡單的標準化步驟。

  1. 應用程序鏈接了Shard Manager庫,並通過插入其業務邏輯來實現分片狀態轉換接口。
  2. 應用程序所有者提供基於意圖的規範來配置約束。Shard Manager提供了四組主要的開箱即用功能:容錯,負載平衡,分片擴展和操作安全性。
  3. 應用程序客戶端使用公共路由庫來路由特定於分片的請求。

分片管理器的設計與實現

在Facebook,我們的整體基礎架構是採用分層方法構建的,各層次之間的關注點清晰分開。這使我們能夠獨立,穩健地發展和擴展每一層。下圖顯示了基礎架構的層次結構。每一層分配並定義相鄰上層操作的範圍。

https://engineering.fb.com/wp-content/uploads/2020/08/SHARD_manager-08.jpg?w=916

  1. 主機管理:資源配額系統管理所有物理服務器,併爲組織和團隊分配容量。
  2. 容器管理:Twine從資源配額系統獲取容量,並將其分配給以容器爲單位的各個應用程序。
  3. 分片管理:分片管理器在Twine提供的容器內爲分片應用程序分配分片。
  4. 分片應用程序:在每個分片中,應用程序分配並運行關聯的工作負載。
  5. 產品:這些是面向用戶的產品,例如移動應用程序,由分片的後端應用程序提供支持。

除了每一層在相鄰較低層上的向下功能依賴關係之外,整個基礎結構堆棧都經過代碼簽名,並通過向上傳播的信號和事件協同工作。特別是對於Shard Manager層,TaskControl是我們實現協作調度的機制。

架構

Shard Manager的體系結構如下:

https://engineering.fb.com/wp-content/uploads/2020/08/SHARD_manager-09.jpg?w=916

  • 應用程序所有者向Shard Manager Scheduler提供了一個規範,其中包含管理應用程序所需的所有信息。
  • Shard Manager Scheduler是協調分片過渡和移動的中央服務。它收集應用程序狀態;監視狀態更改,例如服務器連接,服務器故障和負載更改;調整分片分配;並通過對應用程序服務器的RPC調用來驅動分片狀態轉換。Shard Manager Scheduler在內部被分片以橫向擴展。
  • 應用程序 鏈接Shard Manager庫,該庫通過連接到ZooKeeper來提供服務器成員身份和活動檢查的透明度。應用程序實現分片狀態轉換接口,並由分片管理器調度程序指示狀態轉換。應用程序可以測量和公開由Shard Manager Scheduler收集的動態負載信息。
  • 分片管理器調度程序將分片分配的公共視圖發佈到高度可用且可擴展的服務發現系統,該系統將信息傳播到應用程序客戶端以路由請求。
  • 應用程序客戶端鏈接一個通用路由庫,該路由庫在每個分片的基礎上封裝了服務器端點的發現。端點發現後,客戶端請求將直接發送到應用程序服務器。因此,分片管理器調度程序不在請求服務的關鍵路徑上。

總結

Shard Manager提供了用於構建分片應用程序的通用平臺。用戶只需要實現分片狀態轉換接口,並通過基於意圖的規範來表達分片約束。該平臺與Facebook生態系統的其餘部分完全集成,這使整體基礎結構隱藏了基礎架構的複雜性,並使我們的工程師能夠專注於其應用程序和產品的核心業務邏輯。

Shard Manager從九年前開始發展,但是旅程還遠未完成。我們將繼續努力提供一流的解決方案,以在Facebook上構建分片服務。

儘管我們取得了成功,但我們仍在多個方面擴展Shard Manager的規模和功能。以下是我們計劃在未來幾年應對的各種挑戰:

  1. 通過在內部將應用程序劃分爲較小的獨立分區,每個應用程序可支持數千萬個分片,以滿足不斷增長的大型應用程序的需求。
  2. 通過提供更高的模塊化和可插入性以供用戶自定義,同時使Shard Manager保持簡單,從而支持更復雜的應用程序。
  3. 簡化了當前抽象過於繁瑣的小型,簡單應用程序的長尾使用體驗。

通過展示構建通用分片解決方案的可行性,我們希望我們可以促進進一步的討論,並幫助圍繞技術領域中這一前沿問題共同推動該領域的發展。

banq注:數據庫分片其實是業務數據切分,DDD有界上下文提供一種方式,哈希一致性是從算法角度試圖來解決,但是FB經驗說明這種一刀切的辦法不具有通用性,只能根據不同的領域進行不同的切分,FB這種分片管理器平臺是一種有狀態服務平臺,不同於K8s那種無狀態服務平臺,分片管理器屬於分佈式事務實現的一種方式。

 

分片簡介

人們熟悉分片作爲擴展服務以支持高吞吐量的一種方式。下圖說明了典型Web堆棧的縮放比例。Web層通常是無狀態的,並且易於擴展。由於任何服務器都可以處理任何請求,因此可以使用多種通信量路由策略,例如輪循或隨機。

https://engineering.fb.com/wp-content/uploads/2020/08/SHARD_manager-01.jpg?w=916

另一方面,縮放數據庫部分由於其狀態是不平凡的。我們需要應用一種方案來確定性地跨服務器分佈數據。像散列這樣的簡單散列方案hash(data_key) % num_servers 可以散佈數據,但是當按比例添加服務器時,存在將數據混排的問題。一致性哈希通過僅將一小部分數據從現有服務器重新分配到新服務器來解決此問題。但是,此方案要求應用程序具有細粒度的鍵才能使統計負載平衡有效。由於其本質,一致性哈希支持基於約束的分配的能力(例如,應將歐洲聯盟用戶的數據存儲在歐洲數據中心以降低延遲)。結果,只有某些類型的應用程序(例如分佈式緩存)才採用此方案。

一種替代方案是將數據顯式分區爲分配給服務器的分片。數十億用戶的數據存儲在許多數據庫實例中,每個實例都可以視爲一個分片。爲了提高容錯能力,每個數據庫分片可以具有多個副本(又名副本),每個副本都可以發揮不同的作用 (例如,主要或次要),具體取決於一致性要求。

明確分配給服務器的分片具有合併各種約束(例如,哈希解決方案無法支持的位置首選項)的能力。我們發現分片方法比散列方法更靈活,並且適合更廣泛的分佈式應用程序的需求。

採用這種分片方法的應用程序通常需要某些分片管理功能才能可靠地大規模運行。最基本的功能是故障轉移功能。如果發生硬件或軟件故障,系統可以將客戶端流量從故障服務器轉移開,甚至可能需要在運行狀況良好的服務器上重建受影響的副本。在大型數據中心中,服務器始終計劃停機以執行硬件或軟件維護。分片管理系統需要通過主動將副本從服務器上移開以確保每個分片具有足夠的正常副本,以便在必要時將其刪除。

另外,可能不均勻且不斷變化的分片負載需要負載平衡,這意味着必須動態調整每個服務器主機的分片集,以實現統一的資源利用率並提高整體資源效率和服務可靠性。最後,客戶端流量的波動需要分片擴展,系統在每個分片的基礎上動態調整複製因子,以確保其平均每個副本負載保持最佳狀態。

我們發現,Facebook的不同服務團隊已經在構建自己的自定義解決方案,以實現不同程度的完整性。常見的情況是,服務能夠處理故障轉移,但是負載平衡的形式非常有限。這導致次優的可靠性和較高的操作開銷。這就是爲什麼我們將Shard Manager設計爲通用的分片管理平臺的原因。

使用分片管理器將分片作爲平臺

多年來,已將數百個分片應用程序構建或遷移到Shard Manager上,具有歷史超增長的上十萬個服務器上總共有上千萬個分片副本,這些應用程序有助於各種面向用戶的產品(包括Facebook應用程序,Messenger,WhatsApp和Instagram)的平穩運行。

首先,與Shard Manager集成意味着簡單地實現一個由add_shard 和原語組成的小而直接的界面drop_shard 。其次,每個應用程序都可以通過基於意圖的規範來聲明其可靠性和效率要求。第三,使用通用約束優化求解器使Shard Manager能夠提供通用的負載平衡功能,並輕鬆添加對新平衡策略的支持。

最後但並非最不重要的一點是,通過完全集成到包括容量和容器管理在內的整個基礎架構生態系統中,Shard Manager不僅支持分片應用程序的高效開發,而且還支持分片應用程序的安全運行,因此提供了端到端解決方案,這是同類平臺所沒有的提供。與類似的平臺(例如基於Hex的Apache Helix)(包括基於Paxos的存儲系統用例)相比,Shard Manager支持更復雜的用例。

Shard Manager應用程序的類型

我們在Shard Manager上抽象了應用程序的通用性,並將它們分爲三種類型:僅主,僅次和主次。

僅主Primary only:

主副本**:**每個分片都有一個副本,稱爲主副本。這些類型的應用程序通常將狀態存儲在外部系統中,例如數據庫和數據倉庫。一個常見的範例是,每個分片代表一個工作程序,該工作程序使用諸如批處理之類的可選優化來獲取指定的數據,對其進行處理,有選擇地服務於客戶端請求並回寫結果。流處理是一個真實的示例,它處理來自輸入流的數據並將結果寫入輸出流。Shard Manager提供了至多一項主要保證,以幫助防止由於重複數據處理而導致的數據不一致,就像傳統的基於ZooKeeper鎖的方法一樣。

僅次Secondaries only:

節點**:**每個分片具有多個角色相同的副本,稱爲輔助節點。來自多個副本的冗餘提供了更好的容錯能力。此外,可以根據工作負載調整複製因子:熱分片可以具有更多副本來分散負載。通常,這些類型的應用程序是隻讀的,沒有很強的一致性要求。他們從外部存儲系統中獲取數據,可選地處理數據,在本地緩存結果,並根據本地數據提供查詢。一個真實的例子是機器學習推理系統,該系統從遠程存儲中下載經過訓練的模型並服務於推理請求。

主次

節點**:**每個分片具有主次節點兩個角色的多個副本。這些類型的應用程序通常是對數據一致性和持久性有嚴格要求的存儲系統,其中主副本接受寫請求並驅動所有副本之間的複製,而輔助副本提供冗餘,並且可以選擇提供讀取以減少主副本上的負載。一個示例是ZippyDB,它是具有基於Paxos的複製的全局鍵值存儲。

我們發現以上三種類型可以在Facebook上對大多數分片應用程序建模,截至2020年8月的百分比分佈如下所示。由於架構的簡單性和與傳統ZooKeeper基於鎖的解決方案的概念相似性,百分之六十七的應用程序是僅主的應用程序。但是,就服務器數量而言,僅主的應用程序僅佔17%,這意味着僅主的應用程序平均比其他兩種類型的應用程序小。

https://engineering.fb.com/wp-content/uploads/2020/08/SHARD_manager-04.jpg?w=916

使用Shard Manager構建應用程序

在應用程序所有者決定如何將其工作負載/數據切成分片以及哪種應用程序類型適合其需求之後,無論用例如何,在Shard Manager上構建分片應用程序都需要執行三個簡單的標準化步驟。

  1. 應用程序鏈接了Shard Manager庫,並通過插入其業務邏輯來實現分片狀態轉換接口。
  2. 應用程序所有者提供基於意圖的規範來配置約束。Shard Manager提供了四組主要的開箱即用功能:容錯,負載平衡,分片擴展和操作安全性。
  3. 應用程序客戶端使用公共路由庫來路由特定於分片的請求。

分片管理器的設計與實現

在Facebook,我們的整體基礎架構是採用分層方法構建的,各層次之間的關注點清晰分開。這使我們能夠獨立,穩健地發展和擴展每一層。下圖顯示了基礎架構的層次結構。每一層分配並定義相鄰上層操作的範圍。

https://engineering.fb.com/wp-content/uploads/2020/08/SHARD_manager-08.jpg?w=916

  1. 主機管理:資源配額系統管理所有物理服務器,併爲組織和團隊分配容量。
  2. 容器管理:Twine從資源配額系統獲取容量,並將其分配給以容器爲單位的各個應用程序。
  3. 分片管理:分片管理器在Twine提供的容器內爲分片應用程序分配分片。
  4. 分片應用程序:在每個分片中,應用程序分配並運行關聯的工作負載。
  5. 產品:這些是面向用戶的產品,例如移動應用程序,由分片的後端應用程序提供支持。

除了每一層在相鄰較低層上的向下功能依賴關係之外,整個基礎結構堆棧都經過代碼簽名,並通過向上傳播的信號和事件協同工作。特別是對於Shard Manager層,TaskControl是我們實現協作調度的機制。

架構

Shard Manager的體系結構如下:

https://engineering.fb.com/wp-content/uploads/2020/08/SHARD_manager-09.jpg?w=916

  • 應用程序所有者向Shard Manager Scheduler提供了一個規範,其中包含管理應用程序所需的所有信息。
  • Shard Manager Scheduler是協調分片過渡和移動的中央服務。它收集應用程序狀態;監視狀態更改,例如服務器連接,服務器故障和負載更改;調整分片分配;並通過對應用程序服務器的RPC調用來驅動分片狀態轉換。Shard Manager Scheduler在內部被分片以橫向擴展。
  • 應用程序 鏈接Shard Manager庫,該庫通過連接到ZooKeeper來提供服務器成員身份和活動檢查的透明度。應用程序實現分片狀態轉換接口,並由分片管理器調度程序指示狀態轉換。應用程序可以測量和公開由Shard Manager Scheduler收集的動態負載信息。
  • 分片管理器調度程序將分片分配的公共視圖發佈到高度可用且可擴展的服務發現系統,該系統將信息傳播到應用程序客戶端以路由請求。
  • 應用程序客戶端鏈接一個通用路由庫,該路由庫在每個分片的基礎上封裝了服務器端點的發現。端點發現後,客戶端請求將直接發送到應用程序服務器。因此,分片管理器調度程序不在請求服務的關鍵路徑上。

總結

Shard Manager提供了用於構建分片應用程序的通用平臺。用戶只需要實現分片狀態轉換接口,並通過基於意圖的規範來表達分片約束。該平臺與Facebook生態系統的其餘部分完全集成,這使整體基礎結構隱藏了基礎架構的複雜性,並使我們的工程師能夠專注於其應用程序和產品的核心業務邏輯。

Shard Manager從九年前開始發展,但是旅程還遠未完成。我們將繼續努力提供一流的解決方案,以在Facebook上構建分片服務。

儘管我們取得了成功,但我們仍在多個方面擴展Shard Manager的規模和功能。以下是我們計劃在未來幾年應對的各種挑戰:

  1. 通過在內部將應用程序劃分爲較小的獨立分區,每個應用程序可支持數千萬個分片,以滿足不斷增長的大型應用程序的需求。
  2. 通過提供更高的模塊化和可插入性以供用戶自定義,同時使Shard Manager保持簡單,從而支持更復雜的應用程序。
  3. 簡化了當前抽象過於繁瑣的小型,簡單應用程序的長尾使用體驗。

通過展示構建通用分片解決方案的可行性,我們希望我們可以促進進一步的討論,並幫助圍繞技術領域中這一前沿問題共同推動該領域的發展。

banq注:數據庫分片其實是業務數據切分,DDD有界上下文提供一種方式,哈希一致性是從算法角度試圖來解決,但是FB經驗說明這種一刀切的辦法不具有通用性,只能根據不同的領域進行不同的切分,FB這種分片管理器平臺是一種有狀態服務平臺,不同於K8s那種無狀態服務平臺,分片管理器屬於分佈式事務實現的一種方式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章