Hadoop 是什么?它是如何工作的?
Hadoop是什么?它是如何工作的?為什么 Hadoop可以成為全球最流行的大數(shù)據(jù)處理框架之一?如何基于 Hadoop搭建一套簡單的分布式文件系統(tǒng)?這篇我們一起來來深入討論。

一、Hadoop是什么?
Hadoop是一個開源的分布式計算框架,用于處理和存儲大規(guī)模數(shù)據(jù)集,它是由 Apache Software Foundation維護,能夠幫助用戶在商用硬件集群上以可靠、高效、容錯的方式處理和分析海量數(shù)據(jù)。為了更好地理解 Hadoop是什么,我們列舉了Hadoop一些里程碑:
- 2002年: Nutch項目啟動,目標是實現(xiàn)全面的網(wǎng)頁抓取、索引和查詢功能。
 - 2003年: Google發(fā)布了三篇具有影響力的論文(Google File System(GFS)、MapReduce和Bigtable),為 Hadoop的文件存儲架構(gòu)奠定了基礎(chǔ)。
 - 2004年: Cutting在 Nutch中實現(xiàn)了類似 GFS的功能,形成了后來的 Hadoop分布式文件系統(tǒng)(HDFS)。
 - 2005年: Nutch項目中實現(xiàn)了 MapReduce的初步版本,隨后 Hadoop從 Nutch中分離出來,成為一個獨立的開源項目。
 - 2006年: Yahoo!雇傭 Doug Cutting,并為Hadoop的發(fā)展提供支持,同年,Apache Hadoop項目正式啟動。
 - 2008年: Hadoop成為 Apache頂級項目,并迎來了快速發(fā)展。同年,Cloudera公司成立,推動 Hadoop商業(yè)化進程。
 - 從此,Hadoop迅猛發(fā)展,成為全球最流行的大數(shù)據(jù)處理框架之一。
 
二、Hadoop的核心組件
Hadoop的核心組件包括以下 4個:
- HDFS:HDFS是 Hadoop的數(shù)據(jù)存儲層,它負責(zé)將大量數(shù)據(jù)分塊存儲到集群中的不同節(jié)點上,從而實現(xiàn)分布式保存和冗余備份。數(shù)據(jù)被切分成小塊,并復(fù)制到多個節(jié)點,以防硬件故障。
 - MapReduce:MapReduce是 Hadoop的分布式計算模型,它將處理大規(guī)模數(shù)據(jù)集的任務(wù)分發(fā)到多個節(jié)點,允許并行處理。MapReduce由兩個階段組成:Map階段負責(zé)將任務(wù)分解為多個小任務(wù);Reduce階段負責(zé)對小任務(wù)的結(jié)果進行匯總。
 - YARN:YARN 是 Hadoop的資源管理層,它負責(zé)管理和調(diào)度集群中的計算資源。YARN允許多個作業(yè)在同一 Hadoop集群上并行執(zhí)行,這大大提高了 Hadoop集群的利用率和擴展能力。
 - Hadoop Common:Hadoop Common是 Hadoop的核心庫,提供必要的工具和實用程序,用于支持其他 Hadoop模塊。
 
它們的關(guān)系如下:

接下來我們將對各個組件進行詳細的分析。
1. HDFS
HDFS,全稱 Hadoop Distributed File System(分布式文件系統(tǒng)),它是 Hadoop的核心組件之一,旨在解決海量數(shù)據(jù)的存儲問題。
(1) HDFS 架構(gòu)概述
HDFS是主從結(jié)構(gòu)的分布式文件系統(tǒng),由兩類節(jié)點組成:
- NameNode :NameNode(主節(jié)點是 HDFS 的中心控制節(jié)點,負責(zé)管理文件系統(tǒng)的元數(shù)據(jù)(比如文件和目錄的樹狀結(jié)構(gòu),文件塊的位置、用戶權(quán)限等)。它不直接存儲數(shù)據(jù),而是記錄數(shù)據(jù)存儲在哪些 DataNode 上。
 - DataNode :DataNode(數(shù)據(jù)節(jié)點)是實際存儲數(shù)據(jù)的節(jié)點,它們接收數(shù)據(jù)塊,并定期向 NameNode匯報自己存儲的塊信息和健康狀態(tài)。
 
此外,還有一個可選的組件Secondary NameNode,它用于輔助 NameNode 的元數(shù)據(jù)備份和日志合并,幫助維持文件系統(tǒng)的高可用性。
HDFS的架構(gòu)如下圖:

(2) 數(shù)據(jù)存儲機制
HDFS的文件是分塊存儲的,大文件被按照固定大?。J是 128MB,早期版本是 64MB)劃分為多個數(shù)據(jù)塊(Block),每個文件塊被存儲在集群中的不同 DataNode 上。
為了防止數(shù)據(jù)因節(jié)點故障而丟失,HDFS做了數(shù)據(jù)冗余與容錯機制,它會對每個數(shù)據(jù)塊進行復(fù)制,默認情況下每個數(shù)據(jù)塊有 3 副本:
- 一個副本存儲在與客戶端最近的節(jié)點上。
 - 第二個副本存儲在不同機架的節(jié)點上(防止機架故障)。
 - 第三個副本存儲在第二個副本所在機架的其他節(jié)點上。
 
