Hadoop使用学习笔记

1.Hadoop安装与基本概念

Hadoop发行版本地址

1.1环境配置需求

本文是用的Hadoop版本是最新的2.7.2发行版。
本文分两个机器环境,分别是研发环境和测试环境:


环境配置:
操作系统:
LSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch
Distributor ID: RedHatEnterpriseServer
Description: Red Hat Enterprise Linux Server release 6.6 (Santiago)
Release: 6.6
Codename: Santiago
硬件配置:
内存 16384MB
虚拟处理器(VCPU) 8
硬盘 40GB

首先检查环境配置,
1.Java需求,目前Java版本支持度测试,Hadoop2.7需要Java1.7以上的版本,Hadoop2.6以及之前的需要Java1.6版本以上。
2.Hadoop利用ssh远程操控集群,所以需要ssh(输入sshd命令看是否可以找到这个命令)
3.rsync命令是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件。rsync使用所谓的rsync算法来使本地和远程两个主机之间的文件达到同步,这个算法只传送两个文件的不同部分,而不是每次都整份传送,因此速度相当快。(同理,请输入rsync 命令检查是否存在)
之后开始安装,下载好Hadoop,解压:

>tar zxvf hadoop-2.7.2.tar.gz
>cd hadoop-2.7.2
>ll 
total 52
drwxr-xr-x 2 sfdba usr01  4096 Jan 26 08:20 bin
drwxr-xr-x 3 sfdba usr01  4096 Jan 26 08:20 etc
drwxr-xr-x 2 sfdba usr01  4096 Jan 26 08:20 include
drwxr-xr-x 3 sfdba usr01  4096 Jan 26 08:20 lib
drwxr-xr-x 2 sfdba usr01  4096 Jan 26 08:20 libexec
-rw-r--r-- 1 sfdba usr01 15429 Jan 26 08:20 LICENSE.txt
-rw-r--r-- 1 sfdba usr01   101 Jan 26 08:20 NOTICE.txt
-rw-r--r-- 1 sfdba usr01  1366 Jan 26 08:20 README.txt
drwxr-xr-x 2 sfdba usr01  4096 Jan 26 08:20 sbin
drwxr-xr-x 4 sfdba usr01  4096 Jan 26 08:20 share

解压完毕后,需要修改一个脚本。修改etc/hadoop/hadoop-env.sh

>vim etc/hadoop/hadoop-env.sh

修改其中的JAVA_HOME为java安装路径,hadoop运行时会在后面加上/bin/java来启用java

# The java implementation to use.
export JAVA_HOME=/usr/lib/jvm/jre-1.7.0-openjdk.x86_64/

之后保存,运行一个简单的hadoop命令,看到如下输出,则成功:

>bin/hadoop version
Hadoop 2.7.2
Subversion https://git-wip-us.apache.org/repos/asf/hadoop.git -r b165c4fe8a74265c792ce23f546c64604acf0e41
Compiled by jenkins on 2016-01-26T00:08Z
Compiled with protoc 2.5.0
From source with checksum d0fda26633fa762bff87ec759ebe689c
This command was run using /home/sfdba/hadoop-2.7.2/share/hadoop/common/hadoop-common-2.7.2.jar

下面测试官网给的独立运行测试:

