Hadoop 运行环境搭建

1. Hadoop目录结构

1
2
3
4
5
6
7
8
9
10
11
12
.
├── bin # 存放对Hadoop相关服务(HDFS,YARN)进行操作的脚本
├── etc # 存放Hadoop的配置文件
├── include
├── lib # 存放Hadoop的本地库(对数据进行压缩解压缩功能)
├── libexec
├── LICENSE.txt
├── logs # 存放日志文件
├── NOTICE.txt
├── README.txt
├── sbin # 存放启动或停止Hadoop相关服务的脚本
├── share # 存放Hadoop的依赖jar包、文档、和官方案例

2. Hadoop基本环境搭建

  • 安装jdk 1.8
  • 安装hadoop

2.1. 编辑etc/hadoop/hadoop-env.sh

1
2
3
4
# 修改JAVA_HOME,这样hadoop才能找到JVM
export JAVA_HOME=/usr/lib/java/jdk
# 修改PID生成文件成在目录HADOOP_PID_DIR,默认是/tmp
export HADOOP_PID_DIR=/usr/local/hadoop/tmp

2.2. 编辑etc/hadoop/mapred-env.sh

1
2
3
4
# 修改JAVA_HOME
export JAVA_HOME=/usr/lib/java/jdk
# 修改PID生成文件成在目录
export HADOOP_MAPRED_PID_DIR=/usr/local/hadoop/tmp

2.3. 编辑etc/hadoop/yarn-env.sh

1
2
3
4
# 修改JAVA_HOME
export JAVA_HOME=/usr/lib/java/jdk
# 添加PID生成文件成在目录
export YARN_PID_DIR=/usr/local/hadoop/tmp

3. Hadoop本地模式(Standalone)搭建

刚安装完Hadoop,什么都不配置,默认就是本地模式。

这里的本地模式有两个意思

  • HDFS直接使用本地文件系统。因为fs.defaultFS的默认值是file:///
  • MapReduce运行在本地,而不是YARN。因为mapreduce.framework.name的默认值是local

3.1. 编辑/etc/hosts

查看当前主机的hostname

1
2
$ hostname	# 查看当前主机名
ubuntu

编辑/etc/hosts,为当前主机名添加一条记录。若没有,运行本地MapReduce时会出现java.net.UnknownHostException 错误

1
192.168.57.100 ubuntu   # 为主机名添加一条记录

3.2. 准备数据

创建input目录

1
2
cd /usr/local/hadoop
mkdir input

创建 input/1.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
one
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve
thirteen
fourteen
fifteen
sixteen
seventeen
eighteen
nineteen
twenty

创建 input/2.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apple
banana
blueberry
bone
grape
lemen
orange
pear
peach
strawberry
hello world
hadoop cluster
apache hadoop
hadoop ecosystem

3.3. 官方grep案例

运行grep案例。将input目录下所有文件作为输入,按行遍历,找出所有符合 正则表达式'o.+'的字符串,输出到output目录。注意运行前output目录不应该存在,否则运行会出现FileAlreadyExistsException错误

1
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.5.jar grep input output 'o.+'

查看生成的output目录

1
2
3
4
$ ls -l output/
total 4
-rw-r--r-- 1 root root 41 2月 22 14:52 part-r-00000 # 输出结果
-rw-r--r-- 1 root root 0 2月 22 14:52 _SUCCESS # 空文件,仅仅是一个运行成功的标志

查看结果

1
2
3
4
5
6
7
8
9
$ cat output/part*
2 one
1 ourteen
1 our
1 orange
1 oop ecosystem
1 oop cluster
1 oop
1 o world

3.4. 官方WordCount案例

运行wordcount案例。将input目录下所有文件作为输入,输出到output目录

1
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.5.jar wordcount input output

查看结果

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
$ cat output/part*
apache 1
apple 1
banana 1
blueberry 1
bone 1
cluster 1
ecosystem 1
eight 1
eighteen 1
eleven 1
fifteen 1
five 1
four 1
fourteen 1
grape 1
hadoop 3
hello 1
lemen 1
nine 1
nineteen 1
one 1
orange 1
peach 1
pear 1
seven 1
seventeen 1
six 1
sixteen 1
strawberry 1
ten 1
thirteen 1
three 1
twelve 1
twenty 1
two 1
world 1

