HDFS Federation前世今生

freeshow 2021-08-15 22:34:27 阅读数:287

本文一共[544]字,预计阅读时长:1分钟~
hdfs federation 前世 今生

背景

熟悉大數據的人應該都知道,HDFS 是一個分布式文件系統,它是基於穀歌的GFS實現的開源系統,設計目的就是提供一個高度容錯性和高吞吐量的海量數據存儲解决方案。在經典的HDFS架構中有2個NameNode和多個DataNode,如下

從上面可以看出 HDFS 的架構其實大致可以分為兩層:

  • Namespace:由目錄,文件和數據塊組成,支持常見的文件系統操作,例如創建,删除,修改和列出文件和目錄。
  • Block Storage Service:這個部分又由兩部分組成:
    • 存儲(Storage)
      • 是由DataNode提供,主要在本地文件系統存儲數據塊,並提供讀寫訪問。
    • 數據塊管理(Block Management),這個模塊由NameNode提供
      • 通過處理DataNode的注册和定期心跳來提供集群中DataNode的基本關系;
      • 維護數據到數據塊的映射關系,以及數據塊在DataNode的映射關系;
      • 支持數據塊相關操作,如創建,删除,修改和獲取塊比特置;
      • 管理副本的放置,副本的創建,以及删除多餘的副本。

雖然這個架構可以很好的處理海量的大數據存儲,但是當文件比較多,特別是集群運行了很長時間產生大量小文件的情况下,這種架構的 NameNode就會產生很嚴重的問題。這是因為集群中數據的元數據(比如文件由哪些塊組成、這些塊分別存儲在哪些節點上)全部都是由 NameNode節點維護,為了達到高效的訪問,NameNode在啟動的時候會將這些元數據全部加載到內存中。而HDFS中的每一個文件、目錄以及數據塊,在NameNode內存都會有記錄,每個數據塊的信息大約占用150字節的內存空間。當NameNode維護的目錄和文件總量達到1億,數據塊總量達到4億後,常駐內存使用量將達到90GB!這將嚴重影響HDFS集群的擴展性。

任何一方面,單個NameNode提供讀寫訪問請求,也會影響整個HDFS集群的吞吐量。同時,這種架構中所有租戶共享一個命名空間namespace,無法對不同的應用程序進行隔離。

HDFS Federation

為了解决 HDFS 的水平擴展性問題,社區從 Apache Hadoop 0.23.0 版本開始引入了 HDFS federation(參見 HDFS-1052)。HDFS Federation 是指 HDFS 集群可同時存在多個 NameNode/Namespace,每個 Namespace 之間是互相獨立的;單獨的一個 Namespace 裏面包含多個 NameNode,其中一個是主,剩餘的是備,這個和上面我們介紹的單 Namespace 裏面的架構是一樣的。這些 Namespace 共同管理整個集群的數據,每個 Namespace 只管理一部分數據,之間互不影響。

集群中的 DataNode 向所有的 NameNode 注册,並定期向這些 NameNode 發送心跳和塊信息,同時 DataNode 也會執行 NameNode 發送過來的命令。集群中的 NameNodes 共享所有 DataNode 的存儲資源。HDFS Federation 的架構如下圖所示:

通過 HDFS Federation 架構可解决單 NameNode 存在擴展性、業務隔離以及性能等問題。關於如何配置 HDFS Federation 可以參見這裏

ViewFs

這個版本的 HDFS Federation 雖然能够解决單 Namespace 帶來的一些問題,但是又引來了新的問題。比如現在集群中存在多個 Namespace,每個 Namespace 管理一部分數據,那客戶端如何知道要查詢的數據在哪個 Namespace 上呢?為了解决這個問題,社區引入了視圖文件系統(View File System,簡稱 ViewFs),具體可以參見 HADOOP-7257。ViewFs 類似於某些 Unix / Linux 系統中的客戶端掛載錶。ViewFs 可用於創建個性化命名空間視圖,也可用於創建每個群集的公共視圖。那 ViewFs 是如何解决文件映射到對應的 Namespace 上呢?

ViewFs 通過在 core-site.xml 文件裏面引入了路徑映射配置,如下:

正如上面的配置文件所示,在啟用了 HDFS Federation 的集群,fs.defaultFS 的值已經變成了 viewfs://clusterX,這個和未啟用 HDFS Federation 的集群是不一樣的。然後緊接著配置了五個屬性,用於指定文件和集群的映射關系。

比如用戶訪問了 /data 路徑,那麼通過這個配置文件,我們就知道直接到 hdfs://nn1-clusterx.iteblog.com:8020 集群的 /data 路徑下拿數據;當用戶訪問 /iteblog,那麼通過這個配置文件,我們就知道直接到 hdfs://nn2-clusterx.iteblog.com:8020 集群的 /iteblog 路徑下拿數據。其他路徑的數據獲取和這個類似。如果訪問的路徑在配置文件裏面沒找到,那麼將會訪問 fs.viewfs.mounttable.ClusterX.linkFallback 屬性配置的集群和路徑進行訪問。關於詳細的 ViewFs 配置可以參見 官方文檔

Router-based Federation

