雲原生|新東方在有狀態服務 In K8s 的實踐

語言: CN / TW / HK

有狀態服務建設一直以來都是 K8s 中非常具有挑戰性的工作,新東方在有狀態服務雲化過程中,採用定製化 Operator 與自研本地存儲服務結合的模式,增強了 K8s 原生本地存儲方案的能力,在摸索中穩步推進企業的容器化建設。

新東方有狀態服務 In K8s 的現狀

file

<center><b/>新東方有狀態服務現狀示意圖</center>

如上圖所示,上層 Pod 由自定義的 Operator 和 StatefulSet 控制器來託管,Pod 關聯 PVC,PVC 綁定 PV,最下層是存儲服務。

最下層的存儲服務包含本地存儲和遠端存儲兩類,對於一般的存儲需求,首選是遠端存儲服務;而對於高性能 IO 的存儲需求,那就要選擇本地存儲服務。目前,本地存儲服務包含 K8s 原生 local 存儲服務和自研的 xlss 存儲服務 2 種。

原生 K8s 支撐有狀態服務的能力

原生 K8s 支撐有狀態服務的能力是有狀態服務建設的基礎,其管理模式是:StatefulSet 控制器 + 存儲服務。

StatefulSet 控制器

StatefulSet 控制器:

用來管理有狀態應用的工作負載 API 對象的控制器。管理某 Pod 集合的部署和擴縮,併為這些 Pod 提供持久存儲和持久標識符。

StatefulSet 資源的特點:

  • 穩定的、唯一的網絡標識

  • 穩定的、持久的存儲

  • 有序的、優雅的部署和縮放

  • 有序的、自動的滾動更新

StatefulSet 資源的侷限:

  • 關於存儲,StatefulSet 控制器是不提供存儲供給的。

  • 刪除或者縮容時,StatefulSet 控制器只負責 Pod。

  • 人工要建一個無頭服務,提供每個 Pod 創建唯一的名稱。

  • 優雅刪除 StatefulSet,建議先縮放至 0 再刪除。

  • 有序性也導致依賴性,比如編號大的 pod 依賴前面 pod 的運行情況,前面 pod 無法啟動,後面 pod 就不會啟動。

這 5 點侷限可進一步概括為:StatefulSet 控制器管理 Pod 和部分存儲服務(比如擴容時 pvc 的創建),其它的就無能為力。有序性引起的依賴性也會帶來負面影響的,需要人工干預治癒。

存儲服務

Cloud Native Storage

file

<center>CNS Of CNCF</center>

這是 CNCF 官網關於雲原生存儲的一副截圖。截圖時間是 2021 年 7 月初,有 50 多種存儲產品,接近半數屬於商業產品,開源產品多數都是遠端存儲類型,有支持文件系統的、有支持對象存儲的、還有支持塊存儲的。

K8s PV 類型

file

<center>PV Type Defined by K8s</center>

數據來源於官網,原生 K8s 支持的 PV 類型,有常用的 rbd、hostpath、local 等類型。

如何選擇?

控制器只有 StatefulSet 控制器可使用,存儲產品很多,PV 類型也不少,該怎麼選擇呢?

file

<center>存儲服務考慮因素示意圖</center>

選擇存儲產品,需要考慮哪些因素呢?新東方在選擇存儲產品時考慮了以下一些因素:

  • 開源 VS 商業

  • 本地 VS 遠端

  • 動態供給 VS 靜態供給

  • 數據高可用方案

做選擇是令人頭疼的事情,比如選擇開源,好處是不用花錢,但穩定性就很難保證,甚至提供的能力也有限;商業產品能力和穩定性有保證,但要付費。在這裏先不下結論,最終還是要看需求。

自研存儲產品 XLSS

關鍵需求

新東方有狀態服務建設的關鍵需求:良好的性能,支持 IO 密集型應用;數據可用性,具有一定的容災能力;動態供給,實現有狀態服務的完全自動化管理。

XLSS 介紹

file

<center>XLSS</center>

XLSS(XDF Local Storage Service)中文全稱:新東方本地存儲服務產品,是一種基於本地存儲的高性能、高可用存儲方案。可以解決 K8s 中本地存儲方案的不足之處:localpv 只能靜態供給;使用 localpv 時,pod 與 node 的親和性綁定造成的可用性降低;本地存儲存在數據丟失的風險。

應用場景

  • 高性能應用,IO 密集型的應用軟件,比如 Kafka

  • 本地存儲的動態化管理

  • 數據安全,應用數據定期備份,備份數據加密保護

  • 存儲資源監控吿警,比如 K8s Pv 資源的使用量監控吿警

XLSS In K8s

file

<center>XLSS In K8s</center>