4. Hadoop伪分布模式(Pseudo-Distributed)搭建

伪分布式所有服务仅在1台机器上运行,但是配置与完全分布式类似

4.1. 为主机名添加DNS记录

编辑/etc/hosts,要为当前主机名添加一条记录

1
192.168.57.100 ubuntu

HDFS客户端也要编辑hosts文件,同样要添加DNS记录。因为之后客户端访问HDFS时,NameNode会让client去找DataNode(去找主机名为ubuntu的主机),如果没有添加记录,client就无法访问DataNode

1
192.168.57.100 ubuntu

4.2. 配置ssh本机免密码登录

SSH免密钥登录原理:

  1. A使用ssh-key-gen命令生成密钥对
  2. A将公钥拷贝到B的authorized_keys中
  3. A使用SSH访问B时,用私钥对数据加密
  4. B收到数据,从authorized_keys中找到A的公钥,对数据解密
  5. B给A一个回复,回复的数据用A的公钥加密
  6. A收到B的回复,用私钥解密。到此,A就成功连接上了B。

所以A想要免密钥登录B,需要预先将自己的公钥发送到B的authorized_keys中

运行ssh服务

1
2
3
# 选以下任意一条命令即可
/etc/init.d/ssh start
systemctl start ssh

设置本机免密码登录

1
2
3
4
5
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
# -t: 指定加密算法。此处指定使用rsa加密算法
# -P: 指定密钥的密码。因为是免密码,所以是空串
# -f: 指定生成的密钥文件名
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys # 将公钥添加到认证文件中

登录本地测试。默认情况下,ssh开启StrictHostKeyChecking yes,所以首次连接时会询问yes/no,回答yes即可

1
2
ssh localhost
exit

4.3. 编辑etc/hadoop/core-site.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<configuration>
<property>
<!-- hadoop的基本临时目录。dfs.namenode.name.dir之类的目录以该目录为基础
默认值是/tmp/hadoop-${user.name},而/tmp在系统重启时有可能被系统清理掉,后面配置的namenode和datanode数据存放路径都是基于${hadoop.tmp.dir}的,这样系统重启后数据就全丢了,下一次运行HDFS时必须要重新格式化namenode生成fsimage才行,所以必须要修改
-->
<name>hadoop.tmp.dir</name>
<value>file:/usr/local/hadoop/tmp</value>
</property>
<property>
<!-- NameNode在哪个主机,监听哪个端口
默认值是 file:///,即HDFS默认是本机模式
-->
<name>fs.defaultFS</name>
<value>hdfs://ubuntu:9000</value>
</property>
</configuration>

4.4. 编辑etc/hadoop/hdfs-site.xml

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
<configuration>
<property>
<!-- 块副本数(备份数)
因为只有一台机器,所以设置副本数为1
默认副本数为3。即使配置副本数为3,因为现在DataNode只有1个节点,所以块数据也只会产生1个副本。但是动态增加DataNode之后,NameNode发现增加了几台DataName之后,就会将数据块复制到其它的DataNode上,直到副本数达到dfs.replication
-->
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<!-- NameNode的fsimage存放的位置
默认值是 file://${hadoop.tmp.dir}/dfs/name,虽然手动设置的值和默认路径相同,但是默认值“file://”不符合URL规范,会出错,所以必须手动设置该参数的值。
-->
<name>dfs.namenode.name.dir</name>
<value>file:/usr/local/hadoop/tmp/dfs/name</value>
</property>
<property>
<!-- DataNode的块数据存放的位置
默认值是,file://${hadoop.tmp.dir}/dfs/data,同上,要手动再设置一下
-->
<name>dfs.datanode.data.dir</name>
<value>file:/usr/local/hadoop/tmp/dfs/data</value>
</property>
<property>
<!-- 禁用权限检查, 这样在windows下开发时,使用windows用户就能向HDFS写入数据 -->
<name>dfs.permissions.enabled</name>
<value>false</value>
</property>
</configuration>

4.5. 格式化NameNode

HDFS的格式化和系统磁盘的格式化含义是一致的。