基于上述的副本機制,HDFS可以確保即使部分 DataNode 失效,數(shù)據(jù)依然可以通過其他存有副本的節(jié)點恢復(fù)。
(3) 讀寫操作流程
HDFS 文件寫入過程:
- 客戶端與 NameNode 交互:客戶端首先將寫請求發(fā)給 NameNode,然后 NameNode 返回存儲該文件每個塊的若干 DataNode 節(jié)點位置。
 - 數(shù)據(jù)塊寫入 DataNode:客戶端將數(shù)據(jù)塊發(fā)送至其中一個 DataNode,這個 DataNode 會將數(shù)據(jù)塊傳遞給下一個 DataNode,依次類推,直到所有節(jié)點都保存該數(shù)據(jù)塊的副本。
 - 狀態(tài)更新:上傳完成后,所有涉及的 DataNode 會將其存儲狀態(tài)通知 NameNode,并提交流程結(jié)束。
 
HDFS 文件讀取過程:
- 獲取元數(shù)據(jù):客戶端向 NameNode 請求文件位置信息,NameNode 返回相關(guān)文件塊及其所在 DataNode 的位置。
 - 從 DataNode 讀取數(shù)據(jù)塊:客戶端根據(jù) NameNode 提供的位置從相關(guān)的 DataNode 直接讀取文件的不同數(shù)據(jù)塊并組裝回文件。
 - 容錯處理:如果某個 DataNode 失效,客戶端無法從該NameNode獲取塊信息,它會嘗試從存儲副本的其他 DataNode 讀取。
 
2. MapReduce
MapReduce是 Hadoop的分布式計算框架,通過將復(fù)雜的任務(wù)分解成多個獨立的簡單任務(wù)來實現(xiàn)并行計算,它的核心思想是“Map”和“Reduce”兩個階段:
- Map階段:將原始數(shù)據(jù)映射(map)為鍵值對(key-value pairs)。
 - Reduce階段:將具有相同鍵的數(shù)值進行聚合(reduce)。
 
(1) MapReduce 執(zhí)行流程
MapReduce 執(zhí)行流程包含以下5個步驟:
① Job劃分
一個完整的 MapReduce任務(wù)稱為一個Job,Job是由多個Task構(gòu)成的,分為Map Task和Reduce Task。
② Input Splitting(輸入分片)
MapReduce處理輸入數(shù)據(jù)時,首先將大文件切分成較小的Splits,Map Task的數(shù)量通常與輸入分片數(shù)量一致,每一個Map Task處理一個分片的數(shù)據(jù)。
③ Map階段
- 每個Map Task拿到一份Input Split的數(shù)據(jù),通過RecordReader將數(shù)據(jù)轉(zhuǎn)化為一對對的<key, value>形式,這里的鍵值對((K1, V1))根據(jù)業(yè)務(wù)的需求構(gòu)造。
 - Map函數(shù)逐條處理這些鍵值對,輸出<K2, V2>形式的新的鍵值對。
 - 這些中間鍵值對<K2, V2>在寫入本地磁盤之前會進行Sort(排序) 和 Partition(分區(qū)) 操作,Partition的作用是將具有相同鍵(K2)的鍵值對分發(fā)到相同的 Reducer中執(zhí)行。
 
④ Shuffle and Sort(分發(fā)與排序)
Shuffle發(fā)生在 Map階段結(jié)束和 Reduce階段之間,具體過程如下:
- 排序:每個Map Task輸出的<K2, V2>對會按鍵(K2)進行排序,確保同一鍵的所有值(V2)聚集在一起。
 - 分區(qū):Map Task的輸出會根據(jù) Partition函數(shù)的哈希值發(fā)送到不同的Reduce任務(wù)中。
 - 拉取數(shù)據(jù):Reducer從每個 Map輸出中拉取需要的分區(qū)文件,經(jīng)過網(wǎng)絡(luò)傳輸將其聚合。
 
