最佳實踐|放棄 Ceph,Salesforce 使用 Apache BookKeeper 在雲中實現最強存儲

語言: CN / TW / HK

關於 Apache Pulsar

Apache Pulsar 是 Apache 軟件基金會頂級項目,是下一代雲原生分佈式消息流平台,集消息、存儲、輕量化函數式計算為一體,採用計算與存儲分離架構設計,支持多租户、持久化存儲、多機房跨區域數據複製,具有強一致性、高吞吐、低延時及高可擴展性等流數據存儲特性。
GitHub 地址:http://github.com/apache/pulsar/

本文要點

  • 使存儲系統感知雲的傳統方式是直接遷移,這種方式表現良好,但從我們的經驗來看,重構雲感知架構效果更好。
  • 目前,在跨區域環境中部署 Apache BookKeeper 時需要手動將存儲節點映射到特定區域 / 可用性區域,但在區域中斷時,持久性和可用性會受到影響。
  • Salesforce 獨有的使 Apache BookKeeper 感知雲的方法是通過智能化存儲節點,讓其在雲中部署可以有效運轉,並保證持久性和可用性。
  • 這些方法簡化了集羣的改進、升級和重啟操作,對消費服務的影響最低。

在 Salesforce,我們需要可以同時處理兩種流的存儲系統:一種流用來預寫日誌,另一種流用來處理數據。但對這兩種流,我們的要求相互矛盾:預寫日誌流的寫入延遲低,而讀取吞吐量高;數據流的寫入吞吐量高,但隨機讀取延遲低。作為雲計算的領軍企業,我們的存儲系統必須具備雲感知能力(可用性和持久性要求越來越高)。為了在商用硬件上運行並方便擴容,我們無法更改部署模型設計。

開源方案

在對存儲系統進行初步研究後,我們考慮是自己搭建一套還是購買一套。

考慮到整體規劃和上市時間、資源、成本等主要的業務驅動因素,我們決定使用開源存儲系統。

在查看了開源代碼後,我們有兩個備選方案:Ceph 和 Apache BookKeeper。由於這套系統需要對客户開放,可擴展性和一致性都很重要,系統必須完全滿足用例的 CAP(Consistency:一致性;Availability:可用性;Partition Tolerance:分區容錯性)要求以及我們自己的特殊需求。首先,我們來看一下 BookKeeper 和 Ceph 在 CAP 和其他方面的表現。

Ceph 可以保證一致性和分區容錯,讀取路徑可以藉助不可靠讀取提供可用性和分區容錯;但要使寫入路徑保證可用性和分區容錯性並不容易。並且,我們不能更改部署數據。

我們決定選擇 Apache BookKeeper。BookKeeper 支持僅追加 / 不可變數據存儲,採用高可複製的分佈式日誌,滿足我們對系統 CAP 的要求。BookKeeper 還具備以下特點:

  • 已 Ack 的寫入始終可讀。
  • 已讀 Entry 始終可讀。
  • 無 Master 服務器,客户端使用 Apache ZooKeeper 實現共識(consensus)算法,獲取元數據。
  • 數據佈局無需複雜的哈希 / 計算。

Salesforce 也一直支持開源產品,Apache BookKeeper 社區積極活躍,充滿活力。

Apache BookKeeper——近乎完美,但還有改善空間

Apache BookKeeper 幾乎實現了我們對存儲系統的全部要求,但仍需做一些工作。首先來看一下 Apache BookKeeper 可以實現我們的哪些要求。

  • 存儲節點稱為 Bookie;一組 Bookie 稱為 Ensemble。
  • 寫入的最小單元為 Entry,Entry 不可更改。
  • 一組 Entry 稱為 Ledger,Ledger 僅可追加,不可更改。
  • 寫入或複製 Bookie 的數量稱為 Write Quorum——Entry 的最大副本數。
  • 確認寫入前 Bookie 的數量稱為 Ack quorum——Entry 的最小副本數。

從持久性來看,Ledger 跨 Bookie Ensemble 複製,Ledger 內的 Entry 可以跨 Ensemble。

