Hadoop学习笔记——基础篇

cuixiaogang

简介

Hadoop 是Apache开源的分布式存储与计算框架,它的核心目标是解决海量数据存储和计算的问题。

关键特性

  • 分布式架构: 由多个节点分布式部署,且节点扩容无上限
  • 高容错性: 数据多副本存储,节点宕机数据不丢失
  • 批处理优先: 无法做到实时查询,查询延迟极高
  • 低成本: 支持普通、低配置的机器作为节点加入到集群中

核心组件

分布式存储: HDFS(Hadoop Distributed File System)

类比「分布式硬盘阵列」,是 Hadoop 存储数据的核心,专为「大文件、高吞吐量」设计(不适合小文件,如 KB 级日志碎片)。

核心架构

  • NameNode(主节点):主要用于管理文件系统的「元数据」(文件名、目录结构、文件存储在哪些DataNode上),不存实际数据
  • DataNode(从节点):存储实际数据块(默认128MB/块,可配置),每个数据块默认存3个副本(容错性)
  • SecondaryNameNode: 辅助NameNode进行元数据的管理和checkpoint,以保证HDFS的性能和可靠性(比如用来合并元数据日志,减轻 NameNode 负担,避免元数据丢失)

分布式计算: MapReduce

MapReduce是Hadoop原生的批处理计算框架,核心思想是「分而治之」:将大规模任务拆分为多个小任务,在多个节点并行执行,最后汇总结果。

核心流程:

  • Map阶段:拆分任务->多个节点并行处理数据
  • Shuffle阶段:数据分发->将Map输出的相同Key数据汇总到同一个节点
  • Reduce阶段:合并结果->对同一Key的数据进行最终计算

资源调度: YARN(Yet Another Resource Negotiator)

类比「分布式操作系统的内核」,负责管理集群的CPU、内存资源,协调多个计算任务(MapReduce)的资源分配,避免资源争抢。

核心组件:

  • ResourceManager(主节点):全局资源调度器,接收任务提交,分配资源
  • NodeManager(从节点):每个节点的资源管理器,负责执行任务(启动Map/Reduce进程)
  • ApplicationMaster:每个计算任务(如一个MapReduce作业)的「管家」,向ResourceManager申请资源,协调NodeManager执行任务

HDFS

安装及配置

点击<下载地址>,下载对应版本的文件,直接解压既可。

注意:本文章中的所有截图、配置项,均以3.2.4为依据的示例,其他版本可能略有不同。

以下是相关的配置文件及重要的配置项

core-site.xml

Hadoop集群的全局核心配置文件,文件位置/hadoop-3.2.4/etc/hadoop/core-site.xml

  • fs.defaultFS:设置HDFS的默认访问路径。这是客户端(如hadoop fs命令)用来连接 HDFS 的“地址”
  • hadoop.tmp.dir:指定Hadoop所有临时文件的存储目录,HDFS的NameNode和DataNode在运行时会使用该目录存储临时文件
  • 个人使用的终端中,完整的配置内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<configuration xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="client-viewfs.xml">
<xi:fallback></xi:fallback>
</xi:include>
<property>
<name>fs.defaultFS</name>
<value>hdfs://hostname:9000</value>
</property>

<property>
<name>fs.AbstractFileSystem.file.impl</name>
<value>org.apache.hadoop.fs.local.LocalFs</value>
</property>

<property>
<name>fs.AbstractFileSystem.hdfs.impl</name>
<value>org.apache.hadoop.fs.viewfs.ViewFs</value>
</property>

<property>
<name>fs.hdfs.impl</name>
<value>org.apache.hadoop.fs.viewfs.ViewFileSystem</value>
</property>

<property>
<name>hadoop.v1.jar</name>
<value>hadoop-0.20.2.1-core.jar,hadoop-0.20.2.1-highavailability.jar,hive-shims-0.7.1.jar</value>
</property>

<property>
<name>io.file.buffer.size</name>
<value>131072</value>
</property>