NameNode节点上,有两个最重要的路径

  • dfs.namenode.name.dir:存储元数据信息
  • dfs.namenode.edits.dir:存储操作日志

格式化时,NameNode会清空两个目录下的所有文件,之后,会在两个目录下创建以下文件:

1
2
3
4
5
6
7
8
{dfs.namenode.name.dir}/current/fsimage   # 存储命名空间(目录和文件)的元数据信息
{dfs.namenode.name.dir}/current/fstime # 用来存储元数据上一次check point的时间
{dfs.namenode.name.dir}/current/VERSION # 存储NameNode版本信息,命名空间ID(版本号)
{dfs.namenode.name.dir}/image/fsimage
{dfs.namenode.edits.dir}/current/edits # 存储对命名空间操作的日志信息
{dfs.namenode.edits.dir}/current/fstime # 同上
{dfs.namenode.edits.dir}/current/VERSION # 同上
{dfs.namenode.edits.dir}/image/fsimage # 同上

因为默认${dfs.namenode.edits.dir}=${dfs.namenode.name.dir},所以两个目录实际上是同一个目录。所以只会看到这些文件

1
2
3
4
5
{dfs.namenode.name.dir}/current/fsimage   # 存储命名空间(目录和文件)的元数据信息
{dfs.namenode.name.dir}/current/fstime # 用来存储元数据上一次check point的时间
{dfs.namenode.name.dir}/current/VERSION # 存储NameNode版本信息,命名空间ID(版本号)
{dfs.namenode.name.dir}/image/fsimage
{dfs.namenode.edits.dir}/current/edits # 存储对命名空间操作的日志信息

所以格式化NameNode分两种情况:

  • 首次格式化:HDFS文件系统fsimage还不存在,需要格式化生成文件系统,之后才能对HDFS进行操作。
  • 再次格式化:清空HDFS文件系统的所有数据。

4.5.1. 首次格式化的操作

现在HDFS的文件系统还不存在,所以要先格式化NameNode。

1
2
3
# 以下两条命令等价,选择一条执行即可
hdfs namenode -format
hadoop namenode -format

看到以下信息,说明格式化成功

1
INFO common.Storage: Storage directory /usr/local/hadoop/tmp/dfs/name has been successfully formatted

查看格式化生成的文件

1
2
3
4
5
6
7
8
9
# tree tmp/
tmp/
└── dfs
└── name
└── current
├── fsimage_0000000000000000000
├── fsimage_0000000000000000000.md5
├── seen_txid
└── VERSION

4.5.2. 再次格式化的操作

第一步:先关闭Hadoop集群

第二步:再删除日志目录logs和${hadoop.tmp.dir}。注意一定要先关闭集群,不然一删除,logs和tmp目录又会生成。

1
2
rm -rf logs/				# 删除logs
rm -rf tmp # 删除${hadoop.tmp.dir}

第三步:再次格式化

1
hdfs namenode -format

4.5.3. 格式化前不删除tmp目录的后果

在NameNode格式化后,会生成一个clusterID。之后DataNode和SecondaryNameNode与NameNode通信后,会生成相同的clusterID。

1
2
3
4
5
6
7
8
9
10
11
12
$ find tmp/ -name 'VERSION'
tmp/dfs/name/current/VERSION
tmp/dfs/namesecondary/current/VERSION
tmp/dfs/data/current/BP-671477692-192.168.57.100-1550830174992/current/VERSION
tmp/dfs/data/current/VERSION

$ cat tmp/dfs/name/current/VERSION | grep clusterID # NameNode的clusterID
clusterID=CID-b1086067-1516-4cde-ad96-3cbb3c2afb7b
$ cat tmp/dfs/namesecondary/current/VERSION | grep clusterID # DataNode的clusterID
clusterID=CID-b1086067-1516-4cde-ad96-3cbb3c2afb7b
$ cat tmp/dfs/data/current/VERSION | grep clusterID # SecondaryNameNode的clusterID
clusterID=CID-b1086067-1516-4cde-ad96-3cbb3c2afb7b

如果不删除tmp目录,直接格式化NameNode,那么NameNode会生成新的clusterID,与DataNode和SecondaryNameNode的clusterID就不一致了。重启启动集群时,就会报错 java.io.IOException: Incompatible namespaceIDs,导致集群无法启动。

