Longhorn 的正確使用姿勢:如何處理增量 replica 與其中的 snapshot/backup

語言: CN / TW / HK

作者簡介

吳碩,SUSE Senior Software Development Engineer,已為 Longhorn 專案工作近四年,是專案 maintainer 之一。

本文將介紹 Longhorn 的基本功能和架構,replica 和 backup 這兩個最重要的特性以及使用案例,幫助大家瞭解 Longhorn 的價值所在以及使用方法。

Longhorn 介紹

Longhorn 是一個輕量的、可靠易用的、為 Kubernetes 設計的分散式儲存系統,100% 開源,現已成為 CNCF 孵化專案。

Longhorn 作為儲存系統,最重要、最基本的功能就是為 Kubernetes 的工作負載提供持久儲存,我們稱為 Longhorn volume。它利用叢集工作節點本身的儲存裝置實現儲存,這種超聚合的方式是 Longhorn 的設計理念之一,也可以很好地和 SUSE 另外一個專案——Harvester 整合。

為了保證高可用性,Longhorn 首先支援跨節點或跨可用區(AZ)的資料複製,即 Replication。如果整個叢集或者恰好 volume 的所有 replica 都突然不可用,就需要將資料進一步備份(backup)到叢集外部了。

Longhorn 支援將資料上傳到 NFS 或者 S3 compatible 的儲存方案。利用外部的備份資料,Longhorn 可以做叢集級別的容災恢復。關於資料備份本身,使用者不可能每次手動發起請求,所以 Longhorn 支援週期性的 backup 和 snapshot,這個功能一般稱為 cron job 或者 recurring job。

關於 Longhorn 升級,我們的要求是不能夠影響使用者或者已經執行的 volume 讀寫,所以每次 Longhorn 版本升級都是無中斷升級。

今年 Longhorn 面向 VM 推出了新功能 backing image。假如使用者想要起數十個或者上百個 VM,為每個 VM 單獨下載一份一模一樣的 SLES 或 Ubuntu 等 image,是非常浪費時間和空間的。在這一場景下,客戶只需下載一份 image 作為只讀的底層檔案,並讓所有 VM 共用即可。

此外,Longhorn 還有更多擴充套件功能,在此就不一一贅述了。

Longhorn 提供了一套 GUI 介面,如下圖。使用者可以通過 GUI 檢視整體儲存狀況,管理可用的節點及相應的磁碟空間。

最重要的還是 volume 相關介面。開啟 Longhorn 詳細介面可以看到 volume 狀態、應用資訊以及 snapshot 相關資訊。

此外,還有 backup、recurring job、setting 等介面,絕大部分 Longhorn 本身相關配置都可以在 GUI 中完成。

關於更多 Longhorn 的功能和特點,大家可以自行根據官方網站的文件進行部署體驗。如之前所說,Longhorn 的部署和使用非常簡單直接。

Longhorn 的架構

整體架構和工作流程 當用戶在 Kubernetes 建立一個新的應用(Pod)並需要永續性儲存時,Kubernetes 就會通過 CSI(Container Storage Interface) API 向實現了這套介面的 Longhorn CSI Plugin 傳送請求;而這個 Longhorn CSI Plugin 則利用 Longhorn API,去和中間的 Longhorn Manager 互動並完成請求。

Longhorn Manager 是負責將系統抽象成 Kubernetes 資源(Custom Resource Definition) 並進行協調管理的元件。比如 volume 的建立和掛載(Attachment),就是 Longhron Manager 協調好相應的 Kuberntes 資源 (Custom Resource)後,啟動相應的程序來實現的。

一個 Longhorn Volume 是由一個 engine 與多個 replica 組成的。每一個 replica 都是 volume 資料的完整複製體。Engine 負責連線和控制這些 replica,並向 workload 提供 block device。

此外,Longhorn UI 也是通過 Longhorn API 完成所有的操作和功能。

Longhorn Volume 如何工作 假設有三個工作節點,每個節點都有相應的硬體,比如 CPU、Memory 和 SSD 磁碟。如前文提到,Replica 會直接利用同節點上的 SSD 來儲存資料,而 engine 則負責連線和控制 replica,並處理一些操作,volume 是對 engine 和所有 replica 的總結抽象。

一個 volume 通常有多個 replica 分佈在不同節點上,所以當一個節點宕掉時,其他節點上仍有完好可用的 replica。利用剩餘的完好 replica,我們可以快速重啟 volume 並恢復服務。如下圖,節點 1 宕機後,節點 2 上的 repica 仍然可用,因此我們可以快速在節點 3 上重啟 engine 並恢復 Pod A。由於節點 2 本身沒有宕掉,其中的 Pod B 和 Pod C,及其相應 Volume 的功能不會受到影響,受影響的只有 Volume 的高可用程度。

此外,Volume/Engine 的架構圖還反應了兩個事實。

其一,對於每一個節點來說,所有的 replica 都是由一個 Replica Instance Manager 管理的,engine 同理。這樣可以保證一個節點上可以執行多個 engine 或 replica。而 Instance Manager 之中的 engine/replica 互不干擾,獨立執行。

其二,每一個 volume 的 engine,和其 workload/pod 始終執行在同一個節點上。Instance Manager 功能比較穩定簡單,一般不會導致 engine 崩潰掉。所以一般 volume 或 engine 崩潰掉的的主要原因是所有 replica 同時崩潰,或當前節點突然不可用。換句話說,engine 和 workload 的生命週期通常是相同的,這樣 Longhorn 避免了在多個節點啟動多個 engine 來保障一個 volume 的高可用性。

關於更具體的細節,有興趣的讀者可以訪問 Longhorn 文件

使用案例 1

Longhorn 有何非用不可的理由?畢竟使用 Longhorn 意味著在儲存棧上額外加了一層,效能不可避免地會受到影響。Longhorn 是保證 crash consistency 這種強一致性的,這種強一致性會導致額外的 latency 和寫效能上的損失(不過讀效能反而會有所增加)。

當用戶使用公有云比如 AWS 時,他為什麼不直接使用 EBS Volume,轉而使用Longhorn 呢?因為 EBS 有一個很重要的問題——它無法跨可用區(AZ)做遷移。

如下圖,一個 EKS 在三個 zone 上面部署了工作節點,在 zone 1a 上的節點部署了一個 Pod 並使用了一個 EBS。當這個節點不可用導致 Pod 停掉時,想恢復這個 Pod,使用者就必須在其他兩個 zone 節點上重新部署 Pod,並重新掛載之前的 EBS Volume。這個時候的問題是,EBS Volume 無法跨區遷移,所以直接使用 EBS Volume,是無法處理這種情況的。

第二個痛點則是 AWS 的單個 instance 上可以掛載的 EBS Volume 是有限的,可能就十幾個。在現在容器化的應用場景裡,一個節點可能執行幾十或者上百個容器/pod,其中每個容器/pod 可能需要幾個永續性的儲存(或許單個儲存不需要太大),在這種情況下 EBS Volume 是遠遠不夠用的。

其三,EBS Volume 的 attachment/detachment 相對比較慢,大概是分鐘級,不能完美適用 Pod 經常遷移變動的情景。

如果使用 Longhorn,上述問題就不再是問題。首先,Longhorn volume 的 replica 是可以跨 AZ 來保障高可用性的。當 Zone 1a 節點掛掉時,Longhorn 可以馬上在 zone 1b 上重啟 engine 並直接連線剩餘的 replica,這樣 Pod 可以即刻恢復服務。

另一方面,Longhorn 也通過了 scalability 測試——在 10個節點的 cluster 掛載並使用 2000 個 Volume,即每個節點執行 200個 Volume 是沒有問題的。

最後 Longhorn Volume 的 attachment/detachment 相比 EBS Volume 非常快,通常 3~10 秒就夠了。

使用案例 2

有時候單叢集內的高可用是不太夠用的。如上文提到,當叢集宕機或者節點大規模掉線恰好導致 volume 的所有 replica 都不可用時,Longhorn 也需要確保儘快恢復服務。這時候我們就需要 backup。Backup 是指將 Volume 資料備份到外部的儲存空間,比如 NFS 或者 S3 相相容的儲存方案。

如下圖,當前 Primary Cluster (主叢集,正在提供服務的叢集)內有服務正在使用Longhorn volume,使用者就可以把 Volume 資料備份到 Backup Target 這個外部儲存中。而一旦有了 Backup Volume,使用者可以設定一個 Disaster Recovery Cluster(DR Cluser,災難恢復叢集, 當 Primary Cluster 掛掉時可以快速切換到此叢集以快速恢復服務),連線到同一個 Backup Target,並及時地將 Backup 恢復到叢集內的 DR volume 中備用。此時,Primary Cluster 內的 Volume 在被持續使用,會有新的資料寫入。Longhorn 就會僅將新寫入的資料繼續備份到之前的 Backup Volume,這稱之為 incremental backup (增量備份)。