<property>
<name>fs.trash.interval</name>
<value>1440</value>
</property>

<property>
<name>ipc.server.listen.queue.size</name>
<value>1024</value>
</property>

<property>
<name>thrift.max.ipc.handle</name>
<value>4096</value>
</property>

<property>
<name>io.serializations</name>
<value>org.apache.hadoop.io.serializer.WritableSerialization,org.apache.hadoop.io.serializer.avro.AvroSpecificSerialization,org.apache.hadoop.io.serializer.avro.AvroReflectSerialization</value>
</property>

<property>
<name>io.compression.codecs</name>
<value>org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.DefaultCodec,com.hadoop.compression.lzo.LzoCodec,com.hadoop.compression.lzo.LzopCodec,org.apache.hadoop.io.compress.BZip2Codec,org.apache.hadoop.io.compress.SnappyCodec,org.apache.hadoop.io.compress.LzmaCodec</value>
</property>

<property>
<name>io.compression.codec.lzo.class</name>
<value>com.hadoop.compression.lzo.LzoCodec</value>
</property>

<property>
<name>ha.zookeeper.quorum</name>
<value>ip1:2181,ip2:2181,ip3:2181,ip4:2181,ip5:2181</value>
</property>

<property>
<name>fs.hdfs.impl.disable.cache</name>
<value>false</value>
</property>

<property>
<name>dfs.support.ugi.access</name>
<value>true</value>
</property>

<property>
<name>hadoop.security.authorization</name>
<value>true</value>
</property>

<!-- configuration item for avatar begin -->

<property>
<name>fs.default.name</name>
<value>hdfs://hostname:9000</value>
</property>

<property>
<name>fs.ha.zookeeper.quorum</name>
<value>ip1:2181,ip2:2181,ip3:2181,ip4:2181,ip5:2181</value>
</property>

<property>
<name>fs.hdfsold.impl</name>
<value>org.apache.hadoop.hdfs.DistributedFileSystem</value>
</property>

<property>
<name>ipc.client.connect.max.retries.on.timeouts</name>
<value>5</value>
</property>

<property>
<name>fs.ugi.v1.enable </name>
<value>true</value>
</property>
<property>
<name>dfs.checksum.type</name>
<value>CRC32</value>
</property>
<property>
<name>fs.AbstractFileSystem.hdfsold.impl</name>
<value>org.apache.hadoop.fs.Hdfs</value>
</property>

</configuration>

hdfs-site.xml

用于配置HDFS服务本身的详细参数,文件位置/hadoop-3.2.4/etc/hadoop/core-site.xml

  • dfs.replication:设置HDFS中数据块的默认副本数(默认值3)
  • dfs.namenode.name.dir:指定NameNode存储元数据的本地目录。
  • dfs.datanode.data.dir:指定DataNode存储实际数据块的本地目录。
  • dfs.webhdfs.enabled:是否启用WebHDFS功能。启用后你可以在浏览器里输入http://hadoop-master:50070来查看HDFS的状态和文件。
  • dfs.permissions.enabled:是否启用HDFS的文件权限检查。
  • 个人使用的终端中,完整的配置内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<configuration>

<property>
<name>dfs.support.append</name>
<value>true</value>
<description>Allow append support since we have the HDFS-200 patch and
need append/close support for HLog.java#splitLog</description>
</property>

<property>
<name>dfs.replication</name>
<value>3</value>
</property>

<property>
<name>dfs.block.size</name>
<value>134217728</value>
</property>

<property>
<name>dfs.datanode.socket.write.timeout</name>
<value>30000</value>
</property>

<property>
<name>dfs.socket.timeout</name>
<value>20000</value>
</property>

<property>
<name>dfs.client.max.block.acquire.failures</name>
<value>1</value>
</property>

<property>
<name>dfs.client.baseTimeWindow.waitOn.BlockMissingException</name>
<value>0</value>
</property>

<!-- configuration item for avatar begin -->

