乐趣区

hadoop配置与wordcount

hadoop 配置与 wordcount
参考的博客大多都是 hadoop2.x 和低版本的 java 之上的,配置过程写出来看似很简单,看别人的博客也感觉步骤都差不多,但是自己配置时候出了很多问题:datanode 启动不了,网页不能正常显示,datanode 莫名死掉,resourcemanager 启动不了,nodemanager 启动不了,mapreduce 过程中无法连接到 slave 等等。这个过程看博客看日志折腾了许多时间才弄好,记录一下。
我是在虚拟机中安装了四个 linux 系统作为节点,所需环境相同,因此这里先配置一台,然后用虚拟机自带的功能直接复制得到其他三台。
环境:

Macos , Parallels Desktop
Linux 16.04
Jdk 1.8.0
Hadoop 3.2.0

Java 环境配置
在 oracle 官网下载最新的 jdk 压缩文件,复制到安装的目标目录下解压:
sudo tar -zxvf jdk-12_linux-x64_bin.tar.gz
sudo rm jdk-12_linux-x64_bin.tar.gz
然后配置环境变量。可以写在~/.bashrc 或者 /etc/profile 中,其中~/.bashrc 是在用户的主目录下,只对当前用户生效,/etc/profile 是所有用户的环境变量。
vim /etc/profile
在末尾加入 jdk 的环境变量
JAVA_HOME=/usr/lib/jdk-12
CLASSPATH=.:$JAVA_HOME/lib.tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
之后 source /etc/profile 生效,java —version 检查是否配置正确。
在后面启动 resourcemanager 时候出现了问题,更换成了 jdk8,过程同上。
ssh 免密钥连接
接着安装 hadoop,过程放在下一部分,安装好了之后复制生成三个相同环境的虚拟机。我用的是 parallels,相比于其他的比较稳定易用。

接着就是分布式的部分了。纯的分布式是很难实现的,hadoop 仍然是用一个 master 来集中式地管理数据节点,master 并不存储数据,而是将数据存储在 datanode 之中,这里命名为 slave1, slave2, slave3 三个 datanode,网络连接均为桥接。因此 master 需要能免密钥登陆到 slave。添加节点的 ip 地址(为了在 ip 变化时候不用再重新配置,可以配置静态 ip):
vim /etc/hosts
192.168.31.26 master
192.168.31.136 slave1
192.168.31.47 slave2
192.168.31.122 slave3

vim /etc/hostname
master # 分别配置 slave1, slave2, slave3

ping slave1 # 测试
安装 ssh,这个在 ubuntu 官方的源里面很慢,我试图换到国内的清华和阿里云等的源,但里面是没有的,也可能是有不同的版本之类的原因吧。懒得去管的话直接耐心等待就好了。
sudo apt-get install ssh
然后生成公钥和私钥:
ssh-keygen -t rsa
这里默认路径是用户主目录下.ssh,一路回车就好了。
使每台主机能够免密钥连接自己:
cp .id_rsa.pub authorized_keys
接着为了使 master 能够免密钥连接到 slave,将 master 的公钥追加到每个 slave 的 authorized_keys 中。
然后测试是否能够正常连接:
ssh slave1
安装配置 hadoop
从官网下载 hadoop3.2,解压到 /usr/lib/。并且将读权限分配给 hadoop 用户
cd /usr/lib
sudo tar –xzvf hadoop-3.2.0.tar.gz
chown –R hadoop:hadoop hadoop #将文件夹 ”hadoop” 读权限分配给 hadoop 普通用户
sudo rm -rf hadoop-3.2.0.tar.gz
添加环境变量:
HADOOP_HOME=/usr/lib/hadoop-3.2.0
PATH=$HADOOP_HOME/bin:$PATH
export HADOOP_HOME PATH
接着是最重要的配置 hadoop 部分,分别配置 HADOOP_HOME/etc/hadoop/ 下的以下几个文件:
hadoop-env.sh
export JAVA_HOME=/usr/lib/jdk1.8.0_201
core-site.xml
<configuration>
<property>
<name>hadoop.tmp.dir</name>
<value>/usr/lib/hadoop-3.2.0/tmp</value>
<description>Abase for other temporary directories.</description>
</property>
<property>
<name>fs.defaultFS</name>
<value>hdfs://master:9000</value>
</property>
</configuration>

hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<property>
<name>dfs.name.dir</name>
<value>/usr/lib/hadoop-3.2.0/hdfs/name</value>
</property>
<property>
<name>dfs.data.dir</name>
<value>/usr/lib/hadoop-3.2.0/hdfs/data</value>
</property>
</configuration>

yarn-site.xml
<configuration>
<property>
<name>yarn.resourcemanager.address</name>
<value>master:8032</value>
</property>
<property>
<name>yarn.resourcemanager.scheduler.address</name>
<value>master:8030</value>
</property>
<property>
<name>yarn.resourcemanager.resource-tracker.address</name>
<value>master:8031</value>
</property>
<property>
<name>yarn.resourcemanager.admin.address</name>
<value>master:8033</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address</name>
<value>master:8088</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>
<value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>
</configuration>

mapred-site.xml
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapred.job.tracker</name>
<value>master:49001</value>
</property>
<property>
<name>mapred.local.dir</name>
<value>/usr/lib/hadoop-3.2.0/var</value>
</property>

<property>
<name>yarn.app.mapreduce.am.env</name>
<value>HADOOP_MAPRED_HOME=$HADOOP_HOME</value>
</property>
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=$HADOOP_HOME</value>
</property>
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=$HADOOP_HOME</value>
</property>
</configuration>
workers
slave1
slave2
slave3
这些做完之后就配置完了,接着将整个文件夹复制到其他三台主机就完成了。
启动
格式化 namenode
hdfs namenode -format # 前提是已经将 HADOOP_HOME 添加到环境变量中

如果看到如上 INFO 说明这一步成功了。然后运行 start 脚本:
./sbin/start-all.sh # 在 hadoop 2.x 版本放在./bin/ 下面

用 jps 查看 Java 进程,master 应该包含 NameNode, SecondaryNameNode, ResourceManager,slave 应该包含 DataNode, NodeManager。这里很常见的问题包括没有 datanodes,没有访问权限,resouecemanager 不能启动等,一些原因我写在下面了,大部分都是配置出了问题,查看 log 文件就能找到原因。
通过 master:9870 可以网页查看集群状态。

WordCount 示例程序
wordcount 可以说是 hadoop 学习过程中的 ”hello world”,网上可以找到源码,也可以自己写,我这里直接用了官方 $HADOOP_HOME/share/hadoop/mapreduce/ 下的示例程序。
先将输入文件传到 dfs 中,我这里是自己写了两个含有 ”hadoop”, “hello”, “world” 单词的 txt 文件。然后运行示例程序:
hdfs dfs -mkdir /in
hdfs dfs -put ~/Desktop/file*.txt /in
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.2.0.jar wordcount /in /out

这里可以看到 mapreduce 分为 map 和 reduce 过程。mapreduce 分为 map,shuffle,reduce 过程,先将大任务分到各个节点分别计算,然后 shuffle 是按照一定的规则将不同的 key 值分到不同的节点做整合,然后提交任务再 reduce 整合。查看结果:
hdfs dfs -cat /out/part-r-00000

至此 hadoop 集群环境才能说是正确安装了。接下来就是修改 wordcount 代码自己玩了,上手后就可以自己写了。
一些遇到的问题

复制配置好的文件夹时候不小心复制错了,复制成了之前一次配置失败时候用过的文件夹,导致 datanode 启动一直失败,但是全程无提示。谷歌好久解决不了。后来看 datanode 的 log 文件找到错误的地方,是 core-site.xml 出了问题,修改之后重新格式化,启动成功。这个悲伤的故事告诉我们,出了问题先去看看 log 文件定位错误,大家的错误千奇百怪,谷歌不是万能的。

没有 resourcemanager 和 nodemanager:查看日志找到原因为 classNoFound(javax.XXXXXXX)。发现是由于 java9 以上的一些限制,默认禁用了 javax 的 API,参考博客得到解决办法有两个:

在 yarn-env.sh 中添加 (但是我试过不可行,由于本人不会 java,因此放弃深究)
export YARN_RESOURCEMANAGER_OPTS=”–add-modules=ALL-SYSTEM”
export YARN_NODEMANAGER_OPTS=”–add-modules=ALL-SYSTEM”

更换为 jdk8

第一次运行 wordcount 程序时候将 $HADOOP_HOME/etc/hadoop 整个文件夹全传入作为输入,结果出错,根据 log 发现是内存不足,我的每个虚拟机只开了 1G 的内存。由此可见这样的配置只是仅仅能够作为熟悉 hadoop 分布式环境用途,根本达不到能够解决问题的条件。

退出移动版