4.6. 启动HDFS服务

启动HDFS服务

1
start-dfs.sh

查看进程

1
2
3
4
5
$ jps
3157 DataNode
3034 NameNode
3371 SecondaryNameNode
3483 Jps

访问 NameNode的WebUI,默认端口50070

4.7. 在本地运行MapReduce

在mapred-default.xml中,mapreduce.framework.name默认值是local,所以MapReduce默认在本地运行。

在本地运行MapReduce

1
2
3
hdfs dfs -put input /   # 上传之前的input目录
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.5.jar wordcount /input /output # 以HDFS上的/input目录下所有文件作为输入,输出到HDFS的/output目录
hdfs dfs -cat /output/part* # 查看输出结果

4.8. 编辑etc/hadoop/mapred-site.xml

默认只有模板文件,所以先复制得到一份配置文件

1
cp etc/hadoop/mapred-site.xml.template etc/hadoop/mapred-site.xml

编辑 etc/hadoop/mapred-site.xml

1
2
3
4
5
6
7
<configuration>
<property>
<!-- 默认值为local,即mapreduce默认在本地运行,改为使用yarn运行mapreduce程序 -->
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>

4.9. 编辑etc/hadoop/yarn-site.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<configuration>
<property>
<!-- NodeManager上运行的附属服务。需配置成mapreduce_shuffle,才可以在YARN上运行MapReduce程序
mapreduce_shuffle表示,Reducer以shuffle的方式获取数据
-->
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<!-- 指定shuffle处理类,默认值就是ShuffleHandler,可不配置 -->
<name>yarn.nodemanager.aux-services.mapreduce_shuffle.class</name>
<value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>
<property>
<!-- 指定YARN的ResourceManager所在节点,默认为当前主机名,默认是0.0.0.0,不配置关系也不大 -->
<name>yarn.resourcemanager.hostname</name>
<value>ubuntu</value>
</property>
</configuration>

4.10. 在YARN上运行MapReduce

之前已经配置了在YARN上运行MapReduce,现在尝试运行MapReduce

1
2
3
hdfs dfs -put input /   # 上传之前的input目录
hdfs dfs -rm -r -f /output # 删除/output目录
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.5.jar wordcount /input /output # 运行MapReduce

因为YARN还没有启动,所以运行MapReduce后,会一直尝试连接YARN。CTRL+C 结束尝试。

1
INFO ipc.Client: Retrying connect to server: 0.0.0.0/0.0.0.0:8032   # 不断重复出现Retrying connect 信息

启动YARN

1
start-yarn.sh

再次运行MapReduce,成功

1
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.5.jar wordcount /input /output

4.11. 配置MapReduce历史服务器

在配置启动JobHistory服务之前,YARN的WebUI界面里是无法查看作业的历史信息的

4.11.1. 编辑etc/hadoop/mapred-site.xml

1
2
3
4
5
6
7
8
9
10
<property>
<!-- MapReduce JobHistory Server IPC host:port,默认值0.0.0.0:10020 -->
<name>mapreduce.jobhistory.address</name>
<value>ubuntu:10020</value>
</property>
<property>
<!-- MapReduce JobHistory Server Web UI host:port,默认值0.0.0.0:19888 -->
<name>mapreduce.jobhistory.webapp.address</name>
<value>ubuntu:19888</value>
</property>

4.11.2. 启动历史服务器

启动

1
mr-jobhistory-daemon.sh start historyserver

查看进程

1
2
3
4
5
6
7
$ jps
2721 NodeManager
2424 ResourceManager
3336 JobHistoryServer # 历史服务
1673 DataNode
1595 NameNode
3405 Jps

再次点击查看history

即可看到history的Overview主界面

Counters界面:查看各个计数器信息

Configuration界面:该作业在运行时,所有的配置信息

Map tasks界面:各个Map任务的运行信息

Reduce tasks界面:各个Reduce任务的运行信息

4.12. 配置YARN日志聚集

日志聚集概念:应用运行完成以后,将程序运行日志信息上传到HDFS系统上

日志聚集功能好处:可以方便的查看到程序运行详情,方便开发调试