寫入根據 Write Quorum 和 Ack Quorum(可配置)進行確認,從而保證低寫入延遲和高可擴展。

但實際上,在雲中的商用硬件上運行 BookKeeper 並不輕鬆。

數據佈局策略不具備雲感知能力,並且沒有顧及底層雲服務提供商(雲基礎設施)。目前,一些用户的部署方法是手動標識不同可用性區域中的節點,並進行邏輯分組,然後以組為單位改進數據佈局策略。這不失為一種解決方案,但不支持區域故障,也降低了維護和升級大型集羣時系統的易用性。

另外,所有云基礎設施的可用區域裏都出現過停機情況;而一般的理解是,應用程序要針對這些故障做相應的設計。一個很好的例子是,2012 年聖誕節期間,Amazon 網絡服務可用區域故障,Netflix 底層所依賴的公有云基礎設施停機,而 Netflix 服務仍然可以在有限的容量上運行。

公有云中的問題

公有云基礎設施易於擴展,在一定程度上降低了使用和維護的成本,因此,從網站到應用程序,甚至是企業級軟件,基本都在公有云服務提供商提供的基礎設施上運行。但是,公有云也有其缺陷,它在節點、區域或地區層面都可能出現不可用的情況。底層基礎設施不可用,用户什麼都做不了。起因可能是某些機器、區域或地區出現故障,也可能是由硬件故障引起的網絡延遲增加。所以最終當在公有云基礎設施上運行應用程序時,開發人員在設計時需要考慮由故障引發的問題。

Apache BookKeeper 本身不能解決這一問題,因此,我們需要自行設計一個修復程序。

Salesforce 重構

對問題有了一定的瞭解之後,我們開始考慮解決方案,讓 BookKeeper 具備雲感知能力,滿足我們的以下要求。

  • 在公有云集羣中的 Bookie 需要一個標識。
  • 根據可用區域內 Ensemble 的分佈設計數據佈局策略,實現更好的高可用,簡化維護和部署。
  • 改進 Bookie 已有的功能,如讀取、寫入、數據複製等,使 Bookie 可以充分利用多區域佈局的優勢,並計算跨區域傳輸數據的成本。
  • 上述工作和雲基礎設施無關。

我們的解決方案如下:

雲感知能力:Cookie 和 Kubernetes

現有的 BookKeeper 架構為所有 Bookie 提供唯一標識(在首次啟動時分配)。標識存儲在元數據存儲(ZooKeeper)中,其他 Bookie 或客户端可以訪問。

使 Apache BookKeeper 具有云感知能力的第一步是讓所有 Bookie 均可獲取它部署在 Kubernetes 集羣中的位置。我們認為 Cookie 數據是獲取位置信息的最佳方式。

因此,我們在 Cookie 中增加了 networkLocation 字段,它包含兩部分:可用區域和升級域,用於定位 Bookie。Kubernetes 和雲基礎設施無關,我們可以使用 Kubernetes API 來查詢底層的可用區域信息。我們還根據涉及主機名順序索引的公式生成了 upgradeDomain 字段。它可以用來滾動升級,而不影響集羣的可用性。

在機器啟動時生成上述字段和對應值,並保存在元數據存儲中供用户訪問。這些信息可以用於生成 Ensemble,分配 Bookie 到 Ensemble,以及確定從哪些 Bookie 複製數據,複製的數據存儲到哪些 Bookie。

公有云佈局策略

現在,客户端已經足夠智能,可以與某些區域中的 Bookie 進行通信,下一步便是確保有一個可以使用這一信息的數據佈局策略。我們開發了 ZoneAwareEnsemblePlacementPolicy(ZEPP)。這是一個針對基於雲部署而設計的兩級層次化佈局策略。ZEPP 可以獲取可用區(AZ)和 upgradeDomains(UD)信息。

AZ 是區域內隔離數據中心的邏輯概念;UD 是 AZ 內的一組節點,關閉 UD 不會影響服務,UD 還可以監測到區域的關閉和重啟。

下圖為 ZEPP 可採用的一種部署示意圖。這種部署方式兼顧了 Cookie 中的 AZ 和 UD 信息,並據此對 Bookie 節點進行分組。