⑤ Reduce階段
- 每個Reduce Task接收到的內(nèi)容是經(jīng)過 Shuffle過程后所有鍵值對(<K2, List<V2>>)的集合。
 - Reduce函數(shù)(用戶自定義)會對每個K2執(zhí)行聚合計算,輸出為新的鍵值對<K3, V3>。
 - 最終輸出結(jié)果會通過 RecordWriter寫入 HDFS或者其他存儲系統(tǒng)。
 
整個流程可以用下圖解釋:

2. YARN
YARN(Yet Another Resource Negotiator,另一種資源調(diào)度器)是Hadoop 2.x版本中引入的一個集群資源管理框架,它的設(shè)計初衷是解決 Hadoop 1.x中 MapReduce計算框架的資源調(diào)度和管理局限性,可以支持各種應(yīng)用程序調(diào)度的需求。
(1) 核心組件
YARN包含以下 5個核心組件:
① ResourceManager
ResourceManager(RM,資源管理器)負責(zé)全局集群資源的管理和調(diào)度,它是YARN的中央控制器,協(xié)調(diào)集群中的所有應(yīng)用和計算資源。ResourceManager有兩個重要的子組件:
- Scheduler(調(diào)度器):負責(zé)為應(yīng)用程序按需分配資源,但不負責(zé)任務(wù)的執(zhí)行和重新啟動。調(diào)度器的排期是決定如何把資源多租戶化、多應(yīng)用程序化的關(guān)鍵,它可以實現(xiàn)不同的調(diào)度策略(如公平調(diào)度器,容量調(diào)度器等)。
 - Applications Manager(應(yīng)用程序管理器):負責(zé)各種應(yīng)用程序的生命周期管理,包括應(yīng)用程序的啟動、檢查、資源監(jiān)控和故障恢復(fù)。
 
② NodeManager
NodeManager(NM,節(jié)點管理器)是YARN架構(gòu)中的分布式代理,負責(zé)管理每個計算節(jié)點上的資源,具體負責(zé):
- 資源報告:將本節(jié)點的CPU、內(nèi)存等資源使用情況匯報給ResourceManager。
 - 容器管理:協(xié)調(diào)和管理每一個容器(Container)的生命周期,包括啟動、監(jiān)控和停止容器。
 - 任務(wù)監(jiān)控和報告:監(jiān)控執(zhí)行的任務(wù),并向ResourceManager報告其狀態(tài)和進度。
 
③ ApplicationMaster
ApplicationMaster(AM,應(yīng)用程序管理器)是為每個具體應(yīng)用程序(如MapReduce Job、Spark Job)啟動的專用進程,它負責(zé)協(xié)調(diào)整個應(yīng)用程序生命周期的調(diào)度和執(zhí)行,協(xié)調(diào) ResourceManager與 NodeManager,動態(tài)申請和釋放資源。每一個應(yīng)用程序在提交時都會啟動一個對應(yīng)的ApplicationMaster實例。 AM的職責(zé)包括:
- 申請資源:向ResourceManager請求所需的資源,定義CPU和內(nèi)存需求。
 - 任意調(diào)度:根據(jù)資源信息及負載情況,決定將任務(wù)分配到哪個節(jié)點/容器執(zhí)行。
 - 容器監(jiān)控:監(jiān)控啟動的任務(wù)并處理故障。
 
④ Container
Container(容器)是YARN中的資源分配單位,它將邏輯運行環(huán)境(如CPU、內(nèi)存等涉及硬件維度的資源)與應(yīng)用程序任務(wù)綁定在一起。ApplicationMaster可以向ResourceManager申請多個容器,并在這些容器中分配任務(wù)進行具體的計算。
⑤ Client
客戶端負責(zé)與YARN進行交互,提交應(yīng)用程序請求,并向YARN查詢?nèi)蝿?wù)的執(zhí)行進度和結(jié)果??蛻舳藢①Y源需求信息傳遞給ResourceManager,RM會為該任務(wù)分配資源,然后將其控制權(quán)交給對應(yīng)的ApplicationMaster。
核心組件模型如下圖:

