從兩個模型帶你了解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 。

 

點擊關注,第一時間了解華為雲新鮮技術~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM