從兩個模型帶你瞭解DAOS 分散式非同步物件儲存
摘要:分散式非同步物件儲存 (DAOS) 是一個開源的物件儲存系統,專為大規模分散式非易失性記憶體 (NVM, Non-Volatile Memory) 設計,利用了 SCM(Storage-Class Memory) 和 NVMe(Non-Volatile Memory express) 等的下一代 NVM 技術。
分散式非同步物件儲存 (DAOS) 是一個開源的物件儲存系統,專為大規模分散式非易失性記憶體 (NVM, Non-Volatile Memory) 設計,利用了 SCM(Storage-Class Memory) 和 NVMe(Non-Volatile Memory express) 等的下一代 NVM 技術。
DAOS 是一種橫向擴充套件的物件儲存,可以為高效能運算應用提供高頻寬、低延遲和高 IOPS 的儲存容器,並支援結合模擬、資料分析和機器學習的下一代以資料為中心的工作流程。
與主要針對旋轉介質設計的傳統儲存堆疊不同,DAOS 針對全新 NVM 技術進行了重新構建,可在使用者空間中端對端地執行,並能完全繞開作業系統,是一套輕量級的系統。
DAOS 提供了一種為訪問高細粒度資料提供原生支援的 I/O 模型,而不是傳統的基於高延遲和塊儲存設計的 I/O 模型,從而釋放下一代儲存技術的效能。
與傳統的緩衝區不同,DAOS 是一個獨立的高效能容錯儲存層,它不依賴其它層來管理元資料並提供資料恢復能力。DAOS 伺服器將其元資料儲存在持久記憶體中,而將批量資料直接儲存在 NVMe 固態盤中。
DAOS 特性
DAOS 依靠 OFI(OpenFabric Interface) 繞過作業系統,將 DAOS 操作交付給 DAOS 儲存伺服器,充分利用架構中的任何遠端直接記憶體訪問 (RDMA, Remote Direct Memory Access) 功能,進行低延遲、高訊息速率的使用者空間通訊,並將資料儲存在持久記憶體和 NVMe 固態盤中。
DAOS 的鍵值儲存介面提供了統一的儲存模型,通過遷移 I/O 中介軟體庫實現對 DAOS API 的原生支援後,就能利用 DAOS 豐富的 API 和先進功能,例如 HDF5、MPI-IO 和 Apache Arrow。
DAOS 還提供 POSIX 的模擬。POSIX 不再是新資料模型的基礎,而是像其他 I/O 中介軟體一樣,POSIX 介面將構建為 DAOS 後端 API 頂部的庫。
DAOS 的 I/O 操作會被記錄並存儲到 SCM 維護到持久索引中,每次 I/O 都用一個特定時間戳標記,並與資料集的特定版本關聯。內部不執行讀-修改-寫 (read-modify-write) 操作,寫入操作是無損的,對對齊不敏感。在讀取請求時,DAOS 伺服器遍歷持久索引,建立聚合 RDMA 描述符,從而直接在應用程式提供的緩衝區中重建所請求的版本的資料。
SCM 直接對映到 DAOS 服務地址空間的記憶體,DAOS 服務通過直接載入/儲存來管理持久索引。根據不同 I/O 的特性,DAOS 服務可以決定將 I/O 儲存在 SCM 或 NVMe 中:
- 對延遲敏感的I/O(如應用程式元資料和位元組粒度資料)通常儲存在 SCM 中;
- 檢查點和批量資料儲存在 NVMe 中。
這種方法允許 DAOS 將資料流式傳輸到 NVMe 中,並在 SCM 中維護內部元資料索引,為批量資料提供原始 NVMe 頻寬。持久記憶體開發工具包 PMDK 管理對 SCM 的事務性訪問,儲存效能開發工具包 SPDK 對 NVMe 裝置進行使用者空間 I/O 操作。
DAOS 可以提供:
- 超高細粒度、低延遲和真正零拷貝的 I/O
- 非阻塞型資料和元資料操作,以支援 I/O 和計算重疊
- 先進的資料放置,以解決故障域
- 由軟體管理冗餘,可通過線上重建,支援複製和擦除程式碼
- 端到端 (E2E) 資料完整性
- 可擴充套件的分散式事務,提供可靠的資料一致性和自動恢復功能
- 資料集快照功能
- 安全框架,用於管理儲存池的訪問控制
- 軟體定義儲存管理,用於調配、配置、修改和監控儲存池
- 通過 DAOS 資料模型和 API,為 I/O 中介軟體庫(例如 HDF5、 MPI-IO 和 POSIX)提供原生支援。應用無需移植程式碼,即可直接使用 DAOS API
- Apache Spark 整合
- 使用釋出/訂閱 API,實現原生生產者/消費者工作流程
- 資料索引和查詢功能
- 儲存內計算,以減少儲存和計算節點之間的資料移動
- 容災工具
- 與 Lustre 並行檔案系統無縫整合,並能擴充套件到其他並行檔案系統,從而為跨多個儲存層的資料訪問提供統一的名稱空間
- 資料搬運器,用於在 DAOS 池之間遷移資料集,將資料集從並行檔案系統遷移到 DAOS,反之亦然
DAOS 元件
一個數據中心可能有數十萬個計算節點,通過一個可伸縮的高效能結構相互連線,其中所有節點或稱為儲存節點的節點子集都可以直接訪問 NVM 儲存。
DAOS 安裝涉及幾個可以集中或分散式的元件。
DAOS 系統和儲存節點
DAOS系統由一個系統名標識,它由一組連線到同一結構的 DAOS 儲存節點組成。DAOS 儲存節點為每個節點執行一個 DAOS 服務例項,該例項為每個物理套接字啟動一個 DAOS I/O 引擎程序。這些 DAOS 服務的資訊被記錄到系統對映中,該對映為每個 I/O 引擎程序分配一個唯一的整數秩。兩個不同的 DAOS 系統由兩組不相交的 DAOS 伺服器組成,它們之間無法相互配合。
DAOS 服務
DAOS 服務是一個多租戶守護程序,執行在每個儲存節點的 Linux 例項上(物理節點、虛擬機器或容器)。服務的 I/O 引擎子程序通過網路匯出本地連線的 SCM 和 NVM 儲存。服務監聽一個管理埠(由 IP 地址和 TCP 埠號定址),以及一個或多個結構端點(由網路 URI 定址)。
DAOS 服務通過 /etc/DAOS 中的 YAML 檔案進行配置,包括其 I/O 引擎子程序的配置。服務的啟動可以與不同的守護程序管理或編排框架整合(systemd 指令碼、Kubernetes 服務、或類似 pdsh 和 srun 的並行啟動程式)。
I/O引擎
在 DAOS I/O 引擎中,儲存靜態地跨越多個 Target 分割槽,增強併發能力。為了避免競爭,每個 Target 都有其私有儲存、自己的服務執行緒池以及專用的網路上下文,這些上下文可以直接通過結構定址,而不依賴於託管在同一儲存節點上的其他 Target 。
SCM 模組通常以 AppDirect interleaved 模式配置。因此,它們作為每個套接字(在 fsdax 模式)的單個 PMEM 名稱空間呈現給作業系統。當配置每個 I/O 引擎的 N 個 Target 時,每個 Target 都使用該套接字 fsdax 的 SCM 容量的 \frac{1}{N}N1,與其它 Target 獨立。每個 Target 還使用連線到此套接字的 NVMe 驅動器容量的一小部分。
Target
Target 沒有針對儲存介質故障實現任何內部資料保護機制。因此,一個 Target 就是一個單點故障,同時也是故障單元。動態狀態與每個 Target 相關聯:其狀態可以是“up and running”,也可以是“down and not available”。
Target 是效能的單位。與 Target 關聯的硬體元件(如後端儲存介質、CPU 核心和網路)的能力和容量有限。
DAOS I/O 引擎例項匯出的 Target 數是可配置的,取決於底層硬體(I/O 引擎例項的 SCM 模組數和 NVMe SSD 數)。I/O 引擎的 Target 數的最佳配置是該 I/O 引擎服務的 NVMe 驅動器數的整數倍。
儲存 API、應用程式介面和工具
應用程式、使用者和管理員可以通過兩個不同的客戶端 API 與 DAOS 系統互動。
管理 API 提供了管理 DAOS 系統的介面。它旨在與不同供應商的儲存管理或開源編排框架整合。dmg 命令列工具是在 DAOS 的管理 API 上構建的。
DAOS 庫 libdaos 實現了 DAOS 儲存模型,主要提供給希望在 DAOS 系統中儲存資料集的應用程式和 I/O 中介軟體的開發人員。使用者常用的 daos 命令等的也構建在 API 之上,允許使用者通過命令列管理資料集。
應用程式可以通過本機 DAOS API、I/O 中介軟體庫(如 POSIX 模擬、MPI-IO、HDF5)或已與本機 DAOS 儲存模型整合的 Spark 或 TensorFlow 等框架直接訪問儲存在 DAOS 中的資料集。
代理
DAOS 代理是駐留在客戶端節點上的守護程序,通過與 DAOS 庫互動驗證應用程式程序。它是一個可信任的實體,支援使用證書對 DAOS 客戶端進行簽名。DAOS 代理支援不同的身份驗證框架,並使用 Unix 域套接字與客戶端庫通訊。
儲存模型
DAOS Pool 是分佈在 Target 集合上的儲存資源預留。分配給每個 Target 上的 Pool 的實際空間稱為 Pool Shard。
分配給 Pool 的總空間在建立時確定,後期可以通過調整所有 Pool Shard 的大小(在每個 Target 專用的儲存容量限制內)或跨越更多 Target(新增更多 Pool Shard)來隨時間擴充套件。
Pool 提供了儲存虛擬化,是資源調配和隔離的單元。DAOS Pool 不能跨多個系統。
一個 Pool 可以承載多個稱為 DAOS Container 的事務物件儲存。每個 Container 都是一個私有的物件地址空間,可以對其進行事務性修改,並且獨立於儲存在同一 Pool 中的其他 Container。Container 是快照和資料管理的單元。屬於 Container 的 DAOS 物件可以分佈在當前 Pool 的任何一個 Target 上以提高效能和恢復能力,並且可以通過不同的 API 訪問,從而高效地表示結構化、半結構化和非結構化資料。
下表顯示了每個 DAOS 概念的目標可伸縮性級別:
DAOS Pool
Pool 由唯一的 Pool UUID 標識,並在稱為 Pool 對映的持久版本控制列表中維護 Target 成員身份。成員資格是確定的和一致的,成員資格的變更是按順序編號的。Pool 對映不僅記錄活躍 Target 的列表,還以樹的形式包含儲存拓撲,用於標識共享公共硬體元件的 Target。例如,樹的第一級可以表示共享同一主機板的 Target,第二級可以表示共享同一機架的所有主機板,最後第三級可以表示同一機房中的所有機架。
該框架有效地表示了層次化的容錯域,然後使用這些容錯域來避免將冗餘資料放置在發生相關故障的 Target 上。在任何時候,都可以將新 Target 新增到 Pool 對映中,並且可以排除失敗的 Target。此外,Pool 對映是完全版本化的,這有效地為對映的每次修改分配了唯一的序列,特別是對於失敗節點的刪除。
Pool Shard 是永久記憶體的預留,可以選擇與特定 Target 上 NVMe 預先分配的空間相結合。它有一個固定的容量,滿了就不能執行。可以隨時查詢當前空間使用情況,並報告 Pool Shard 中儲存的任何資料型別所使用的總位元組數。
一旦 Target 失敗並從 Pool 對映中排除,Pool 中的資料冗餘將自動線上恢復。這種自愈過程稱為重建。重建進度定期記錄在永久記憶體中儲存的 Pool 中的特殊日誌中,以解決級聯故障。新增新 Target 時,資料會自動遷移到新新增的 Target,以便在所有成員之間平均分配佔用的空間。這個過程稱為空間再平衡,使用專用的永續性日誌來支援中斷和重啟。
Pool 是分佈在不同儲存節點上的一組 Target,在這些節點上分佈資料和元資料以實現水平可伸縮性,並使用複製或糾刪碼 (erasure code) 確保永續性和可用性。
建立 Pool 時,必須定義一組系統屬性以配置 Pool 支援的不同功能。此外,使用者還可以定義將持久儲存的屬性。
Pool 只能由經過身份驗證和授權的應用程式訪問。DAOS 支援多種安全框架,例如 NFSv4 訪問控制列表或基於第三方的身份驗證 (Kerberos)。連線到 Pool 時強制執行安全性檢查。成功連線到 Pool 後,將嚮應用程式程序返回連線上下文。
如前文所述,Pool 儲存許多不同種類的永續性元資料,如 Pool 對映、身份驗證和授權資訊、使用者屬性、特性和重建日誌。這些元資料非常關鍵,需要最高級別的恢復能力。因此,Pool 的元資料被複制到幾個來自不同高階容錯域的節點上。對於具有數十萬個儲存節點的非常大的配置來說,這些節點中只有很小的一部分(大約幾十個)執行 Pool 元資料服務。在儲存節點數量有限的情況下,DAOS 可以依賴一致性演算法來達成一致,在出現故障時保證一致性,避免腦裂。
要訪問 Pool,使用者程序應該連線到 Pool 並通過安全檢查。一旦授權,Pool 就可以與任何或所有對等應用程式程序(類似 openg() POSIX 擴充套件)共享(通過 local2global() 和 global2local() 操作)連線。這種集體連線機制有助於在資料中心上執行大規模分散式作業時避免元資料請求風暴。當發出連線請求的原始程序與 Pool 斷開連線時,Pool 連線將被登出。
DAOS Container
Container 代表 Pool 中的物件地址空間,由 Container UUID 標識。
下圖顯示了使用者(I/O 中介軟體、特定領域的資料格式、大資料或 AI 框架等)如何使用 Container 來儲存相關資料集:
與 Pool 一樣,Container 可以儲存使用者屬性。Container 在建立時必須傳遞一組屬性,以配置不同的功能,例如校驗和。
要訪問 Container,應用程式必須首先連線到 Pool,然後開啟 Container。如果應用程式被授權訪問 Container,則返回 Container 控制代碼,它的功能包括授權應用程式中的任何程序訪問 Container 及其內容。開啟程序可以與所有對等程序共享此控制代碼。它們的功能在 Container 關閉時被撤銷。
Container 中的物件可能具有不同的模式,用於處理資料分佈和 Target 上的冗餘,定義物件模式所需的一些引數包括動態或靜態條帶化、複製或糾刪碼。Object 類定義了一組物件的公共模式屬性,每個 Object 類都被分配一個唯一的識別符號,並在 Pool 級別與給定的模式相關聯。一個新的 Object 類可以在任何時候用一個可配置的模式來定義,這個模式在建立之後是不可變的(或者至少在屬於這個類的所有物件都被銷燬之前)。
為了方便起見,在建立 Pool 時,預設情況下會預定義幾個最常用的 Object 類:
如下所示,Container 中的每個物件都由一個唯一的 128 位物件地址標識。物件地址的高 32 位保留給 DAOS 來編碼內部元資料,比如 Object 類。剩下的 96 位由使用者管理,在 Container 中應該是唯一的。只要保證唯一性,棧的上層就可以使用這些位來編碼它們的元資料。DAOS API 為每個 Container 提供了 64 位可伸縮物件 ID 分配器。應用程式要儲存的物件 ID 是完整的 128 位地址,該地址僅供一次性使用,並且只能與單個物件模式相關聯。
<---------------------------------- 128 bits ----------------------------------> -------------------------------------------------------------------------------- |DAOS Internal Bits| Unique User Bits | -------------------------------------------------------------------------------- <---- 32 bits ----><------------------------- 96 bits ------------------------->
Container 是事務和版本控制的基本單元。所有的物件操作都被 DAOS 庫隱式地標記為一個稱為 epoch 的時間戳。DAOS 事務 API 允許組合多個物件更新到單個原子事務中,並基於 epoch 順序進行多版本併發控制。所有版本更新都可以定期聚合,以回收重疊寫入所佔用的空間,並降低元資料複雜性。快照是一個永久引用,可以放置在特定的 epoch 上以防止聚合。
Container 元資料(快照列表、開啟的控制代碼、物件類、使用者屬性、屬性和其他)儲存在永續性記憶體中,並由專用 Container 元資料服務維護,該服務使用與父元資料 Pool 服務相同的複製引擎或自己的引擎,這在建立 Container 時是可配置的。
與 Pool 一樣,對 Container 的訪問由 Container 控制代碼控制。要獲取有效的控制代碼,應用程式程序必須開啟 Container 並通過安全檢查。然後,可以通過 Container 的 local2global() 和 global2local() 操作與其他對等應用程式程序共享此控制代碼。
DAOS Object
為了避免傳統儲存系統常見的擴充套件問題和開銷,DAOS 有意將物件簡化,不提供型別和架構之外的預設物件元資料。這意味著系統不維護時間、大小、所有者、許可權,甚至不跟蹤開啟者。
為了實現高可用性和水平伸縮性,DAOS 提供了許多物件模式(複製/糾刪碼、靜態/動態條帶化等)。模式框架是靈活的,並且易於擴充套件,以允許將來使用新的自定義模式型別。模式佈局是在物件識別符號和 Pool 對映開啟的物件上通過演算法生成的。通過在網路傳輸和儲存期間使用校驗和保護物件資料,確保了端到端的完整性。
可以通過不同的 API 訪問 DAOS 物件:
- Multi-level key-array API 是具有區域性性特徵的本機物件介面。金鑰分為分發金鑰 (dkey) 和屬性金鑰 (akey)。dkey 和 akey 都可以是可變長度的型別(字串、整數或其它複雜的資料結構)。同一 dkey 下的所有條目都保證在同一 Target 上並置。與 akey 關聯的值可以是不能部分修改的單個可變長度值,也可以是固定長度值的陣列。akeys 和 dkey 都支援列舉。
- Key-value API 提供了一個簡單的鍵和可變長度值介面。它支援傳統的 put、get、remove 和 list 操作。
- Array API 實現了一個由固定大小的元素組成的一維陣列,該陣列的定址方式是 64 位偏移定址。DAOS 陣列支援任意範圍的讀、寫和 punch 操作。
事務模型
DAOS API 支援分散式事務,允許將針對屬於同一 Container 的物件的任何更新操作組合到單個 ACID 事務中。分散式一致性是通過基於多版本時間戳排序的無鎖樂觀併發控制機制提供的。DAOS 事務是可序列化的,可以在特定的基礎上獲取部分需要的資料集。
DAOS 版本控制機制允許建立持久的 Container 快照,該快照提供 Container 的實時分佈一致性檢視,該檢視可用於構建生產者-消費者管道。
Epoch 和時間戳
每個 DAOS I/O 操作都有一個稱為 epoch 的時間戳。epoch 是一個 64 位整數,它集成了邏輯和物理時鐘(詳見 HLC paper)。DAOS API 提供了輔助函式,用於將 epoch 轉換為傳統的 POSIX 時間(即 struct timespec,詳見 clock_gettime(3))。
Container 快照
如下圖所示,Container 的內容可以隨時快照。
DAOS 快照非常輕量級,並且使用與建立快照的時間相關聯的 epoch 進行標記。一旦建立成功,快照將一直保持可讀性,直到它被顯式銷燬。在特定快照未被銷燬前,Container 的內容可以回滾到該快照。
Container 快照功能支援本機生產者/消費者管道:
一旦成功寫入資料集的一致版本,生產者 (Producer) 將生成一個快照。使用者 (Consumer) 的應用程式可以訂閱 Container 快照事件,以便在生產者提交更新時可以處理新的更新。
快照的不變性保證了使用者可以看到一致的資料,即使生產者繼續進行新的更新。生產者和消費者實際上都在 Container 的不同版本上操作,不需要任何序列化操作。一旦生產者生成了資料集的新版本,使用者就可以查詢兩個快照之間的差異,並且只處理增量修改。
分散式事務
與 POSIX 不同,DAOS API 不強制執行最壞情況下的併發控制機制來處理衝突的 I/O 操作。相反,各個 I/O 操作被標記為不同的 epoch,並按照 epoch 的順序應用,而不管執行順序如何。這個基準模型為不產生衝突的 I/O 工作負載的資料模型和應用程式提供了最大的可伸縮性和最高的效能。典型的例子是 MPI-IO 集合操作、POSIX 檔案讀/寫操作和 HDF5 資料集讀/寫操作。
對於需要將衝突序列化的部分資料模型,DAOS 提供了基於多版本併發控制的分散式可序列化事務。當不同的使用者程序要覆蓋與 dkey/akey 關聯的值時,通常需要該事務。例如 DAOS 上的 SQL 資料庫,或者由非一致的客戶端併發訪問的一致的 POSIX 名稱空間。
在同一操作的上下文中提交的所有 I/O 操作(包括讀取)將使用相同的 epoch。DAOS 事務機制自動檢測傳統的讀/寫、寫/讀和寫/寫衝突,並中止其中一個衝突事務(事務在 -DER_RESTART 引數下提交失敗)。然後,使用者/應用程式必須重新啟動失敗的事務。
在目前的實現中,事務 API 具有以下限制,這些限制將在未來的 DAOS 版本中解決:
- 不支援 Array API
- 通過同一上下文環境執行的物件獲取/列表和鍵值獲取/列表操作所進行的事務物件更新和鍵值放入操作不可見。
本文分享自華為雲社群《DAOS 分散式非同步物件儲存》,原文作者:debugzhang 。
點選關注,第一時間瞭解華為雲新鮮技