注意:开启日志聚集功能,需要重新启动NodeManager 、ResourceManager和HistoryManager

4.12.1. 关闭相关服务

1
2
mr-jobhistory-daemon.sh stop historyserver
stop-yarn.sh

4.12.2. 编辑etc/hadoop/yarn-site.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<property>
<!-- 开启YARN的日志聚集功能。默认值为false -->
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<property>
<!-- 设置日志保留时间,单位为秒。
默认值为-1,表示不保留,即不启用日志聚合。所以只配置yarn.log-aggregation-enable,不设置yarn.log-aggregation.retain-seconds,也看不到日志。
设置7天,即604800秒
-->
<name>yarn.log-aggregation.retain-seconds</name>
<value>604800</value>
</property>

4.12.3. 启动相关服务

1
2
start-yarn.sh
mr-jobhistory-daemon.sh start historyserver

4.12.4. 再次运行WordCount

1
2
hdfs dfs -rm -r -f /output
jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.5.jar wordcount /input /output

4.12.5. 通过Web查看日志

先进入history页面

再进入logs页面

进入日志页面。默认只显示4096字节的日志信息,可点击查看完整日志

4.13. 配置文件说明

Hadoop配置文件分两类:默认配置文件和自定义配置文件,只有用户想修改某一默认配置值时,才需要修改自定义配置文件,更改相应属性值

要获取的默认文件 文件存放在Hadoop的jar包中的位置
core-default.xml hadoop-common-2.7.2.jar/ core-default.xml
hdfs-default.xml hadoop-hdfs-2.7.2.jar/ hdfs-default.xml
yarn-default.xml hadoop-yarn-common-2.7.2.jar/ yarn-default.xml
mapred-default.xml hadoop-mapreduce-client-core-2.7.2.jar/ mapred-default.xml

core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml四个配置文件存放在$HADOOP_HOME/etc/hadoop这个路径上,用户可以根据项目需求重新进行修改配置。

5. Hadoop完全分布式搭建

5.1. 集群规划

hostname hadoop1 hadoop2 hadoop3
ip 192.168.57.101 192.168.57.102 192.168.57.103
system ubuntu16.04 ubuntu16.04 ubuntu16.04
HDFS NameNode DataNode DataNode SecondaryNameNode DataNode
YARN NodeManager ResourceManager NodeManager NodeManager

原则:NameNode、SecondaryNameNode、ResourceManager最好分别处在不同的节点上

5.2. 配置静态ip

编辑 /etc/network/interfaces

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# hadoop1
auto ens33
iface ens33 inet static
address 192.168.57.101/24
gateway 192.168.57.2
dns-nameservers 114.114.114.114
# hadoop3
auto ens33
iface ens33 inet static
address 192.168.57.102/24
gateway 192.168.57.2
dns-nameservers 114.114.114.114
# hadoop2
auto ens33
iface ens33 inet static
address 192.168.57.103/24
gateway 192.168.57.2
dns-nameservers 114.114.114.114

5.3. 配置hostname

编辑 /etc/hostname

1
2
3
4
5
6
# hadoop1
hadoop1
# hadoop2
hadoop
# hadoop3
hadoop

5.4. 创建集群分发脚本xsync

因为 /usr/local/bin目录在$PATH中,该目录下的命令可以直接执行,所以创建 /usr/local/bin/xsync,写入以下内容

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
#!/bin/bash

### 获取输入参数个数,如果没有参数,直接退出
pcount=$#
if ((pcount == 0)); then
echo no args;
exit;
fi

### 获取文件名称
p1=$1
fname=`basename $p1`
echo fname=$fname

### 获取上级目录到绝对路径
pdir=`cd -P $(dirname $p1); pwd`
echo pdir=$pdir

### 获取当前用户名称
user=`whoami`

### 循环远程同步到各个节点上
for ((host = 1; host <= 3; host++)); do
echo ------------------- hadoop$host --------------
rsync -rvl $pdir/$fname $user@hadoop$host:$pdir
done

添加可执行权限

1
chmod 755 /usr/local/bin/xsync

5.5. 创建集群执行同一命令的脚本xcall

创建 /usr/local/bin/xcall

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash

### 获取输入参数个数,如果没有参数,直接退出
pcount=$#
if ((pcount == 0)); then
echo no args;
exit;
fi