mkdir input
cp etc/hadoop/*.xml input
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.2.jar grep input output 'dfs[a-z.]+'
cat output/*

这是一段将所有配置文件作为输入,检查其中匹配’dfs[a-z.]+’这个正则表达式(开头是dfs末尾为多个字母的词语)的词语的个数

1.2 伪集群安装

Hadoop可以单机伪集群模式运行。
首先我们先来明确几个概念:
Hadoop主要由两部分构成,分别是Mapreduce计算部分,还有底层存储HDFS。
系统架构(manager-worker架构):

其中Namenode就是整个集群中的Manager,保存着文件系统的命名空间,以及维护整个文件系统。这些信息保存在两个文件中形式中:命名空间镜像文件还有编辑日志文件。也记录着每个文件的**块(有的地方叫block也有叫chunk,都可以,磁盘块大概512字节,Hadoop中目前默认为128MB,原理:块设置的足够大,那么块寻址时间将远小于磁盘传输时间,减少寻址占比。假设寻址时间为10ms,传输速度为100MB/s,那么块设置为100MB,将使寻址时间占比约为1%)**所载在的据节点信息,但是不是持久化的,这些信息会在系统启动时,由数据节点重建
Datanode就是文件系统中的工作节点,根据需要存储并检索数据库块,并且定时向Namenode发送所存储块的列表。
Namenode不能损坏,否则数据无法从data中拼接出来

伪集群安装,就是在单机部署多个Hadoop实例(多个JVM运行)。这里,我们部署一个namenode和一个datanode的单机伪集群。
首先,我们需要修改etc/hadoop/core-site.xml,添加如下所示:

<configuration>
        <property>
                <!-指定HDFS服务端口-->
                <name>fs.defaultFS</name>
                <value>hdfs://localhost:9000</value>
        </property>
</configuration>

之后修改HDFS配置文件:

<configuration>
        <property>
                <!-指定HDFS数据复制份数-->
                <name>dfs.replication</name>
                <value>1</value>
        </property>
</configuration>

之后,检查是否可以无参正常ssh连接localhost

>ssh localhost

如果不行,则执行如下命令生成SSH秘钥:

>ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
>cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
>chmod 0600 ~/.ssh/authorized_keys

之后启动HDFS,分为如下几步:
1.格式化文件系统,执行下面命令,初始化Hadoop文件系统HDFS(其实就是初始化保存目录以及namenode中要保存的metadata)如果,,日志中没报错并且看到INFO util.ExitUtil: Exiting with status 0的话则成功初始化

>bin/hdfs namenode -format

2.启动Datanode还有Namenode。运行下面命令:

>sbin/start-dfs.sh

打开浏览器,访问http://你的机器ip:50070,如果出现如下类似界面,则成功

3.下一步我们为当前用户创建必要的目录

>bin/hdfs dfs -mkdir /user
#这里<username>替换成你当前系统用的用户名
>bin/hdfs dfs -mkdir /user/<username>

查看刚才网页中的Utilities->Browse the file system,可以看到我们之前创建的文件夹:

4.接下来接着使用刚才的例子测试,首先将etc/hadoop 目录下的文件传入HDFS中的input文件夹(就是放在/usr//input中)

>bin/hdfs dfs -put etc/hadoop input

之后执行刚才的例子:

>bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.2.jar grep input output 'dfs[a-z.]+'

命令中指定结果放在HDFS的/usr/<username>/output文件夹中,查看结果,结果如下所示:

>bin/hdfs dfs -cat output/*
6       dfs.audit.logger
4       dfs.class
3       dfs.server.namenode.
2       dfs.period
2       dfs.audit.log.maxfilesize
2       dfs.audit.log.maxbackupindex
1       dfsmetrics.log
1       dfsadmin
1       dfs.servers
1       dfs.replication
1       dfs.file

可以看出,HDFS其实和linux的基本文件系统在使用命令上大同小异

5.停止集群:

>sbin/stop-dfs.sh

1.3 利用YARN提交任务

确认上面1.2节的前三步已经执行后,我们可以通过YARN(Yet Another Resource Negotiator)来提交MapReduce任务。
为了能够对集群中的资源进行统一管理和调度,Hadoop 2.0引入了数据操作系统YARN。YARN的引入,大大提高了集群的资源利用率,并降低了集群管理成本。首先,YARN允许多个应用程序运行在一个集群中,并将资源按需分配给它们,这大大提高了资源利用率,其次,YARN允许各类短作业和长服务混合部署在一个集群中,并提供了容错、资源隔离及负载均衡等方面的支持,这大大简化了作业和服务的部署和管理成本。
之后我们会详细介绍YARN。
首先,如果要里用YARN提交任务,我们需要先启动YARN。修改etc/hadoop/mapred-site.xml:

<configuration>
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
</configuration>

之后修改YARN配置etc/hadoop/yarn-site.xml:

<configuration>
    <property>
        <name>yarn.nodemanager.aux-services</name>
        <value>mapreduce_shuffle</value>
    </property>
</configuration>

启动YARN:

>sbin/start-yarn.sh

访问http://你的机器ip:8808,可以看到YARN控制台
就可以以YARN的方式提交MapReduce任务。
关闭YARN:

>sbin/stop-yarn.sh

1.4 Hadoop集群安装

在Hadoop集群中,一般包括如下七个元素:
HDFS: NameNode, SecondaryNameNode, 还有DataNode
YARN:ResourceManager, NodeManager, 还有WebAppProxy
如果需要用到MapReduce,则MapReduce历史服务器也需要用到。
我们通过修改etc/hadoop/hadoop-env.sh, etc/hadoop/mapred-env.sh and etc/hadoop/yarn-env.sh这三个脚本来修改一些关于JVM的配置。
这里我们对于云环境,稍微修改限制下JVM heap size,防止内存溢出。

**第一步,首先配置每台机器的host文件。**对于每台机器,执行 vim /etc/hosts 添加:

#三台机器/etc/hosts文件配置,nosql1作为主,nosql2作为从
10.202.7.184 nosql1
10.202.7.185 nosql2
10.202.7.186 nosql3

之后,在每台机器上分别执行:

ping nosql1
ping nosql2
ping nosql3

看网络是否通畅。

第二步,添加hadoop用户,配置两台机器ssh无密登陆。
几台机器中的hadoop用户以及hadoop存放路径需要相同,否则hadoop HDFS会找不到节点。
SSH无密码原理:Master作为客户端,要实现无密码公钥认证,连接到服务器Salve上时,需要在Master上生成一个密钥对,包括一个公钥和一个私钥,而后将公钥复制到所有的Slave上。当Master通过SSH连接Salve时,Salve就会生成一个随机数并用Master的公钥对随机数进行加密,并发送给Master。Master收到加密数之后再用私钥解密,并将解密数回传给Slave,Slave确认解密数无误之后就允许Master进行连接了。这就是一个公钥认证过程,其间不需要用户手工输入密码。
以nosql1举例,首先在master上创建hadoop用户,属于hadoop组:

#创建hadoop组
groupadd hadoop
#创建具有管理员权限的用户hadoop,属于hadoop组,同时自动创建用户home目录
useradd -g hadoop -r -m hadoop
#修改hadoop密码
passwd hadoop
#切换到hadoop用户
su - hadoop

之后,我们需要生成SSH秘钥:

#生成公钥私钥至~/.ssh/id_dsa
ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
#添加到授权秘钥
cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
#更改权限为仅限当前用户读写
chmod 0600 ~/.ssh/authorized_keys

验证是否可以无密登陆本机:

ssh localhost

在slave上添加同样的用户后,从master将公钥拷贝过去:

ssh-copy-id hadoop@nosql2
ssh-copy-id hadoop@nosql3

验证成功后,即可无密登陆nosql2和nosql3

ssh nosql2
ssh nosql3

之后以相同的方式配置slave无密登陆master即可
注意:每次修改host中的相关DNS信息后,需要清除掉之前的SSH公钥秘钥,重新生成

第三步,配置Hadoop。
如下配置:
etc/hadoop/core-site.xml:

<configuration>
        <property>
                <name>fs.defaultFS</name>
                <value>hdfs://nosql1:9000</value>
        </property>
        <property>
                <name>io.file.buffer.size</name>
                <value>131072</value>
        </property>
</configuration>

etc/hadoop/hdfs-site.xml:

<configuration>
        <property>
                <name>dfs.replication</name>
                <value>1</value>
        </property>
        <!--Path on the local filesystem where the NameNode stores the namespace and transactions logs persistently.-->
        <!--If this is a comma-delimited list of directories then the name table is replicated in all of the directories, for redundancy.-->
        <property>
                <name>dfs.namenode.name.dir</name>
                <value>/home/hadoop/nnData1,/home/hadoop/nnData2</value>
        </property>
        <!--HDFS blocksize of 256MB for large file-systems.-->
        <property>
                <name>dfs.blocksize</name>
                <value>268435456</value>
        </property>
        <!--More NameNode server threads to handle RPCs from large number of DataNodes.-->
        <property>
                <name>dfs.namenode.handler.count</name>
                <value>5</value>
        </property>
        <!--Comma separated list of paths on the local filesystem of a DataNode where it should store its blocks.-->
        <property>
                <name>dfs.datanode.data.dir</name>
                <value>/home/hadoop/dnData1,/home/hadoop/dnData2,/home/hadoop/dnData3</value>
        </property>
        <property>
                <name>dfs.namenode.secondary.http-address</name>
                <value>nosql2:9001</value>
        </property>
</configuration>

etc/hadoop/mapred-site.xml:

<configuration>
         <property>
                <name>mapreduce.framework.name</name>
                <value>yarn</value>
         </property>
        <property>
                 <name>mapreduce.jobhistory.address</name>
                <value>nosql1:10020</value>
        </property>
        <property>
                 <name>mapreduce.jobhistory.webapp.address</name>
                <value>nosql1:19888</value>
        </property>
</configuration>

etc/hadoop/yarn-site.xml:

<configuration>
        <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>
        <property>
                <name>yarn.resourcemanager.address</name>
                <value>nosql1:8032</value>
        </property>
        <property>
                <name>yarn.resourcemanager.scheduler.address</name>
                <value>nosql1:8030</value>
        </property>
        <property>
                <name>yarn.resourcemanager.resource-tracker.address</name>
                <value>nosql1:8031</value>
        </property>
        <property>
                <name>yarn.resourcemanager.admin.address</name>
                <value>nosql1:8033</value>
        </property>
        <property>
                <name>yarn.resourcemanager.webapp.address</name>
                <value>nosql1:8088</value>
        </property>
</configuration>

etc/hadoop/slaves:

nosql2
nosql3

第四步,修改脚本
至少要修改JAVA_HOME为你的JAVA安装地址
在hadoop-env.sh,mapred-env.sh,yarn-env.sh添加或修改:

export JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.101-2.6.6.1.el7_2.x86_64/jre

第五步,格式化,启动集群
首先将master上配置好的hadoop拷贝传输到slave上,注意master和slave上的hadoop路径一定要一致:

scp –r hadoop-2.7.2 hadoop@nosql2:/home/hadoop/
scp –r hadoop-2.7.2 hadoop@nosql3:/home/hadoop/

传输完成,在master上执行:

>bin/hdfs namenode -format

sbin/start-all.sh

启动完成后,在主机执行jps,可以看到:

7826 NameNode
8662 Jps
8092 ResourceManager

在从机上执行,可以看到:

30742 Jps
29552 SecondaryNameNode
29638 NodeManager
29425 DataNode

访问:http://nosql1:50070/查看HDFS集群状况
访问:http://nosql1:8088/cluster查看任务状况
接着测试之前的MapReduce任务:

bin/hdfs dfs -mkdir -p /test/input
bin/hdfs dfs -put ./etc/hadoop/hdfs-site.xml /test/input
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.2.jar grep /test/input /test/output 'dfs[a-z.]+'

观察结果即可:
这里写图片描述

这里写图片描述

问题整理:

1、Map-Reduce成功,结果失败:Job history中:

2014-06-04 13:17:20,060 ERROR [Thread-62] org.apache.hadoop.mapreduce.v2.app.rm.RMContainerAllocator: Exception while unregistering 
java.lang.NullPointerException
    at org.apache.hadoop.mapreduce.v2.util.MRWebAppUtil.getApplicationWebURLOnJHSWithoutScheme(MRWebAppUtil.java:133)
    at org.apache.hadoop.mapreduce.v2.util.MRWebAppUtil.getApplicationWebURLOnJHSWithScheme(MRWebAppUtil.java:148)
    at org.apache.hadoop.mapreduce.v2.app.rm.RMCommunicator.doUnregistration(RMCommunicator.java:207)
    at org.apache.hadoop.mapreduce.v2.app.rm.RMCommunicator.unregister(RMCommunicator.java:177)
    at org.apache.hadoop.mapreduce.v2.app.rm.RMCommunicator.serviceStop(RMCommunicator.java:250)
    at org.apache.hadoop.mapreduce.v2.app.rm.RMContainerAllocator.serviceStop(RMContainerAllocator.java:255)
    at org.apache.hadoop.service.AbstractService.stop(AbstractService.java:221)
    at org.apache.hadoop.service.ServiceOperations.stop(ServiceOperations.java:52)
    at org.apache.hadoop.mapreduce.v2.app.MRAppMaster$ContainerAllocatorRouter.serviceStop(MRAppMaster.java:817)
    at org.apache.hadoop.service.AbstractService.stop(AbstractService.java:221)
    at org.apache.hadoop.service.ServiceOperations.stop(ServiceOperations.java:52)
    at org.apache.hadoop.service.ServiceOperations.stopQuietly(ServiceOperations.java:80)
    at org.apache.hadoop.service.CompositeService.stop(CompositeService.java:159)
    at org.apache.hadoop.service.CompositeService.serviceStop(CompositeService.java:132)
    at org.apache.hadoop.service.AbstractService.stop(AbstractService.java:221)
    at org.apache.hadoop.mapreduce.v2.app.MRAppMaster.shutDownJob(MRAppMaster.java:548)
    at org.apache.hadoop.mapreduce.v2.app.MRAppMaster$JobFinishEventHandler$1.run(MRAppMaster.java:599)

表明:某个host配置有问题,检查*-site.xml中所有的域名是否正确

2、都提示成功,但是找不到datanode,但是jps中有datanode,datanode日志报错:

2016-07-19 16:38:13,817 INFO org.apache.hadoop.hdfs.server.datanode.DataNode: Block pool BP-896553954-10.202.44.205-1468914346523 (Datanode Uuid null) service to /10.202.44.205:9000 beginning handshake with NN
2016-07-19 16:38:13,820 ERROR org.apache.hadoop.hdfs.server.datanode.DataNode: Initialization failed for Block pool BP-896553954-10.202.44.205-1468914346523 (Datanode Uuid null) service to /10.202.44.205:9000 Datanode denied communication with namenode because hostname cannot be resolved (ip=10.202.44.206, hostname=10.202.44.206): DatanodeRegistration(0.0.0.0:50010, datanodeUuid=9ef57feb-d3a5-47c4-9ed2-db386e4969a8, infoPort=50075, infoSecurePort=0, ipcPort=50020, storageInfo=lv=-56;cid=CID-d5340873-3047-4a6a-89db-8aba9ee5846b;nsid=463107860;c=0)
        at org.apache.hadoop.hdfs.server.blockmanagement.DatanodeManager.registerDatanode(DatanodeManager.java:863)
        at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.registerDatanode(FSNamesystem.java:4528)
        at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.registerDatanode(NameNodeRpcServer.java:1285)
        at org.apache.hadoop.hdfs.protocolPB.DatanodeProtocolServerSideTranslatorPB.registerDatanode(DatanodeProtocolServerSideTranslatorPB.java:96)
        at org.apache.hadoop.hdfs.protocol.proto.DatanodeProtocolProtos$DatanodeProtocolService$2.callBlockingMethod(DatanodeProtocolProtos.java:28752)
        at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:616)
        at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:969)
        at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2049)
        at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2045)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAs(Subject.java:415)
        at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1657)
        at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2043)

表明:域名填写的是IP,改成域名。

3、执行ssh-copy-id hadoop@nosql2
提示:/usr/bin/ssh-copy-id: ERROR: No identities found
改成指定公钥文件的命令:
ssh-copy-id -i ~/.ssh/id_dsa.pub nosql2

4、远程登录被拒绝:
设置允许远程登录,linux一般都通过ssh远程连接,修改/etc/ssh/sshd_config文件
在结尾处添加 AllowUsers 用户名,如 AllowUsers zhangsan
保存,退出
重启ssh服务,service sshd restart