(2) 工作流程
YARN工作流程包含以下4個步驟:
① 應(yīng)用程序啟動流程
- 啟動應(yīng)用程序:客戶端通過API或命令行向YARN集群提交應(yīng)用程序。此時,客戶端給RM發(fā)送請求,描述任務(wù)的資源需求及執(zhí)行規(guī)范。
 - 生成ApplicationMaster:ResourceManager根據(jù)集群的整體資源利用情況,為應(yīng)用程序分配第一個容器(Container),并啟動相應(yīng)的ApplicationMaster。
 - ApplicationMaster初始化:ApplicationMaster會在啟動后向ResourceManager注冊自己,并根據(jù)初始任務(wù)和資源需求向RM申請更多的資源。
 - 分配資源:ResourceManager根據(jù)集群的實時負載情況和調(diào)度策略,將余下的容器分配給ApplicationMaster,AC根據(jù)任務(wù)需求啟動容器,并將計算任務(wù)分配給這些容器去執(zhí)行。
 
② 資源調(diào)度流程
- 請求資源:ApplicationMaster向ResourceManager提交資源申請。請求中指定了計算任務(wù)所需的資源(如CPU、內(nèi)存)以及在何處優(yōu)先執(zhí)行(一定節(jié)點上或任意節(jié)點)。
 - 資源心跳與分配:NodeManager通過定期心跳將節(jié)點的可用資源(包括剩余內(nèi)存、CPU等情況)匯報給ResourceManager。ResourceManager根據(jù)集群整體資源情況,通過調(diào)度器(Scheduler)為機器或容器分配任務(wù)。
 - 任務(wù)分配與啟動:ApplicationMaster得到資源分配信息后,再與NodeManager通信,為任務(wù)啟動容器并分配計算任務(wù)。
 
③ 任務(wù)運行與監(jiān)控
一旦任務(wù)開始執(zhí)行,NodeManager會為Container提供隔離的運行環(huán)境(如JVM),ApplicationMaster監(jiān)視任務(wù)的運行狀態(tài),并通過心跳與NodeManager通信,確保任務(wù)成功完成或在出現(xiàn)故障時重新調(diào)度任務(wù)。
④ 應(yīng)用完成與資源回收
當ApplicationMaster檢測到所有任務(wù)均已成功完成,它會向ResourceManager發(fā)送一個"完成"信號,表示應(yīng)用程序已經(jīng)完成。隨后,ResourceManager會通知NodeManager釋放任務(wù)所占用的資源容器,集群整體資源狀態(tài)更新。
三、代碼實戰(zhàn)
在代碼實戰(zhàn)環(huán)節(jié),我們將通過一個完整的示例來展示如何在 Java中實現(xiàn)一個 MapReduce任務(wù),并將處理結(jié)果存儲回 HDFS。
任務(wù)描述:計算給定文件中每個單詞出現(xiàn)的次數(shù)文件格式:CVS或者JSON項目結(jié)構(gòu):項目結(jié)構(gòu)如下:
wordcount/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   ├── WordsCounterMapper.java
│   │   │   ├── WordsCounterReducer.java
│   │   │   └── WordsCounterDriver.java
│   └── resources/
├── input/
│   └── input.cvs
│ input.cvs
└── output/
1.安裝Hadoop
我自己Mac電腦安裝的是 Hadoop-3.4.1,查看版本指令:hadoop version,關(guān)于安裝 Hadoop,可以參考這篇文章

2.處理文件
(1) 處理 CSV文件
假設(shè)我們有一個超大的 CSV文件:input.csv,如下內(nèi)容只是展示前幾行數(shù)據(jù):
id,name,address
1,yuanjava,hangzhou
2,juejin,beijin
3,didi,beijing
...我們可以使用開源的 Apache Commons CSV工具類來處理該文件,對應(yīng)的依賴如下:
// maven依賴
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-csv</artifactId>
    <version>1.12.0</version>
</dependency>
// gradle 依賴
implementation 'org.apache.commons:commons-csv:1.12.0'(2) 處理 Json文件
假設(shè)我們有一個超大的 Json文件:input.json,如下內(nèi)容只是展示前幾行數(shù)據(jù):
[
    {"id": 1, "name": "yuanjava", "address": "hangzhou"},
    {"id": 2, "name": "juejin", "address": "beijing"},
    {"id": 3, "name": "didi", "address": "beijing"},
    ...
]我們可以使用開源的 Jackson庫來處理文件,對應(yīng)的依賴如下:
// maven依賴
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.18.1</version>
</dependency>
// gradle 依賴
implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.1'3.增加 Hadoop依賴
// maven依賴
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>3.4.1</version>
</dependency>
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-mapreduce-client-core</artifactId>
    <version>3.4.1</version>