### 获取当前用户名称
user=`whoami`

### 获取执行的命令(除了可执行文件名后面的所有参数)
cmd=$@

### 在各个节点上执行
for ((host = 1; host <= 3; host++)); do
# 打印执行的命令
echo --------------------- hadoop$host: $@ ---------------------
# ssh执行命令
ssh $user@hadoop$host $cmd
done

添加可执行权限

1
chmod 755 /usr/local/bin/xcall

命令测试

1
2
3
4
xcall echo 111 '>' ~/1.txt
xcall echo 111 '>>' ~/1.txt
xcall source /etc/profile '&&' jps
xcall ls -al

5.6. 添加hosts记录

编辑 /etc/hosts,添加以下记录

1
2
3
192.168.57.101 hadoop1
192.168.57.102 hadoop2
192.168.57.103 hadoop3

同步 /etc/hosts

1
xsync /etc/hosts

同步xsync脚本

1
xsync /usr/local/bin/xsync

5.7. 配置SSH免密码登录

hadoop1 hadoop2 hadoop3
HDFS NameNode DataNode DataNode SecondaryNameNode DataNode
YARN NodeManager ResourceManager NodeManager NodeManager

hadoop1是NameNode,故要能够免密钥登录到所有的HDFS节点(包括自身NameNode 、DataNode、SecondaryNameNode)

hadoop2是NodeManager,故要能够免密钥登录到所有的YARN节点(包括自身ResourceManager、NodeManager)

hadoop1和hadoop2执行以下操作

1
2
3
4
5
6
7
8
9
10
# 生成密钥对
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
# 将公钥添加到自身以及其它节点的authorized_keys文件中
ssh-copy-id -i ~/.ssh/id_rsa.pub hadoop1
ssh-copy-id -i ~/.ssh/id_rsa.pub hadoop2
ssh-copy-id -i ~/.ssh/id_rsa.pub hadoop3
# 连接测试
ssh hadoop1
ssh hadoop2
ssh hadoop3

5.8. 安装jdk

安装jdk,同步jdk和环境变量

1
2
xsync /usr/lib/java
xsync /etc/profile

各节点使环境变量生效

1
source /etc/profile

5.9. 安装并配置hadoop

安装hadoop,配置基本环境,与之前的操作一样

1
2
3
4
5
6
7
8
9
### 编辑etc/hadoop/hadoop-env.sh
export JAVA_HOME=/usr/lib/java/jdk
export HADOOP_PID_DIR=/usr/local/hadoop/tmp
### 编辑etc/hadoop/mapred-env.sh
export JAVA_HOME=/usr/lib/java/jdk
export HADOOP_MAPRED_PID_DIR=/usr/local/hadoop/tmp
### 编辑etc/hadoop/yarn-env.sh
export JAVA_HOME=/usr/lib/java/jdk
export YARN_PID_DIR=/usr/local/hadoop/tmp

同步hadoop和环境变量

1
2
xsync /usr/local/hadoop
xsync /etc/profile

各节点使环境变量生效

1
source /etc/profile

5.9.1. 编辑etc/hadoop/core-site.xml

1
2
3
4
5
6
7
8
9
10
11
12
<configuration>
<property>
<!-- hadoop的基本临时目录 -->
<name>hadoop.tmp.dir</name>
<value>file:/usr/local/hadoop/tmp</value>
</property>
<property>
<!-- NameNode在哪个主机,监听哪个端口 -->
<name>fs.defaultFS</name>
<value>hdfs://hadoop1:9000</value>
</property>
</configuration>

5.9.2. 编辑etc/hadoop/slaves

编辑slaves,一行一个datanode和nodemanager。注意:文件中不允许有空行,每行后面不允许有多余的空格。

1
2
3
hadoop1
hadoop2
hadoop3