<property>
<name>dfs.avatarnode.port</name>
<value>9001</value>
</property>

<property>
<name>dfs.cli.support.metrics</name>
<value>false</value>
</property>

<property>
<name>fs.ha.retrywrites</name>
<value>true</value>
</property>

<property>
<name>dfs.client.block.write.locateFollowingBlock.retries</name>
<value>8</value>
</property>

<!-- configuration item for avatar end -->

<property>
<name>hdfs.raid.locations</name>
<value>/archive-raid/meta/xor</value>
</property>

<property>
<name>hdfs.raidrs.locations</name>
<value>/archive-raid/meta/rs</value>
</property>

<property>
<name>hdfs.raid.stripeLength</name>
<value>10</value>
</property>

<property>
<name>hdfs.raidrs.paritylength</name>
<value>3</value>
</property>

<property>
<name>dfs.raidnode.client.fastfix</name>
<value>true</value>
</property>

<property>
<name>dfs.user.home.dir.prefix</name>
<value>/home</value>
</property>

</configuration>

workers

列出了集群中所有DataNode节点的主机名或IP地址(旧版本中使用slaves文件来定义),文件位置/hadoop-3.2.4/etc/hadoop/workers

注意:3.0版本已经引入了workers文件作为定义文件,但目前3.2版本依然能使用slaves文件,具体逻辑会先读取workers,如果workers不存在,则读取slaves文件

1
2
3
hadoop-slave1
hadoop-slave2
192.168.1.103

hadoop-env.sh

这个文件用于配置Hadoop运行时的环境变量,特别是Java的安装路径。

  • 个人使用的终端中,完整的配置内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Set Hadoop-specific environment variables here.

# The only required environment variable is JAVA_HOME. All others are
# optional. When running a distributed configuration it is best to
# set JAVA_HOME in this file, so that it is correctly defined on
# remote nodes.

# The java implementation to use.
export JAVA_HOME=/usr/bin/hadoop/software/java8/

# The jsvc implementation to use. Jsvc is required to run secure datanodes
# that bind to privileged ports to provide authentication of data transfer
# protocol. Jsvc is not required if SASL is configured for authentication of
# data transfer protocol using non-privileged ports.
#export JSVC_HOME=${JSVC_HOME}

export HADOOP_CONF_DIR=${HADOOP_CONF_DIR:-"/etc/hadoop"}
export HADOOP_HOME=/usr/bin/hadoop/software/yarn3/