</dependency>
// gradle依賴
implementation 'org.apache.hadoop:hadoop-common:3.4.1'
implementation 'org.apache.hadoop:hadoop-mapreduce-client-core:3.4.1'4.編寫 Mapper類
Mapper類的作用是處理輸入數(shù)據(jù),并為每個輸入記錄生成鍵值對,在詞頻統(tǒng)計任務(wù)中,Mapper 的任務(wù)是將每個單詞映射為一個中間鍵值對 (word, 1)。
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
import java.io.StringReader;
public class WordsCounterMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
    private final static IntWritable one = new IntWritable(1);
    private Text word = new Text();
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String line = value.toString().trim();
        if (line.isEmpty()) {
            return; // Skip empty lines
        }
        // json以'{'開頭, CVS以'['開頭
        if (line.startsWith("{") || line.startsWith("[")) {
            processJson(line, context);
        } else {
            processCsv(line, context);
        }
    }
    private void processJson(String line, Context context) throws IOException, InterruptedException{
        JsonNode rootNode = objectMapper.readTree(line);
        if (rootNode.isArray()) {
            for (JsonNode node : rootNode) {
                String name = node.get("name").asText();
                word.set(name);
                context.write(word, one);
            }
        } else if (rootNode.isObject()) {
            String name = rootNode.get("name").asText();
            word.set(name);
            context.write(word, one);
        }
    }
    private void processCsv(String line, Context context) throws IOException, InterruptedException{
        StringReader reader = new StringReader(line);
        Iterable<CSVRecord> records = CSVFormat.DEFAULT.parse(reader);
        for (CSVRecord record : records) {
            // Assuming the CSV has a header row and "name" is one of the columns
            String name = record.get("name");
            word.set(name);
            context.write(word, one);
        }
    }
}5.編寫 Reducer類
Reducer類的作用是對來自 Mapper的中間鍵值對進行匯總,在詞頻統(tǒng)計任務(wù)中,Reduce 的任務(wù)是對相同單詞的計數(shù)進行累加。
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class WordsCounterDriver {
    public static void main(String[] args){
        if (args.length != 2) {
            System.err.println("Please enter input path and output path.");
            System.exit(-1);
        }
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf, "wordCounter");
        job.setJarByClass(WordsCounterDriver.class);
        job.setMapperClass(WordsCounterMapper.class);
        job.setReducerClass(WordsCounterReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}6.編寫 Driver 類
Driver 類用于配置 MapReduce 作業(yè)并啟動作業(yè)。它指定了 Mapper 和 Reducer 的實現(xiàn)類,以及輸入和輸出路徑等。
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class WordsCounterDriver {
    public static void main(String[] args){
        if (args.length != 2) {
            System.err.println("Please enter input path and output path.");
            System.exit(-1);
        }
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf, "wordCounter");
        job.setJarByClass(WordsCounterDriver.class);
        job.setMapperClass(WordsCounterMapper.class);
        job.setReducerClass(WordsCounterReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}7.運行和查看結(jié)果
(1) 運行步驟:
- 編譯和打包:將上述代碼編譯并打包成一個 JAR 文件。
 - 上傳數(shù)據(jù)到 HDFS:將待處理的 CSV 和 JSON 數(shù)據(jù)上傳到 HDFS 的一個目錄中。
 - 執(zhí)行 MapReduce作業(yè):在 Hadoop集群上運行該 JAR文件,并指定輸入和輸出路徑,指令如下:
 
hadoop jar wordcounter.jar WordCounterDriver input/input.cvs output/
hadoop jar wordcounter.jar WordCounterDriver input/input.json output/- /input/input.cvs(json) 是 HDFS上包含 CSV和 JSON文件的目錄。
 - /output 是用于存儲結(jié)果的 HDFS目錄。注意:輸出目錄不能預(yù)先存在,否則作業(yè)將失敗。
 
(2) 查看輸出結(jié)果
任務(wù)完成后,輸出結(jié)果將會保存在指定的輸出目錄中,我們可以使用以下命令查看結(jié)果:
hadoop fs -cat output/part-r-00000輸出結(jié)果可能如下:
yuanjava 100
juejin 3000
didi 100
...8.代碼解釋與優(yōu)化
(1) Mapper詳解
繼承與泛型:Mapper<LongWritable, Text, Text, IntWritable> 表示輸入鍵值對的類型和輸出鍵值對的類型。輸入鍵是行偏移量,值是行文本,輸出鍵是單詞,值是整數(shù) 1。
map 方法:對每一行文本進行分割,然后對每個單詞輸出一個鍵值對。
(2) Reducer詳解
繼承與泛型:Reducer<Text, IntWritable, Text, IntWritable> 表示輸入和輸出鍵值對類型。輸入鍵是單詞,值是整數(shù)列表,輸出鍵是單詞,值是單詞的累加計數(shù)。
reduce 方法:對每個單詞的所有計數(shù)進行累加輸出。
(3) Driver詳解
Job 配置:設(shè)置 Mapper和 Reducer類,指定輸入輸出格式。
路徑設(shè)置:通過命令行參數(shù)指定輸入輸出路徑。
(4) 優(yōu)化建議
- Combiner使用:在 Map端進行部分匯總,減少傳輸?shù)?Reduce端的數(shù)據(jù)量。
 - 數(shù)據(jù)壓縮:啟用中間數(shù)據(jù)壓縮減少網(wǎng)絡(luò)傳輸開銷。
 - 分區(qū)與排序:根據(jù)數(shù)據(jù)特性自定義分區(qū)器和排序規(guī)則。
 
通過這個簡單的例子,我們展示了如何在 Java中實現(xiàn)一個基本的 MapReduce程序,通過定義 Mapper和 Reducer 再結(jié)合 Driver,能夠?qū)崿F(xiàn)對大規(guī)模數(shù)據(jù)集的分布式處理。如果要處理更復(fù)雜的任務(wù),可以通過自定義分區(qū)器、排序規(guī)則、Combiner 等方式進行優(yōu)化。
通過此示例,我們可以更好地理解 Hadoop MapReduce 的工作原理和編程模型以及它對于大數(shù)據(jù)處理的重要性。
四、總結(jié)
本文,我們分析了 Hadoop的核心組件及其工作原理,讓我們對 Hadoop有了一定的認識。本人有幾年 Hadoop的使用經(jīng)驗,從整體上看,Hadoop的使用屬于中等難度,Hadoop的生態(tài)比完善,學(xué)習(xí)難度比較大,但是,不得不說 Hadoop的設(shè)計思維很優(yōu)秀,值得我們花時間去學(xué)習(xí)。
2003年,Google發(fā)布 Google File System(GFS)、MapReduce和 Bigtable 三篇論文后,Doug Cutting和 Michael J. Cafarella抓住了機會,共同創(chuàng)造了 Hadoop。Google的這三篇經(jīng)典論文是大數(shù)據(jù)領(lǐng)域的經(jīng)典之作,但它的影響力遠不止大數(shù)據(jù)領(lǐng)域,因此,如果想成為一名優(yōu)秀的工程師,閱讀原滋原味的優(yōu)秀論文絕對是受益無窮的一種方式。
Hadoop展示了大數(shù)據(jù)領(lǐng)域一個優(yōu)秀的架構(gòu)模式:集中管理,分布式存儲與計算。這種優(yōu)秀的架構(gòu)模式同樣還運用在 Spark、Kafka、Flink、HBase、Elasticsearch、Cassandra等這些優(yōu)秀的框架上,它在大數(shù)據(jù)領(lǐng)域展示了顯著的優(yōu)勢。
最近一年,我從事的項目有幸和 MIT,Standford這樣頂尖學(xué)府出來的工程師合作,他們強悍的數(shù)學(xué)建模能力以及對同一個問題思考的深度確實讓我望塵莫及,在互聯(lián)網(wǎng)大廠卷了這么多年,每天都有寫完的需求開不完的會,絕大多數(shù)程序員都被業(yè)務(wù)裹挾著,導(dǎo)致很多優(yōu)秀的人無法從業(yè)務(wù)中抽離出來去研究更深層領(lǐng)域的東西,陷入無盡的內(nèi)卷。
如何在這個內(nèi)卷的環(huán)境中讓自己立于不敗之地?基本功絕對是重中之重。
最后,因為 Hadoop的內(nèi)容太多,很難僅憑本文把 Hadoop講透,希望在分享我個人對 Hadoop理解的同時也能拋磚引玉,激發(fā)同行寫出更多優(yōu)秀的文章,對于技術(shù),對于行業(yè)產(chǎn)生共多思考的共鳴。















 
 
 














 
 
 
 