5.9.3. 编辑etc/hadoop/hdfs-site.xml

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
<configuration>
<property>
<!-- 块副本数(备份数) -->
<name>dfs.replication</name>
<value>3</value>
</property>
<property>
<!-- NameNode的fsimage存放的位置
默认值是 file://${hadoop.tmp.dir}/dfs/name,虽然手动设置的值和默认路径相同,但是默认值“file://”不符合URL规范,会出错,所以必须手动设置该参数的值。
-->
<name>dfs.namenode.name.dir</name>
<value>file:/usr/local/hadoop/tmp/dfs/name</value>
</property>
<property>
<!-- DataNode的块数据存放的位置
默认值是,file://${hadoop.tmp.dir}/dfs/data,同上,要手动再设置一下
-->
<name>dfs.datanode.data.dir</name>
<value>file:/usr/local/hadoop/tmp/dfs/data</value>
</property>
<property>
<!-- SecondaryNameNode的HTTP服务 -->
<name>dfs.namenode.secondary.http-address</name>
<value>hadoop3:50090</value>
</property>
</configuration>

5.9.4. 编辑etc/hadoop/mapred-site.xml

默认只有模板文件,所以先复制得到一份配置文件

1
cp etc/hadoop/mapred-site.xml.template etc/hadoop/mapred-site.xml

编辑 etc/hadoop/mapred-site.xml

1
2
3
4
5
6
7
<configuration>
<property>
<!-- 默认值为local,即mapreduce默认在本地运行,改为使用yarn运行mapreduce程序 -->
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>

5.9.5. 编辑etc/hadoop/yarn-site.xml

1
2
3
4
5
6
7
8
9
10
11
12
<configuration>
<property>
<!-- Reducer以shuffle的方式获取数据 -->
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<!-- 指定YARN的ResourceManager所在节点 -->
<name>yarn.resourcemanager.hostname</name>
<value>hadoop2</value>
</property>
</configuration>

5.9.6. 同步hadoop

因为操作了很多文件,直接将整个hadoop同步一下

1
xsync /usr/local/hadoop

5.9.7. 格式化NameNode

在格式化之前注意:

  • 确保各个节点的服务都于关闭状态
  • 确保各个节点的logs和tmp目录已删除

hadoop1(NameNode)执行格式化命令

1
hdfs namenode -format

5.9.8. 启动HDFS

hadoop1(NameNode)执行

1
start-dfs.sh

查看进程

1
2
3
4
5
6
7
8
9
10
11
$ jps		# hadoop1
4259 DataNode
4109 NameNode
4766 Jps
$ jps # hadoop2
3426 Jps
3275 DataNode
$ jps # hadoop3
2853 DataNode
2972 SecondaryNameNode
3037 Jps

5.9.9. 启动YARN

hadoop2(ResourceManager)执行

1
start-yarn.sh

查看进程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ jps               # hadoop1
26753 Jps
26215 NameNode
26376 DataNode
26649 NodeManager
$ jps # hadoop2
26272 NodeManager
25969 ResourceManager
26403 Jps
25838 DataNode
$ jps # hadoop3
25680 NodeManager
25428 DataNode
25785 Jps
25563 SecondaryNameNode

5.10. 集群基本测试

input目录里有两个小文件

1
2
3
4
$ ls -l input
total 8
-rw-r--r-- 1 root root 280 2月 23 13:02 1.txt
-rw-r--r-- 1 root root 58 2月 23 13:03 2.txt

上传input目录

1
hdfs dfs -put input /input

Web查看。因为是小文件,所以都只有1个数据块,在3个DataNode上各有1个副本

查看块数据文件

1
2
3
4
5
6
$ ls -l tmp/dfs/data/current/BP-1856722919-192.168.57.101-1550860466565/current/finalized/subdir0/subdir0
total 16
-rw-r--r-- 1 root root 280 2月 23 13:03 blk_1073741825 # 1.txt对应的block
-rw-r--r-- 1 root root 11 2月 23 13:03 blk_1073741825_1001.meta
-rw-r--r-- 1 root root 58 2月 23 13:03 blk_1073741826 # 2.txt对应的block
-rw-r--r-- 1 root root 11 2月 23 13:03 blk_1073741826_1002.meta
1
2
cat blk_1073741825   # 1.txt的内容
cat blk_1073741826 # 2.txt的内容

上传大文件

1
2
$ ls -lh hadoop-2.6.5.tar.gz
-rw-r--r-- 1 root root 191M 2月 18 19:34 hadoop-2.6.5.tar.gz
1
hdfs dfs -put hadoop-2.6.5.tar.gz /

