【Hadoop02】:安装Hadoop集群

前言

俗话说,工欲善其事必先利其器。我们要学习Hadoop,首先得把环境装好。学习一门技术,一定要实践、实践、再实践。千万不要光看不练,否则过几天你就忘了。本章我们先把环境搭好,运行一些基本的示例程序。

Hadoop集群可以在三种模式下运行:

  • 本地模式,所有的组件运行在一个JVM进程中,主要用于调试
  • 伪分布式模式,在一个节点上启动所有的组件,一般用于学习环境
  • 完全分布式模式,在多个节点上启动相应的组件,通常用于生产环境

那么我们在学习阶段应该采用哪种模式呢?如果你的机器环境允许的话,建议还是直接使用完全分布式模式来学习,能够更好的模拟生产环境。此外,一些故障问题只会在该模式下出现,在学习阶段出现的问题越多,对于你后续的成长进步就越大。不过在此我们对这三种模式都会进行演示。

环境准备

我们采用VMWare搭建三个节点的虚拟机,操作系统使用CentOS 7。创建好虚拟机后,分别设置主机名与IP地址,如下所示。

主机名 IP地址
hadoop01 192.168.100.11
hadoop02 192.168.100.12
hadoop03 192.168.100.13

设置完成后,别忘了在/etc/hosts中配置主机名映射,使之能够互相ping通。

在Hadoop的官网中,点击菜单栏中的Download,进入下载页面,下载hadoop-3.1.2安装包。

Hadoop下载

在Oracle的官网中,下载jdk8u201安装包。

JDK下载

关于JDK版本的选择,可以查看JDK版本兼容性

最后,在三个节点上创建hadoop用户,并将安装包上传到software目录下。

1
2
3
4
5
6
$ useradd hadoop
$ passwd hadoop
123456
123456
$ su - hadoop
$ mkdir software

将上传的jdk和hadoop安装包进行解压,并创建软连接,如图所示。

这里多说一句,为什么要创建hadoop用户,我直接在root用户下搞,不也一样么?当然可以,没有任何问题,但是有几点建议要说明:

  • 不建议使用root用户进行操作,因为你拥有所有的权限,操作的风险很高
  • 以后我们还会学习SparkKafkaFlink等框架,并且这些框架都要同时运行,你认为是全部使用一个用户来管理方便,还是使用独立的用户来操作合适呢
  • 在稍微有些规模的公司,集群的root权限都是不开放的,你可以申请sudo权限,但是所有的操作都会被监控,稍微不注意就会有违规
  • 在实际的生产环境中,不同的服务也是在不同的用户下启动的,我们最好遵循这种约定

$HADOOP_HOME/etc/hadoop/hadoop-env.sh中设置JAVA_HOME。

1
export JAVA_HOME=/home/hadoop/software/java

这里就体现出了软连接的好处了,软连接是为了方便软件的维护和升级,比如后期想换一个JDK版本,只需要把软连接指向新的JDK目录就行了,其他服务无需任何改动。

本地模式

默认情况下,hadoop被配置为本地模式,不需要我们进行过多的配置,就能运行。

下面我们参照官方的例子,运行一个简单的示例程序。