可用性 & 延遲 & 成本

進行上述調整後,Apache BookKeeper 可以具備雲感知能力了。但成本也是設計架構時必須考慮的因素之一。大多數雲基礎設施對傳出服務的數據進行單向收費,跨可用區傳輸的費用會有所不同。這是 BookKeeper 客户端需要考慮的一個重要因素,因為它現在是從 Ensemble 中隨機選擇一個 Bookie 進行讀取。

如果 Bookie 和客户端屬於不同的可用區,會增加不必要的成本。數據複製可能發生在跨可用區的 Bookie 之間,當可用區出現故障時,使用成本會增加。

我們通過以下方式來處理這些特殊情況:

重排序讀取

目前,BookKeeper 客户端從 Ensemble 隨機選取 Bookie 進行讀取。藉助重排序讀取特性,現在客户端可以選擇 Bookie,從而減小讀延遲,降低成本。

啟用重排序讀取後,客户端按照以下順序選擇 Bookie:

  • 本地區域中滿足要求且待處理請求少的 Bookie;
  • 遠程區域中滿足要求且待處理請求少的 Bookie;
  • 本地區域中故障最少或待處理請求高於設定閾值的下一個 Bookie;
  • 遠程區域中故障最少或待處理請求高於設定閾值的下一個 Bookie。

按照上述順序,運行很長時間且出現過故障的系統也可以滿足我們對延遲與成本的要求。

處理區域故障

當區域關閉時,不同 Ensemble 中的所有 Bookie 都開始將數據複製到當前可用區域內的 Bookie 中,從而滿足 Ensemble Size 和 Quorum 要求,引起“驚羣問題”。

要解決這一問題,首先要確定區域關閉的時間。故障可能是暫時性的操作失誤,比如網絡故障引起區域不可用,我們不希望系統複製 TB 級的數據;但同時我們也要做好準備,應對真正的故障。我們的解決方案包含兩步:

  • 辨別區域是真正故障還是暫時故障;
  • 將整個區域的大規模自動複製轉換為手動操作。

下圖為區域關閉與重啟時我們的應對方案。

根據區域中可用 Bookie 數量和區域中 Bookie 總量可以計算出 HighWaterMark 和 LowWaterMark 的值。用户可以為這兩個值設置閾值,系統可以據此判斷故障情況,進而確定故障類型。

當區域標記為關閉時,我們會禁用自動複製,從而避免跨區域自動複製 TB 級的數據。此外,我們在數據複製的地方增加了告警,提示用户可能出現的區域故障。我們認為,運維專家能夠將噪聲與實際故障區分開,並決定是否開始自動複製整個區域的數據。

我們還可以通過 shell 命令啟動已禁用的 Bookie 自動複製。

我們的收穫

Apache BookKeeper 是一個開源項目,社區非常活躍,並一直在積極討論面臨的一系列挑戰。由於BookKeeper 是存儲數據的組件,對很多用户而言,其雲感知能力十分重要。

本文介紹的更改已在 Salesforce 進行了實戰驗證。目前,藉助 Apache BookKeeper ,我們已經可以支持 AZ 和 AZ + 1 故障。但是,這樣的架構更改必然會影響到可用性、延遲、成本、部署和維護的簡易性。社區已經接受了我們提交的一些更改,我們會繼續為社區做出貢獻。我們希望這些更改可以簡化集羣打補丁、升級、重啟的操作,同時儘可能降低對消費服務的影響。

關於作者

Anup Ghatage 任職於 Salesforce,主要負責雲基礎架構和數據工程,曾任職於 SAP 和 Cisco Systems,對維護和開發高可擴展的系統有濃厚興趣。他本科畢業於普納大學計算機專業,碩士畢業於卡耐基·梅隆大學。他是 Apache BookKeeper 的 committer,積極參與 Apache BookKeeper 的開發。歡迎在 Twitter 上關注 Anup(@ghatageanup )。

相關閲讀

點擊 鏈接 ,查看英文版原文。

「其他文章」