Hadoop 基礎原理
- 基本介紹
- Hadoop 的必要性
- Hadoop 核心組件
- Hadoop 生態系統中的附加組件
- HDFS
- HDFS 集群架構
- HDFS 讀寫流程
- HDFS 寫流程
- HDFS 讀流程
- NameNode 持久化機制
- MapReduce
- 底層原理
- 示例
Hadoop 是一個由 Apache 基金會開發的分布式系統基礎架構,主要解決海量數據的存儲和計算問題,廣義上 Hadoop 指的是 Hadoop 生態圈,包含 HDFS、Hive、MapReduce 多種組件
基本介紹
Hadoop 的必要性
Hadoop 主要解決了海量數據的存儲問題
- 高可用性:底層會維護多個數據副本,所以即使 Hadoop 某個計算元素或存儲出現故障,也不會導致數據的丟失。
- 高擴展性: 在集群間分配任務數據,可方便的擴展數以千計的節點。
- 高效性: 在 MapReduce 的思想下,Hadoop 是并行工作的,以加快任務處理速度。
- 高容錯性: 能夠自動將失敗的任務重新分配。
一個 block 塊在 NameNode 中占150byte(固定),過多小文件會占用 NameNode 內存
小文件的尋址時間大于讀取時間
不支持并發寫和隨機寫
一個文件只能有一個寫,不允許多線程同時寫
Hadoop 核心組件
Hadoop 核心組件包含以下兩種
- HDFS:高可靠、高吞吐的分布式文件系統
- MapReduce:分布式離線并行計算框架
Hadoop 生態系統中的附加組件
我們后端開發接觸的比較多的是Hadoop 生態系統中的附加組件,Sqoop 以及 Hive,分別用來同步數據和查詢數據
- Sqoop:Hadoop(Hive)與傳統數據庫(Mysql)之間傳輸數據的工具,支持批量導入和導出數據
Flume 高可用、高可靠分布式的海量日志采集、聚合和傳輸系統 - Spark:是一個通用的分布式計算框架,支持內存計算,可以顯著提高數據處理速度。它支持多種計算模式,包括批處理、流處理、機器學習等
- HBase:HBase 是一個分布式的、面向列的 NoSQL 數據庫,建立在 HDFS 之上。它提供了實時讀寫訪問,適合處理大規模數據集
- Hive:是基于 Hadoop 的數據倉庫工具,它提供了一種 SQL-like 的查詢語言(HiveQL),使用戶可以方便地進行數據查詢和分析。它可以將 HiveQL 轉換為 MapReduce 任務執行
HDFS
HDFS 是 Hadoop 的分布式文件系統,解決了海量數據的存儲問題
HDFS 集群架構
HDFS 使用 Master/Slave 架構,架構邏輯比較類似 Kafka、ES 等 Apache 的其他項目
一般一個集群有一個 NameNode 和一定數目 DataNode 組成,Namenode 是 HDFS 集群主節點,Datanode 是 HDFS 集群從節點,兩種角色各司其職,共同協調完成分布式的文件存儲服務
HDFS 中文件在物理上是分塊存儲,通過 dfs.blocksize 配置,2.x之后的版本默認128M
HDFS 中文件在邏輯上是連續的,提供一個文件目錄樹
HDFS 讀寫流程
HDFS 寫流程
1,客戶端向 NameNode 發送寫數據請求(包含待上傳文件名和將要上傳的路徑)
2,NameNode 檢查路徑是否存在,文件是否重名等(假設滿足上傳條件)
3,NameNode 向客戶端響應數據,可以上傳文件
4,客戶端根據文件大小進行切分成一個個 block 塊,并向 NameNode 發送提交即將上傳 block1 的請求
5,NameNode 查詢 DataNode 信息,規劃 block1 的存儲位置
6,NameNode 向客戶端返回 block1 可以存儲的數據節點 ip 列表
7,客戶端直接請求數據節點1上傳 block1,數據節點1存儲 block1 完畢并根據 ip 列表將 block1 發送給數據節點8,數據節點2存儲完畢 block1 并根據 ip 列表將 block1 發送給數據節點3,數據節點3存儲完成響應數據給數據節點2,數據節點2將響應數據給數據節點1,數據節點1將存儲結果返回給 NameNode 和客戶端
9,重復第四步上傳下一個block
我知道你們想問什么,為什么 HDFS 的寫流程必須一個個的上傳塊,不能并發上傳嗎?這是設計者對于 HDFS 寫少讀多場景的這種考量。該場景如此設計的好處:
1,每個數據塊的寫入是原子操作,即要么成功寫入,要么完全不寫入。這確保了數據的一致性。如果并發寫入需要考量并發安全性問題
2,集群默認全同步,數據高可靠
HDFS 讀流程
1,客戶端向 NameNode 請求下載文件
2,NameNode 返回目標文件的元數據
3,客戶端根據元數據請求 DataNode 讀取數據 block
4,DataNode 向客戶端傳輸數據
5,重復第三步,直到所有的塊傳輸完成
6,客戶端根據元數據組裝 block 塊完成讀取數據
NameNode 持久化機制
NameNode 元數據的存儲位置是在內存中,但是內存一旦斷電元數據將丟失,因此必須將內存中的元數據存儲在磁盤中用于備份,這里引入額外一個概念叫 Fsimagem
Fsimagem 為內存元數據的備份。若內存的元數據發生改變,如果同時更新 Fsimage 會降低效率,如果不更新會發生數據不一致問題
針對上述問題,最終邏輯是不更新 Fsimage 文件,為解決數據不一致問題,引入 edits 文件,該文件只記錄操作并且采用追加寫的形式,即每當內存的元數據發生改變的同時記錄本次操作記錄追加到磁盤中的 edits,這樣內存元數據等于磁盤的 Fsimage + edits
當 NameNode 啟動時先滾動 edits 并生成一個空的 edits.inprogress,會將 Fsimage 和 edits 文件加載到內存中進行合并,之后的操作(增刪)將追加到 edits.inprogress 中
其行為類似 redis 的 RDB 和 AOF 機制
MapReduce
MapReduce 是一種編程模型和分布式計算框架,是開發基于 Hadoop 的數據分析應用的核心框架。MapReduce 的主要用途包括:
- 大數據處理:處理和分析 PB 級別的數據,如日志分析、數據挖掘、統計分析等
- 數據轉換:將原始數據轉換為所需的格式,如 ETL(Extract, Transform, Load)任務
- 數據索引:構建大規模數據的索引,如搜索引擎的網頁索引
- 機器學習:處理大規模的訓練數據,進行模型訓練和預測
總之,只要是統計或者計算 Hadoop 中的數據,都會用到 MapReduce。Hive(基于 Hadoop 的數據倉庫工具,它提供了一種 SQL-like 的查詢語言,使得用戶可以方便地進行數據查詢和分析)底層對接 MapReduce 來執行查詢和數據處理任務。Hive 的查詢最終會被轉換成一個或多個 MapReduce 作業來執行
底層原理
MapReduce 實現分布式計算分成2個階段,Map(映射)和 Reduce(歸約)
第一個階段 MapTask 并發實例,完全并行運行,互不干擾。首先會將輸入數據分割成多個小塊,每個小塊稱為一個切片(split)。每個切片的大小通常與 HDFS 的塊大小(默認 128MB)一致。這么做使數據能夠并行處理,提高處理速度。
隨后我們對輸入數據進行處理,生成中間鍵值對(key-value pairs)。每個 Map 任務從輸入切片中讀取數據,對每條記錄調用用戶定義的 Map 函數,生成中間鍵值對
第二個階段 ReduceTask 完全并行運行,數據依賴上一個階段所有 MapTask 并發實例輸出。將 Map 任務生成的中間鍵值對進行分區、排序和合并
- 分區(Partitioning):根據鍵的哈希值將中間鍵值對分配到不同的 Reduce 任務中
- 排序(Sorting):對每個分區內的鍵值對按鍵進行排序
- 合并(Merging):將來自不同 Map 任務的相同鍵的鍵值對合并在一起
MapReduce 編程模型只能包含一個 Map 階段一個 Reduce 階段,但可以實現多個 MapReduce 串行運行
示例
上面的描述可能有些抽象,讓大家有很多問題,比如為啥 ReduceTask 也可以并行執行?如果 MapTask 的產物是鍵值對的話,那么存放在 HDFS 的關系型表會怎么轉換成鍵值對然后暴露給我們?接下來舉個例子讓大家更加深入的了解問題:
假設我們有一個關系型表 users,其結構如下:
user_id | name | age | city |
---|---|---|---|
1 | Alice | 25 | New York |
2 | Bob | 30 | London |
3 | Carol | 22 | New York |
4 | Dave | 28 | Tokyo |
假設我們要計算每個城市的用戶數量:
SELECT city, COUNT(*) AS user_count
FROM users
GROUP BY city;
在這個例子中,Map 階段會將每行數據轉換為鍵值對,其中鍵是城市名稱,值是用戶 ID。例如:
- 輸入行:1, Alice, 25, New York。輸出鍵值對:(New York, 1)
- 輸入行:2, Bob, 30, London。輸出鍵值對:(London, 2)
- 輸入行:3, Carol, 22, Paris。輸出鍵值對:(New York, 3)
- 輸入行:4, Dave, 28, Tokyo。輸出鍵值對:(Tokyo, 4)
Map 階段結束我們就得到很多鍵值對,在 Reduce 階段,Hive 會將 Map 任務生成的中間結果按鍵進行分組,相同城市的鍵值對會被分到一個 ReduceTask 中:
- (New York, [1,3]) -> (New York, 2)
- (London, [2]) -> (London, 1)
- (Tokyo, [4]) -> (Tokyo, 1)
ReduceTask 輸出最后的處理結果。所以一個 sql 在 Hive 中的執行流程和普通 db 中是完全不一樣的。通過上面的 case 我們可以看出,先 map 后 reduce 事實上就是想利用并發的能力處理大量數據,Hadoop 的創作者們將我們所有的查詢操作都抽象成了這完全可以并行執行的兩步