如上圖所示,XLSS 在 K8s 中的運行狀態是 Xlss 的 3 個組件以容器形式運行在 K8s 集羣中,使用本地存儲為有狀態服務提供存儲服務,並定期執行數據的備份作業,Xlss 會提供有關存儲和相關作業的 metrics 數據。

XLSS 核心組件介紹

Xlss 主要組件包含:

<b/>xlss-scheduler

  • 基於 kube-scheduler 的自定義調度器

  • 對於有狀態服務的 pod 的調度,自動識別 xlss localpv 的使用身份,智能干預 pod 調度,消除 pod 與 node 的親和性綁定造成的可用性降低

<b/>xlss-rescuer

  • 以 DaemonSet 資源類型運行在 k8s 集羣中

  • 按照數據備份策略,執行數據備份作業

  • 監視數據恢復請求,執行數據恢復作業

  • 提供 metrics 數據

<b/>xlss-localpv-provisioner

  • 動態供給本地存儲

xlss-scheduler 關鍵邏輯實現思路

file

<center>K8s 調度框架模型</center>

如上圖,這是 K8s 調度器的調度框架模型,在調度流程中包含了許多擴展點。xlss-scheduler 就是基於該調度框架模型,通過編寫自定義的插件實現,主要在 3 個擴展點上做了增強:

  • Prefilter:依據 Pod 的節點親和性,分析親和性節點的健康狀態,若節點異常,對 Pod 設置特殊標記。

  • Filter:針對設置特殊標記的 Pod,解除節點親和性。

  • Prebind:對設置特殊標記的 Pod,刪除特殊標記,根據調度結果,發送數據恢復請求。

xlss-rescuer 數據備份作業實現邏輯

file

<center>數據備份作業實現邏輯</center>

圖中 3 個部分,左右各一個循環邏輯,中間通過一個緩存隊列實現通信。左邊的循環實現的功能:收集備份作業策略,並更新到緩存隊列中。主要 3 步:

  • watch pod 事件

  • 從 pod 註解當中獲取備份策略,備份作業的配置信息是通過 pod 註解實現的

  • 同步備份策略到緩存隊列

右邊的循環實現的功能:執行備份作業。也是 3 步:

  • 對緩存隊列元素排序,排序按照下次備份作業的執行時間點進行升序排列

  • 休眠等待,若當前時間還沒有到最近的一個備份作業執行時間,就會進行休眠等待

  • 執行備份作業

xlss-rescuer 數據恢復作業實現邏輯

file

<center>數據恢復作業實現邏輯</center>

數據恢復作業流程和數據備份作業流程實現思路是類似的,但在具體實現邏輯上有所不同。

左邊的循環實現的功能:監視恢復作業請求,並更新到緩存隊列中。主要 3 步:

  • watch CRD,監視數據恢復請求,接收 xlss-scheduler 發出的數據恢復請求(數據恢復請求以 CRD 方式實現)

  • 分析 CRD 狀態,避免重複處理

  • 同步恢復請求到緩存隊列

右邊的循環實現的功能:執行恢復作業。這裏是 4 步:

  • 更新 CRD 實例狀態

  • 恢復快照數據到指定目錄

  • 更新 PV 與 PVC

  • 刪除 CRD 實例

xlss-localpv-provisioner 存儲創建實現思路

file

<center>本地存儲動態創建示意圖</center>

xlss-localpv-provisioner 組件,其功能比較專一,實現本地存儲的動態創建。其工作流程當 provisioner pod 獲取到創建存儲的請求時,首先會創建一個臨時的 helper pod,這個 helper pod 會被調度到指定的 node 上面,創建文件目錄作為本地存儲使用,這就完成了 pv 實際後端存儲的創建,當存儲創建完畢,provisioner pod 會將這個 helper pod 刪除。至此,一次本地存儲的動態創建完成。

xlss 自動災難恢復工作流程

file

<center>xlss 自動災難恢復工作流程</center>

完整的自動災難恢復工作流程要經歷 6 個階段:

  • 數據備份:以 pod 為粒度,對 pv 數據進行備份。

  • 節點異常:此時集羣出現異常情況,某一節點發生異常,比如服務器損壞,引起在其上面的 pod 工作異常,最後有狀態服務的 pod 就會一直處於 Terminating 狀態。

  • 異常 pod 處理:當有狀態服務的 pod 處於 Terminating 狀態時,要清理掉這些 pod,可以手動刪除,也可藉助工具,讓這些有狀態的 pod 有重新創建的機會。

  • 智能調度 :解除親和性,將新 pod 調度到健康的節點上。

  • 數據恢復:拉取該 pod 對應的最新的快照數據進行數據恢復。

  • 服務恢復:啟動應用,對外提供服務。