一旦有新的資料被備份,DR Cluster 會檢測到變化,將新的資料繼續恢復到之前的 DR Volume。這樣即使存在延遲,但 DR volume 的資料基本是相應的 Volume 保持一致的。稍後,如果 Primary Cluster 突然宕機,使用者就可以立即啟用 DR cluster 並激活 DR Volume,以達到快速恢復服務的目的。

RPO 和 RTO:衡量整個災難恢復速度/能力的指標 RPO(Recovery Point Objective)即恢復點目標,指從上次備份到災難發生中間隔了多長時間,這個指標反映了(能容忍的)資料的丟失量。該指標實際由 backup 間隔決定,Backup 建立的間隔有多久,RPO 就有多久。

RTO(Recovery Time Objective)即恢復時間目標,指從災難發生到服務恢復需要多少時間。DR cluster 與 DR volume 的存在,就是為了儘可能地減少這個時間。假如沒有 DR cluster 或者 DR Volume,災難發生時,我們想盡快恢復服務,就要把所有的 Backup Volume 一口氣恢復到新的 ctuster 中。對於企業來說大概是 PB 級的資料,短時間恢復這麼大的資料所需要的時間非常長,可能幾個小時,或者幾天的時間,這對於企業來說是不太能接受的。

但是假設有一個 DR cluster,由於它會週期性地自動拉取最新備份的資料到 DR Volume 裡,只要檢測拉取的間隔合理,大部分情況下 DR Volume 裡都是含有最新的資料的,或者跟相應的 Volume 只差了一個備份週期以內的資料,恢復這部分資料可能僅需幾分鐘或者幾十分鐘。相比幾個小時或者幾天,恢復時間縮短了一個數量級,這就是為什麼說 DR Cluster 和 DR Volume 能縮短 RTO。簡而言之,通過配置 backup 和 restore 的間隔,使用者就能控制 RTO 和 RPO。

backup 是如何建立或者刪除的,以及 backup 本身的結構 如下圖,左邊是 Volume 的結構。這裡說一下,snapshot 本質是儲存了某個時間段的歷史資料,volume head 裡則是最新寫入的資料。所以讀取 volume 中某段資料,就是從最新的 volume head 開始,查詢這部分空間最近寫入的資料(在 volume head 或者某個 snapshot 中)。

簡而言之,我們讀取資料,包括備份時的資料讀取,都是從右往左讀。這時要為 snapshot2 建立 backup,首先要確定 snapshot2 這個點上 volume 的資料是什麼樣子的。以 snapshot2 為最右邊或者最近的檔案,從右往左看,能看到的資料是第一個 data block 在 snapshot1,後面兩個 data block 是在 snapshot2。這樣我們找到了 backup 對應的 snapshot,瞭解了包含這些 snapshot 中的哪些 data block,剩下的就是把資料上傳到 backup target 即可。

稍後,新的資料被寫入了,我們想要建立新的 backup,就先需要把當前的 volume head 變成 snapshot3 並基於 snapshot3 做 backup。這時候就重新從右往左看,也就是從 snapshot3,整個 Volume 就包含 5 個 data block。跟之前的 backup 相比,所差的資料就是 snapshot3 的資料。強調這個 delta 部分的原因是,之前 backup 過的資料是不需要重新上傳的,也就是隻需要備份新的資料,即 snapshot3 中的資料就可以。

backup deletion 也類似。比如我們要刪掉 snapshot 對應的 backup,就需要和前一個 backup 做對比。我們發現,有幾個 data block 是被前一個 backup 正在使用的,所以只能刪掉那些孤立的、僅被當前 backup 所指的 data block,這樣其他的 backup 不會被影響,這就是 deletion 的機制。當然這些 backup 相關操作都有一個檔案鎖來保護,所以不需要擔心 race condition 的問題。

最後,restore 也是類似的原理。如果是直接根據 snapshot2 的 backup 建立 DR volume,我們發現三個 data block 後,直接把它們恢復到對應的 DR Volume 裡就可以。而如果是拉取最新的(incremental) backup 資料,則是對比上一個 restore 過的 backup,把新增的 data block 拉取下來即可。

backup 在伺服器裡是什麼樣子?我們怎麼管理檔案呢?如下圖,由於這個 backup volume 可能有很多的 backup,每個 backup 就有一個對應的元資料檔案 snap.cfg,主要記錄這些 backup 由哪些 data block 組成。剩下的就是 data block,可能是被一個或者多個 backup 引用。這就是關於 backup 和 restore 的全部基本介紹。