# Extra Java CLASSPATH elements. Automatically insert capacity-scheduler.
for f in $HADOOP_HOME/contrib/capacity-scheduler/*.jar; do
if [ "$HADOOP_CLASSPATH" ]; then
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:$f
else
export HADOOP_CLASSPATH=$f
fi
done

# The maximum amount of heap to use, in MB. Default is 1000.
#export HADOOP_HEAPSIZE=
#export HADOOP_NAMENODE_INIT_HEAPSIZE=""

# Extra Java runtime options. Empty by default.
export HADOOP_OPTS="$HADOOP_OPTS -Djava.net.preferIPv4Stack=true"

# Command specific options appended to HADOOP_OPTS when specified
export HADOOP_NAMENODE_OPTS="-Dhadoop.security.logger=${HADOOP_SECURITY_LOGGER:-INFO,RFAS} -Dhdfs.audit.logger=${HDFS_AUDIT_LOGGER:-INFO,NullAppender} $HADOOP_NAMENODE_OPTS"
export HADOOP_DATANODE_OPTS="-Dhadoop.security.logger=ERROR,RFAS $HADOOP_DATANODE_OPTS"

export HADOOP_SECONDARYNAMENODE_OPTS="-Dhadoop.security.logger=${HADOOP_SECURITY_LOGGER:-INFO,RFAS} -Dhdfs.audit.logger=${HDFS_AUDIT_LOGGER:-INFO,NullAppender} $HADOOP_SECONDARYNAMENODE_OPTS"

export HADOOP_NFS3_OPTS="$HADOOP_NFS3_OPTS"
export HADOOP_PORTMAP_OPTS="-Xmx512m $HADOOP_PORTMAP_OPTS"

# The following applies to multiple commands (fs, dfs, fsck, distcp etc)
export HADOOP_CLIENT_OPTS="-Xmx10000m $HADOOP_CLIENT_OPTS"
#HADOOP_JAVA_PLATFORM_OPTS="-XX:-UsePerfData $HADOOP_JAVA_PLATFORM_OPTS"

# On secure datanodes, user to run the datanode as after dropping privileges.
# This **MUST** be uncommented to enable secure HDFS if using privileged ports
# to provide authentication of data transfer protocol. This **MUST NOT** be
# defined if SASL is configured for authentication of data transfer protocol
# using non-privileged ports.
export HADOOP_SECURE_DN_USER=${HADOOP_SECURE_DN_USER}

# Where log files are stored. $HADOOP_HOME/logs by default.
#export HADOOP_LOG_DIR=${HADOOP_LOG_DIR}/$USER

# Where log files are stored in the secure data environment.
export HADOOP_SECURE_DN_LOG_DIR=${HADOOP_LOG_DIR}/${HADOOP_HDFS_USER}

###
# HDFS Mover specific parameters
###
# Specify the JVM options to be used when starting the HDFS Mover.
# These options will be appended to the options specified as HADOOP_OPTS
# and therefore may override any similar flags set in HADOOP_OPTS
#
# export HADOOP_MOVER_OPTS=""

###
# Advanced Users Only!
###

# The directory where pid files are stored. /tmp by default.
# NOTE: this should be set to a directory that can only be written to by
# the user that will run the hadoop daemons. Otherwise there is the
# potential for a symlink attack.
export HADOOP_PID_DIR="/home/yarn/yarn/pids" #${HADOOP_PID_DIR}
export HADOOP_SECURE_DN_PID_DIR=${HADOOP_PID_DIR}

# A string representing this instance of hadoop. $USER by default.
export HADOOP_IDENT_STRING=$USER

export YARN_CONF_DIR=${HADOOP_CONF_DIR:-"/etc/hadoop"}

HDFS的常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 建议重命名hdfs名称,后面的所有命令都是hdfs命令
alias hdfs='hadoop fs'

# 和本地文件系统类似的命令
hdfs -ls
hdfs -rm
hdfs -cat
hdfs -chmod
hdfs -chown
hdfs -head
hdfs -mv
hdfs -tail
hdfs -df
hdfs -du
hdfs -find
hdfs -cp
hdfs -mkdir
hdfs -touch

# 特殊的命令
# 从HDFS中复制文件到本地
hdfs -copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>
# 从本地复制文件到HDFS上
hfds -copyFromLocal [-f] [-p] [-l] [-d] [-t <thread count>] <localsrc> ... <dst>

MapReduce

MapReduce是ApacheHadoop内置的分布式批处理计算框架,核心思想是「分而治之」:将大规模计算任务拆分成无数个小任务,在集群节点上并行执行,最后汇总结果

核心流程

Map阶段

将输入的大文件(按 HDFS 数据块拆分),转换成「键值对(Key-Value)」形式的中间结果。

实战案例

  • 程序接收到多行数据{"id": 1, "username":"xxx", "data":"xxxxx"}
  • Map函数逻辑:解析JSON数据,将username值作为key,value为原始数据
  • 输出Map结果:xxx\t{"id": 1, "username":"xxx", "data":"xxxxx"}

集群行为

  • Hadoop会为每个数据块启动一个「Map Task」,分布在不同的DataNode节点上(数据本地化,减少网络传输)
  • 多个Map Task并行执行,各自处理自己负责的数据块。

Shuffle阶段

将所有Map Task输出的中间结果,按Key汇总到同一个节点(给后续 Reduce 阶段用)—— 这是MapReduce性能的「瓶颈阶段」(涉及大量网络传输和磁盘 I/O)

注意:按Key汇总不是按Key排序,比如KEY是00b的数据不一定和00a在同一个节点上,也不一定在00a的后面

集群行为

  • 排序(Sort):Map输出后会先在本地排序,减少后续传输量
  • 分区(Partition):通过哈希函数决定每个Key归属哪个Reduce Task
  • 合并(Combine):本地合并相同Key的Value,减少网络传输。

Reduce阶段

接收Shuffle阶段汇总后的同一Key的所有Value,执行最终计算,输出结果到HDFS。

实战案例

  • 程序接收到多行数据xxx\t{"id": 1, "username":"xxx", "data":"xxxxx"}
  • Reduce函数逻辑:将相同的xxx计数,如果下一个key不相同,则输出上一个key的计数
  • 输出最终结果:注意接收到EOF信号时,输出最后一行

集群行为

  • 一个Reduce Task处理一个或多个Key的数据
  • 最终结果以文件形式存储在HDFS(默认一个 Reduce Task 输出一个文件)

Tez

Tez是Apache开源的分布式计算框架,核心定位是「替代MapReduce,作为Hive/Pig等工具的底层计算引擎」,解决MapReduce的低效率问题。

与MapReduce相比较,Tez进行了如下优化与改进:

  • DAG模型替代串行执行:MapReduce的任务是「Map->Shuffle->Reduce」的固定串行流程,而Tez可将多个Map/Reduce步骤组合成一个DAG图,并行执行无关步骤,减少等待时间
  • 内存计算优先:中间结果优先存储在内存中,仅当内存不足时才写入磁盘,大幅减少I/O开销
  • 减少任务启动开销:MapReduce每个任务都要启动独立进程,Tez可复用进程/线程,减少任务启动时间

YARN

YARN核心定位是Hadoop集群的「资源调度与任务管理中心」,类比成「集群的操作系统内核」—— 不管是MapReduce、Spark、Tez这些计算框架,都得通过YARN申请CPU/内存资源,由YARN协调不同节点的资源分配,避免任务争抢资源。

对于本人来说,本身不是JAVA开发者,所以只需要了解它的原理既可

核心组件

ResourceManager(RM)

集群的“总经理”

  • 全局唯一,运行在NameNode或独立主节点上
  • 核心职责:接收任务提交、管理全集群资源(CPU/内存总量)、给任务分配资源、监控NodeManager状态

NodeManager(NM)

节点“分公司经理”

  • 每个DataNode上都运行一个
  • 核心职责:管理当前节点的硬件资源(比如该节点有8核CPU、32G 内存)、启动/停止任务进程、向RM汇报节点资源使用情况。

ApplicationMaster(AM)

单个任务的“产品经理”

  • 每个提交到YARN的任务(比如一个Spark作业、一个Hive查询)都会启动一个AM;
  • 核心职责:代表任务向RM申请资源、和NM沟通启动任务进程、监控任务执行状态(失败了申请重试)。

工作原理

  1. 提交任务:将查询任务(底层是Tez/MapReduce任务)提交给YARN的RM,同时指定任务所需的资源(比如最大4核CPU、16G内存)。
  2. 启动AM:RM收到任务后,会在某个NodeManager上启动一个ApplicationMaster(AM),并给AM分配少量初始资源(够AM自身运行即可)。
  3. 申请资源:AM启动后,会根据任务的计算需求(比如需要10个计算节点),向RM申请具体的资源(比如每个节点2核CPU、4G内存)。
  4. 分配并启动任务:RM依据全集群资源情况,给AM分配资源;同时AM拿到资源清单后,会和对应节点的NM沟通,让NM启动任务进程Container(Container是YARN中资源的最小单位(比如一个Container对应2核CPU+4G内存),实际的计算逻辑(比如 Tez 的 Map/Reduce 任务)就在 Container 中执行)
  5. 监控与完成:AM 实时监控所有Container的运行状态,待所有Container执行完成后,AM向RM汇报任务完成,RM释放资源,任务结束