Web查看。191M的文件被分成2块,在3个DataNode上各有1个副本


查看块数据文件

1
2
3
4
5
6
7
8
9
10
$ ls -l tmp/dfs/data/current/BP-1856722919-192.168.57.101-1550860466565/current/finalized/subdir0/subdir0
total 196504
-rw-r--r-- 1 root root 280 2月 23 13:03 blk_1073741825
-rw-r--r-- 1 root root 11 2月 23 13:03 blk_1073741825_1001.meta
-rw-r--r-- 1 root root 58 2月 23 13:03 blk_1073741826
-rw-r--r-- 1 root root 11 2月 23 13:03 blk_1073741826_1002.meta
-rw-r--r-- 1 root root 134217728 2月 23 13:35 blk_1073741827 # block1
-rw-r--r-- 1 root root 1048583 2月 23 13:35 blk_1073741827_1003.meta
-rw-r--r-- 1 root root 65417541 2月 23 13:35 blk_1073741828 # block2
-rw-r--r-- 1 root root 511083 2月 23 13:35 blk_1073741828_1004.meta
1
2
cat blk_1073741827 blk_1073741828 >> tmpfile  # 拼接两个block,得到完整文件
tar -zxvf tmpfile # 原本是tgz,所以能解压

5.11. 集群时间同步

时间同步的方式:找一个机器,作为时间服务器,所有的机器与这台集群时间进行定时的同步,比如,每隔十分钟,同步一次时间。

5.11.1. 时间服务器配置

让hadoop1作为时间服务器

5.11.1.1. 安装ntp

1
2
dpkg -l | grep ntp  # 查看是否安装ntp
apt-get install -y ntp # 安装ntp

5.11.2. 编辑/etc/ntp.conf

修改1:授权 192.168.57.0/24 网段操作权限

1
2
3
4
### 授权方式是否定式的,如果不做任何限制,就是所有权限
# nomodify: 客户端不能通过ntpc和ntpq修改服务器的时间配置,但可以通过服务器来校时
# notrap: 不提供trap这个远程事件登录 (remote event logging) 的功能
restrict 192.168.57.0 mask 255.255.255.0 nomodify notrap

修改2:集群在局域网中,不使用其他互联网上的时间

1
2
3
4
5
# 默认会使用互联网上的时间,将以下语句注释
#pool 0.ubuntu.pool.ntp.org iburst
#pool 1.ubuntu.pool.ntp.org iburst
#pool 2.ubuntu.pool.ntp.org iburst
#pool 3.ubuntu.pool.ntp.org iburst

修改3:当该节点丢失网络连接,依然可以采用本地时间作为时间服务器为集群中的其他节点提供时间同步

1
2
server 127.127.1.0
fudge 127.127.1.0 stratum 10

5.11.2.1. 重启ntp服务

1
systemctl restart ntp

5.11.3. 其他机器配置

hadoop2、hadoop3是客户端,根据hadoop1校时

5.11.3.1. 安装ntpdate

1
apt-get install -y ntpdate

5.11.3.2. 测试ntpdate校时

1
2
3
4
5
6
7
8
timedatectl set-ntp no   # 默认开启NTP时间同步,先将其关闭,才能修改系统时间
# timedatectl set-time "1990-1-1 11:11:11" # 修改系统时间(timedatectl set-time不仅修改系统时间,还会修改硬件时间)
date -s "1990-1-1 11:11:11" # 仅修改系统时间
date # 查看系统时间
timedatectl status # 查看系统时间和硬件时间
ntpdate hadoop1 # 通过hadoop1进行校时
timedatectl status # 再查看系统时间,查看时间是否校正
timedatectl set-ntp yes # 测试结束,开启NTP时间同步

5.11.4. 设置校时计划任务

开启cron服务

1
systemctl start cron

crontab -e 添加计划任务,每10分钟通过hadoop1进行校时

1
2
# 注意命令要写绝对路径/usr/sbin/ntpdate,而不是写为ntpdate,因为crontab不会读取$PATH变量,会出现找不到ntpdate的情况
*/10 * * * * /usr/sbin/ntpdate hadoop1
panchaoxin wechat
关注我的公众号
支持一下