至此,一個完整的自動災難恢復工作流程結束,最後又回到起點。

大規模存儲型中間件服務

存儲問題基本解決了,那該怎麼落地呢?答案就是建設存儲型中間件服務。

Kafka Cluster In K8s

file

<center>Kafka Cluster In K8s</center>

以 kafka 集羣為例,通過定製化的 kafka operator 來部署 kafka 集羣,指定存儲服務使用 xlss 存儲。採取定製化 Operator + xlss 模式去建設存儲型中間件服務。

有狀態中間件服務 In K8s

file

<center>Stateful Apps In K8s</center>

有狀態中間件服務在 K8s 中的運行狀態如上圖所示,這些存儲型中間件服務集羣託管於對應的 Operator,底層存儲根據業務需要適配各類存儲。隨着中間件服務集羣規模的日益擴大,我們建設了 PaaS 控制面,用户可以通過該控制面來管理運行在 K8s 中的各類中間件服務集羣。控制面可以直接和 apiserver 交互,用户通過控制面增刪改 CRD 資源,Operator 根據 CRD 資源的最新狀態,調和中間件服務集羣的狀態。

用户申請中間件服務示例

file

<center>用户申請中間件服務示例</center>

這是用户申請中間件服務的示例:用户通過管理台申請服務,填寫相關的配置信息後,申請通過後,就可以在 K8s 集羣裏面創建相應的服務了。

基於 KubeSphere 部署 XLSS

<b/>如果希望使用 xlss 存儲,那該怎麼部署呢?

若是首次部署,首先要做好本地磁盤的規劃,創建好提供給 xlss 使用的存儲空間。然後,就是將 xlss 的各個組件運行到 K8s 集羣中。將 xlss 組件部署到 K8s 集羣中,我們藉助了 KubeSphere 的 CI/CD 流水線。自定義流水線一共 5 步,實現將 xlss 組件從靜態代碼到運行在 K8s 中的容器的轉換,高度自動化維護。

<b/>CI/CD 流水線如下圖所示:

file

<center>CI/CD 流水線</center>

Road Map

file

<center>Road Map</center>

目前,新東方的有狀態服務容器化建設大致可分成 4 階段。

<b/>第一階段:“雲前時代”。

有狀態服務容器化的起點,確定了容器化的目標。這個階段有狀態服務主要特徵是 VM+PaaS 組合的模式管理有狀態服務。實現的主要功能:資源管理、白屏運維、簡單調度策略、運行時管理。

<b/>第二階段:“初上雲端”。

從這個階段開始,嘗試將有狀態服務從 VM 中解脱出來,遷移到 K8s 平台。這個階段有狀態服務主要特徵是 K8s+Operator 組合的模式管理有狀態服務。

這時,運行時被託管到 K8s,有狀態服務由 Opeartor 接管,自動化程度顯著提高。此時也暴露出一些不足:比如遠端存儲的性能不夠好,本地存儲的可用性不能保證。

<b/>第三階段:“自研之路”。

主要是新東方自研 xlss 的實踐階段,前面章節已有涉及。此階段有狀態服務建設的典型特徵:Scheduler + Logical Backup 組合模式。這基本達到了我們期望的:本地存儲 + 動態供給 + 數據可用性保證。但事情永遠都不會那麼完美,那還有那些瑕疵呢?

  • 數據恢復時長取決於數據量大小,如果數據量很大,恢復時間也會增大,在 node 異常發生的情況下,這就增大了有狀態服務的不可用時間。

  • 現在 PV 數據還沒能做到存儲隔離,無法約束應用對存儲的使用量,會存在一定的風險。

瑕不掩瑜,在小規模存儲場景:如 redis、kafka 等還是有用武之地的,但是對於大數據量的服務,目前 xlss 的能力還有些勉強。

<b/>第四階段:“追求卓越”。

在這個階段,有狀態服務建設的典型特徵:Isolation + Physical Backup 組合模式。重點會解決第三階段發現的瑕疵。大致的解決思路是:利用 LVM 技術實現存儲的隔離;利用 DRBD 技術,增加 DRBD 同步物理備份能力,實現應用數據的同步實時備份,解決由於數據量大導致恢復時間增長的問題。

在使用 DRBD 技術時,有一個需要權衡的地方,那就是副本數量的設置。若副本數量設置多些,則會增大存儲資源使用量;若副本數量設置少些,在 K8s 集羣 node 異常情況下,有狀態服務 Pod 漂移可選擇的 node 數量就會減少。最終需要根據業務場景做出合理選擇。

本文由博客一文多發平台 OpenWrite 發佈!