1
2
3
4
5
6
7
8
9
$ hostname
hadoop01
$ pwd
/home/hadoop/software/hadoop
$ mkdir input
$ cp etc/hadoop/*.xml input/
$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.2.jar grep input output 'dfs[a-z.]+'
$ cat output/*
1 dfsadmin

上面的例子是运行一个hadoop自带的MapReduce程序,对输入的文件每一行进行正则表达式匹配,并将匹配到的结果输出到指定目录。

当你运行$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.2.jar时,会显示所支持的其他例子,你也可以尝试运行其他例子。

伪分布式模式

伪分布式模式是在一个节点上运行hadoop的所有组件,下面我仍然以hadoop01节点为例,配置并运行伪分布式模式。

服务配置

配置$HADOOP_HOME/etc/hadoop/core-site.xml,如下所示。

1
2
3
4
5
6
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://hadoop01:9000</value>
</property>
</configuration>

配置$HADOOP_HOME/etc/hadoop/hdfs-site.xml,如下所示。

1
2
3
4
5
6
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>

配置$HADOOP_HOME/etc/hadoop/mapred-site.xml,如下所示。

1
2
3
4
5
6
7
8
9
10
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.application.classpath</name>
<value>$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/*:$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/lib/*</value>
</property>
</configuration>

配置$HADOOP_HOME/etc/hadoop/yarn-site.xml,如下所示。

1
2
3
4
5
6
7
8
9
10
<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.nodemanager.env-whitelist</name>
<value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value>
</property>
</configuration>

配置本机的免密登录,如下所示。

1
2
3
4
$ ssh-keygen -t rsa
4个回车
$ ssh-copy-id hadoop01
123456

配置完成后,使用ssh localhost登录进行测试。

注意,暂且不用考虑这些配置的含义是什么,先照着配置下来,能把服务启动起来就行。

启动服务

伪分布式模式下,需要启动多个JVM进程,也就是我们后面要学习到的NameNodeDataNodeResourceManagerNodeManager等,暂且不考虑这些角色的作用,先启动它们再说。

1
2
3
$ bin/hadoop namenode -format
$ sbin/start-dfs.sh
$ sbin/start-yarn.sh

命令执行完成后,我们可以通过jps查看当前已启动的进程。

我们也可以打开浏览器,访问NameNode和ResourceManager的Web页面。

1
2
http://hadoop01:9870/
http://hadoop01:8088/

测试

这次我们运行一个不同的MapReduce程序,统计文件中单词的个数。

创建一个文件,输入要统计的单词,例如我这里就创建一个words.txt文件,文件内容如下。

1
2
3
hadoop yarn spark mr
yarn hadoop mr yarn
hadoop hadoop spark

将文件上传到HDFS。

1
2
$ bin/hadoop fs -mkdir -p /test/input
$ bin/hadoop fs -put words.txt /test/input/

运行MapReduce程序。

1
$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.2.jar wordcount /test/input /test/output

查看执行结果。

1
2
3
4
5
$ bin/hadoop fs -cat /test/output/*
hadoop 4
mr 2
spark 2
yarn 3

完全分布式模式

前面的两种模式都是在单个节点上进行的,完全分布式是指hadoop相关的组件在不同的节点启动,我们使用3个节点来完成环境搭建。

在完全分布式模式中,我们尽量将每一步都说明清楚,尽量使得大家在此过程中少出错。(本节的配置较多,请大家认真操作)

使用root用户进行如下操作,注意三台节点都要进行此操作:

1
2
$ mkdir /data
$ chmod 777 /data

使用hadoop用户进行如下操作,注意三台节点都要进行此操作:

1
2
3
4
$ ssh-keygen -t rsa
$ ssh-copy-id hadoop01
$ ssh-copy-id hadoop02
$ ssh-copy-id hadoop03

服务配置

我们在hadoop01节点上进行配置,然后将配置文件复制到剩余两个节点上。

配置$HADOOP_HOME/etc/hadoop/hadoop-env.sh,如下所示。

1
2
3
export JAVA_HOME=/home/hadoop/software/java
export HADOOP_PID_DIR=/home/hadoop/hadoop/pid
export HADOOP_LOG_DIR=/home/hadoop/hadoop/logs

注意,这里配置了HADOOP_PID_DIR以及HADOOP_LOG_DIR,用于指定日志文件以及PID文件的存放位置。

配置$HADOOP_HOME/etc/hadoop/core-site.xml,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://hadoop01:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/data/hadoop</value>
</property>
<property>
<name>fs.trash.interval</name>
<value>1440</value>
</property>
</configuration>

配置说明:

  • fs.defaultFS,设置NameNode的URI,客户端通过此地址与其进行通信
  • hadoop.tmp.dir,设置Hadoop数据存放的根目录
  • fs.trash.interval,开启回收站功能,数据被删除后会进行回收站,保留时间是1440分钟(24小时),该配置默认为0,即不开启回收站

配置$HADOOP_HOME/etc/hadoop/hdfs-site.xml,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<configuration>
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<property>
<name>dfs.blocksize</name>
<value>268435456</value>
</property>
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>hadoop02:9868</value>
</property>
</configuration>

配置说明:

  • dfs.replication,指定HDFS文件的副本数量,这里我们配置为3,相当于一个文件会保存三份
  • dfs.blocksize,指定HDFS的块大小,HDFS会将上传的文件切分为块,存储到不同的节点上,这里指定块大小为256MB(如果不设置,默认为128MB),即一个1GB的文件会被切分为4块
  • dfs.namenode.secondary.http-address,设置SecondaryNameNode的HTTP地址与端口

配置$HADOOP_HOME/etc/hadoop/yarn-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
30
31
32
33
34
<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop02</value>
</property>
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>2048</value>
</property>
<property>
<name>yarn.nodemanager.remote-app-log-dir</name>
<value>/home/yarn/logs</value>
</property>
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>604800</value>
</property>
<property>
<name>yarn.log-aggregation.retain-check-interval-seconds</name>
<value>86400</value>
</property>
<property>
<name>yarn.nodemanager.env-whitelist</name>
<value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value>
</property>
</configuration>

配置说明:

  • yarn.nodemanager.aux-services,对于MapReduce程序设置的shuffle服务
  • yarn.resourcemanager.hostname,设置ResourceManager服务在哪台节点启动
  • yarn.log-aggregation-enable,是否要开启日志聚合服务,即保留提交到YARN程序的运行日志
  • yarn.nodemanager.resource.memory-mb,设置NodeManager最多能分配的物理内容大小,单位是MB
  • yarn.nodemanager.remote-app-log-dir,设置日志聚合的目录
  • yarn.log-aggregation.retain-seconds,聚合日志的保留时间,单位是秒
  • yarn.log-aggregation.retain-check-interval-seconds,多久时间检查一次聚合的日志保留时间
  • yarn.nodemanager.env-whitelist,容器可以从NodeManager继承下来的环境变量

配置$HADOOP_HOME/etc/hadoop/mapred-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>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>hadoop03:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>hadoop03:19888</value>
</property>
<property>
<name>mapreduce.map.memory.mb</name>
<value>512</value>
</property>
<property>
<name>mapreduce.reduce.memory.mb</name>
<value>512</value>
</property>
<property>
<name>mapreduce.application.classpath</name>
<value>$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/*:$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/lib/*</value>
</property>
</configuration>

配置说明:

  • mapreduce.framework.name,设置运行MapReduce任务的框架
  • mapreduce.jobhistory.address,设置运行任务历史服务的节点即端口
  • mapreduce.jobhistory.webapp.address,设置任务历史服务的Web节点和端口
  • mapreduce.map.memory.mb,设置MapReduce任务中每个map任务可以申请的内存总数,单位为MB
  • mapreduce.reduce.memory.mb,设置MapReduce任务中每个reduce任务可以申请的内容总数,单位为MB
  • mapreduce.application.classpath,设置MapReduce应用的classpath

配置$HADOOP_HOME/etc/hadoop/workers文件,如下所示:

1
2
3
hadoop01
hadoop02
hadoop03

该文件中每行都是一个节点地址,用于执行启动脚本时,自动使用ssh的方式登录到其他节点启动相关服务,这也是我们设置节点之间免密登录的原因。

配置就此完成,我们需要将配置复制到其他节点。

1
2
3
4
$ pwd
/home/hadoop/software/hadoop/etc/hadoop
$ scp ./* hadoop@hadoop02:$PWD
$ scp ./* hadoop@hadoop03:$PWD

启动服务

hadoop01节点上,执行如下命令。

1
2
3
4
$ pwd
/home/hadoop/software/hadoop
$ bin/hadoop namenode -format
$ sbin/start-dfs.sh

hadoop01节点进程如下所示。

hadoop02节点上,执行如下命令。

1
$ sbin/start-yarn.sh

hadoop02节点进程如下所示。

hadoop03节点上,执行如下命令。

1
$ bin/mapred --daemon start historyserver

hadoop03节点进程如下所示。

如果发现没有启动相应的进程,可以在$HADOOP_HOME/hadoop/logs目录下查看相关日志,找出问题原因。

测试

本次测试我们仍然使用自带的MapReduce程序来完成,不过为了更加有乐趣,我们通过脚本来生成测试数据。

下面是生成测试数据的脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash

words=("hadoop" "spark" "kafka" "elasticsearch" "zookeeper" "flume" "flink" "hive" "hbase" "storm")
len=${#words[@]}
count=$1

for((start=1; start<=$count; start++))
do
str=""
for((i=0; i<10; i++))
do
r=$(($RANDOM % $len))
str="$str ${words[$r]}"
done
echo $str
done

脚本很简单,用户指定要生成的行数,就可以生成指定行数的随机单词,每行10个,可以通过以下的方式进行调用。

1
2
3
$ sh generate.sh 100000 >> words1.txt
$ sh generate.sh 100000 >> words2.txt
$ sh generate.sh 100000 >> words3.txt

我们生成了3个数据文件,每个文件中分别有十万行数据,每行数据10个单词。当然,生成数据的时间根据各人环境有所不同,你也可以生成少量的数据来进行测试,没有任何影响。

下面我们将生成后的数据上传到HDFS,并提交MapReduce程序来完成WordCount。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ bin/hadoop fs -mkdir -p /wordcount/input
$ bin/hadoop fs -put words* /wordcount/input
$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.2.jar wordcount /wordcount/input /wordcount/output
$ bin/hadoop fs -cat /wordcount/output/*
elasticsearch 300618
flink 299106
flume 299967
hadoop 299112
hbase 301227
hive 301083
kafka 299595
spark 299892
storm 299835
zookeeper 299565

小结

本章介绍了hadoop的三种运行模式:本地模式、伪分布式模式以及完全分布式模式。并针对每种模式进行了环境搭建、服务配置以及测试。本章配置较多,稍微不留意就会出错,需要结合日志文件定位错误的原因。

如果您觉得不错,请赞赏一下!