ViewFs 方案雖然可以很好的解决文件命名空間問題,但是它的實現有以下幾個問題:

  • ViewFS 是基於客戶端實現的,需要用戶在客戶端進行相關的配置,那麼後面對客戶端昇級就會比較困難,這個客戶端相當於重客戶端了;
  • 新增或者修改路徑映射,需要多方配合完成,維護成本比較高。

為了解决這個問題,社區從 Hadoop 2.9.0 和 Hadoop 3.0.0 版本開始引入了一種基於路由的 Federation方案(Router-Based Federation),具體參見 HDFS-10467,這個方案主要是由微軟和優步的工程師實現。和之前的 ViewFS 不一樣,這個是基於服務端實現的。

基於路由的 Federation 方案是在服務端添加了一個 Federation layer,這個額外的層允許客戶端透明地訪問任何子集群,讓子集群獨立地管理他們自己的 block pools,並支持跨子集群的數據平衡。為實現這些目標,Federation layer 必須將塊訪問路由到正確的子集群,維護 namespaces 的狀態,並提供數據重新平衡的機制,跨集群的數據平衡可以參見 HDFS-13123。同時,這個層必須具有可擴展性,高可用性和容錯性。

Federation layer 的設計架構如上圖所示,從上圖可以看出,這個層包含了多個組件:Router、State Store 以及 Rebalancing mechanisms。Router 組件和 Namenode 具有相同的接口,並根據 State Store 裏面的信息將客戶端請求轉發到正確的子集群。State Store 是遠程掛載錶(remote mount table,和 ViewFS 方案裏面的配置文件類似,但在客戶端之間共享),存儲子集群相關的信息包括 load/capacity。下面對這幾個模塊進行介紹。

Router

一個系統中可以包含多個 Router,每個 Router 主要包含兩個作用:

  • 通過 Federated interface,Router 為客戶端提供單個全局的 NameNode 接口,並將客戶端的請求轉發到正確子集群中的活動 NameNode 上;路由器接收到客戶端的請求,然後檢查 State Store 中是否有正確的子集群,並將請求轉發到該子集群的活動 NameNode 上。路由器是無狀態的,所以可以部署在負載均衡器後面並達到高可擴展性等。為了提高性能,路由器還會緩存遠程掛載錶裏面的信息和子群集的狀態。為確保 State Store 的更改可以傳播到所有的路由器,每個路由器需要向 State Store 發送心跳信息。
  • 收集 NameNode 的心跳信息,報告給 State Store,這樣 State Store 維護的信息是實時更新的。路由器也會定期檢查 NameNode 的狀態(通常比特於同一服務器上),並將其高可用性(HA)狀態和負載/空間狀態報告給 State Store。為了實現高可用性和靈活性,多個路由器可以監視相同的 Namenode 並將心跳發送到 State Store,這種方式可以提高整個系統的可靠性,State Store 中沖突的 NameNode 信息是由每個 Router 通過 quorum 協議解决。

State Store

State Store 物理實現是分布式的,在 State Store 裏面主要維護以下幾方面的信息:

  • 子集群的狀態,包括塊訪問負載,可用磁盤空間,HA狀態等;
  • 文件夾/文件和子集群之間的映射,即遠程掛載錶;
  • Rebalancer 操作的狀態;
  • Routers 的狀態。

上面四點中的文件夾/文件和子集群之間的映射其實和 ViewFS 裏面的遠程掛載錶類似,內容如下:

hdfs://tmp → hdfs://C0-1/tmp /* Folder tmp is mapped to folder tmp in subcluster C0-1 */
hdfs://share → hdfs://C0-2/share
hdfs://user/iteblog → hdfs://C0-3/user/iteblog
hdfs://user/user2 → hdfs://C0-2/user2

通過這些我們就可以知道數據在哪個子集群,針對這些信息的存儲 Hadoop 為我們提供了幾種實現,包括基於文件(StateStoreFileSystemImpl)的和基於ZK(StateStoreZooKeeperImpl)的方式,可以通過 dfs.federation.router.store.driver.class 參數配置。關於 Router-Based Federation 更多的情况請訪問 Hadoop 的官方文檔

RBF訪問流程

上面已經簡單的介紹了 Router-Based Federation 的各個組件等情况,下面我們來看看這個方案客戶端訪問文件的流程,如下所示:

圖中的 R 代錶 Router。當客戶端需要進行讀寫操作,它的步驟如下:

  • 客戶端向集群中任意一個 Router 發出某個文件的讀寫請求操作;
  • Router 從 State Store 裏面的 Mount Table 查詢哪個子集群包含這個文件,並從 State Store 裏面的 Membership table 裏面獲取正確的 NN;
  • Router 獲取到正確的 NN 後,會將客戶端的請求轉發到 NN 上,然後也會給客戶端一個請求告訴它需要請求哪個 子集群;
  • 此後,客戶端就可以直接訪問對應子集群的 DN,並進行讀寫相關的操作。

由於 Router-based HDFS federation 還算比較新的特性,所以社區分了幾個階段修複或添加了一些新的功能,比如 Apache Hadoop 3.2.0 版本修複或添加了一些功能,參見 HDFS-12615,以及 Router-based HDFS federation 穩定性相關的 ISSUE HDFS-13891,這個 ISSUE 可能會在 Apache Hadoop 3.3.0 版本發布。

版权声明:本文为[freeshow]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/08/20210815223358048r.html