后记:建议生产环境部署CDH3版本,而不是apache版本,CDH3版本对apache版本做了很多性能方面的优化,经实际测试,效率要高于apache版本,有很多公司在使用CDH3版本的hadoop
下载:
0.21版本已经很长时间没有维护,存在一些bug,所以应该部署0.20版本。当前版本为0.20.204.0
注意:该笔记部署时没有使用本机的hostname,而是通过再hosts文件中添加解析来解析各节点,在部署和使用hadoop时没有问题,但是,后期添加kerberos时因为主机名的问题遇到很多的故障,所以,建议还是使用hostname做为各节点解析的名称。
下载jdk 1.6
一、我的环境:
192.168.122.1 master(namenode/jobtracker)
192.168.122.21 slave(datanode/tasktracker)
192.168.122.31 slave(datanode/tasktracker)
namenode将上传的文件分成数据块,分发数据块到datanode。
jobtracker将job分成task,分发到tasktracker。
namenode和datanode和hdfs有关。jobtracker和tasktracker和map reduce有关。
注意:在0.21版本上,一台主机即是namenode又是datanode,会出现异常,所以,尽量不要这么做。遇到的问题在后面会提到。
注意:后面涉及到的服务器,都必须使用主机名或域名,而不能使用ip。
hadoop 使用”master“和"slave"配置文件中定义的域名,并在/etc/hosts或DNS中找到相关的ip地址来进行引用的。
而 Map-Reduce 或任何 Hadoop class 又可能使用机器名 hostname 来进行引用。
如果你的环境不能通过修改主机名或域名来使hostname 和 /etc/hosts 里的hadoop虚拟域名一致,你需要分别添加hostname 和hadoop虚拟域名的解析
修改所有服务器的host文件
/etc/hosts
-
192.168.122.1 hdp-namenode centosvm3
-
192.168.122.21 hdp-datanode2 centosvm2
-
192.168.122.31 hdp-datanode3 srv4.lf.com
注意:一定要把本机的主机名写上,因为在启动时会解析本机的主机名到IP。不写得话会报错:
STARTUP_MSG: host = java.net.UnknownHostException:
可以使用进行测试
groovy -e "print InetAddress.getLocalHost().getHostName()"
注意:在Hadoop中,主机名不要包含下划线“_”,但可以有横线“-”。
删除127.0.0.1及::1的解析。
I commented the localhost thing. The reason during reduce phase some sort of copying happens between nodes and at that time it has to be identified by its host name i,e master, node1, node2, node3, node4 etc. But if localhost is present it will treated as localhost and then it faces the “too many fetch failure” (as it is not able to complete a FETCH successfully.
下面的错误就是由于没有正确解析主机名和ip地址造成的:
那么基本上你的 reduce 不太可能会成功,在 name node 的 console 里每当执行到 reduce 的时候会报出这种错误:
Shuffle Error: Exceeded MAX_FAILED_UNIQUE_FETCHES; bailing-out
二、hadoop
下载
文档:
1、配置环境变量
-
export PATH=$PATH:/usr/local/hadoop/bin/
-
echo "export PATH=$PATH:/usr/local/hadoop/bin/" >>/etc/profile
-
-
export HADOOP_HOME=/usr/local/hadoop
-
echo "export HADOOP_HOME=/usr/local/hadoop" >>/etc/profile
注:0.20.204
hadoop的目录:
namenode在启动datanode时,将namenode上hadoop所在的物理路径当做参数传递给datanode作为启动参数,所以,如果datanode上不存在这个路径,将无法启动,解决办法就是在datanode上见软连接,或更改namenode的hadoop home的物理路径。
20131219 更新:最好不要使用软连接,会有很多奇怪的问题,还是使用cp文件到hadoop目录或者使用mount --bind比较稳妥。
如果存在libexec/hadoop-config.sh文件,则查看该文件,否则,查看bin/hadoop-config.sh:
-
common_bin=$(cd -P -- "$(dirname -- "$this")" && pwd -P)
cd -P的作用:The -P option says to use the physical directory structure instead of following symbolic links。即使用物理地址。
所以,最后传递给datanode 的HADOOP_HOME的地址会是物理地址,而不是软链接的地址,如果namenode和datanode的hadoop没有安装同一个目录造成datanode找不到目录而启动失败。为什么要这样?
vi /usr/local/hadoop/conf/hadoop-env.sh
添加:
-
export JAVA_HOME=/usr/java/jdk1.6.0_22/
2、创建hadoop hdfs的目录,用于存放上传到hadoop集群的文件
-
mkdir /hadoop_data/
-
chown -R hadoop.hadoop /usr/local/hadoop/ /hadoop_data/
3、在name 及datanode上执行,用于配置使用key,不需密码登陆。
注意主要用于当start-all.sh时,namenode去启动slave,所以,只需要namenode 可以访问datanode即可。
su - hadoop
ssh-keygen -d
-
cat ~/.ssh/id_dsa.pub |while read line;\
-
do \
-
ssh hadoop@hdp-datanode2 \
-
"echo $line >>/home/hadoop/.ssh/authorized_keys2 &&\
-
chmod 600 /home/hadoop/.ssh/authorized_keys2";\
-
done
-
-
cat ~/.ssh/id_dsa.pub |while read line;\
-
do \
-
ssh hadoop@hdp-datanode3 \
-
"echo $line >>/home/hadoop/.ssh/authorized_keys2 &&\
-
chmod 600 /home/hadoop/.ssh/authorized_keys2";\
-
done
为了防止错误的使用其他用户启动hadoop,修改下面的文件
如果存在libexec/hadoop-config.sh文件,则修改该文件,否则,修改bin/hadoop-config.sh
或者在start-all.sh和stop-all.sh中添加
添加:
-
if [[ `whoami` != "hadoop" ]];then
-
echo "use user hadoop to run this scripts "
-
exit
-
fi
4、hadoop的配置文件,有三个相关的配置文件,分别是
core-site.xml
mapred-site.xml
hdfs-site.xml
关于hadoop的配置选项
Hadoop configuration is driven by two types of important configuration files:
-
Read-only default configuration - src/core/core-default.xml, src/hdfs/hdfs-default.xml and src/mapred/mapred-default.xml.
-
Site-specific configuration - conf/core-site.xml, conf/hdfs-site.xml and conf/mapred-site.xml.
除非在conf目录下相应的文件中指定,否则使用src中的配置参数。
添加true,该参数不会被后面所加载的参数所覆盖。
配置文件中也可以使用变量
详见:
注:有些参数必须要加到master上才起作用,而有些必须要加到slaves上才起作用。当然,master和slave可以使用相同的配置文件,但是为了使配置文件清晰,我使用不同的配置文件。
笔记最后添加上我的配置文件。
core-site.xml
-
<configuration>
-
<property>
-
<name>fs.default.name</name>
-
<value>hdfs://hdp-namenode:9000</value>
-
true
-
</property>
-
-
<property>
-
<name>hadoop.tmp.dir</name>
-
<value>/hadoop_data/tmp</value>
-
true
-
</property>
-
-
-
</configuration>
mapred-site.xml
-
<configuration>
-
-
<property>
-
<name>mapred.job.tracker</name>
-
<value>hdp-namenode:9001</value>
-
</property>
-
-
<property>
-
<name>mapred.reduce.tasks</name>
-
<value>12</value>
-
</property>
-
-
<property>
-
<name>mapred.tasktracker.map.tasks.maximum</name>
-
<value>6</value>
-
</property>
-
-
<property>
-
<name>mapred.tasktracker.reduce.tasks.maximum</name>
-
<value>6</value>
-
</property>
-
-
</configuration>
关于
这个参数实际上设置了也不起作用,某个job的map数由所上传的文件所分的块来决定。
reduce.tasks的数目建议是0.95或1.75乘以 (<number. of nodes> * mapred.tasktracker.reduce.tasks.maximum)。
用0.95,所有reduce可以在maps一完成时就立刻启动,开始传输map的输出结果。用1.75,速度快的节点可以在完成第一轮reduce任务后,可以开始第二轮,这样可以得到比较好的负载均衡的效果。
总结:上面的四个参数
mapred.map.tasks、mapred.reduce.tasks是job属性
mapred.tasktracker.map.tasks.maximum、mapred.tasktracker.reduce.tasks.maximum是node属性,用于限制该node可以同时运行的map或reduce的task数量。
经过测试,发现将mapred.tasktracker.map.tasks.maximum设置为节点的cpu cores数目或者数目减1,运行效率较高。
mapred.map.tasks在文件上传时就决定了,分了多少块,就对应多少个map task。
mapred.reduce.tasks 可以通过-D参数修改。
如果在xml里修改,修改以后,提交的job即会使用新的参数。如,修改前为10,修改后为12,则修改后提交的job,reduce的数量就会是12.
-
mapred.tasktracker.map.tasks.maximum、 mapred.tasktracker.reduce.tasks.maximum无法通过-D参数传递。因为这两个参数是作用于datanode(tasktracker)的,而不是作用于job的.
-
"The properties mapred.tasktracker.{map,reduce}.tasks.maximum are node level
parameters, and are read by tasktrackers when they start up. Passing them in
the job confing doesn't do any change ..."
-
详细参考:
可以通过观察Hadoop Map/Reduce Administration页面来分析理解
50030/jobtracker.jsp
补充:关于通过-D参数传递job运行的参数
-D
Use value for given property.
-D参数必须作为第一个参数,有多个参数需要调整时,写多个-D
其中的property是任何可以在core,hdfs,maprd配置文件里写的属性,都可以在这里传递。但是有些参数可能不起作用,例如上面提到的。
-D参数可以广泛用于hadoop的命令中,例如dfs,详细查看:current/commands_manual.html
例如:在上传文件时,指定拷贝的副本
hadoop dfs -D dfs.replication=10 -put 70M logs/2
所以,修改map、reduce的maximum只能通过修改xml,然后重启节点来实现了。
通过修改正在运行的hadoop集群的某个datanode上xml中的make reduce的maximum task数量,修改后:
/usr/local/hadoop/bin/hadoop-daemon.sh stop tasktracker
/usr/local/hadoop/bin/hadoop-daemon.sh start tasktracker
重启tasktracker不影响正在运行的job:
Cluster Restartability
MapReduce
The job tracker restart can recover running jobs if mapred.jobtracker.restart.recover is set true and is enabled. Alsomapred.jobtracker.job.history.block.size value should be set to an optimal value to dump job history to disk as soon as possible, the typical value is 3145728(3MB).
在任何节点上执行stop-mapred.sh或stop-dfs.sh,在任何节点上执行,都会作用于所有节点。因为start-mapred.sh/stop-mapred.sh、start-dfs.sh/stop-dfs.sh等。它们都会参考slaves文件,对slave上的datanode,tasktracker进程进行操作。
hdfs-site.xml
-
<configuration>
-
-
<property>
-
<name>dfs.name.dir</name>
-
<value>/hadoop_data/name</value>
-
</property>
-
-
<property>
-
<name>dfs.data.dir</name>
-
<value>/hadoop_data/data</value>
-
</property>
-
-
<property>
-
<name>dfs.replication</name>
-
<value>1</value>
-
</property>
-
-
<property>
-
<name>dfs.block.size</name>
-
<value>67108864</value>
-
<description>64M per block size</description>
-
</property>
-
-
</configuration>
data目录有多个?用逗号分隔
5、master、slave文件只需要在namenode上存在即可
将名称节点的域名加到/usr/local/hadoop/conf/masters
该文件里应该写得是SecondaryNameNode,而不是JobTracker/NameNode machine。谁是JobTracker/NameNode machine?谁运行start-all.sh谁就是master。当然,也可以把namenode当作SecondaryNameNode
The conf/masters file contains the hostname of the SecondaryNameNode. This should be changed from "localhost" to the fully-qualified domain name of the node to run the SecondaryNameNode service. It does not need to contain the hostname of the JobTracker/NameNode machine; that service is instantiated on whichever node is used to run bin/start-all.sh, regardless of the masters file. The conf/slaves file should contain the hostname of every machine in the cluster which should start TaskTracker and DataNode daemons.
将数据节点的域名加到namemode的/usr/local/hadoop/conf/slaves,每行一个
关于slaves文件,默认情况下,里面写得域名仅仅用于主namenode启动slave时ssh使用。其余地方用不到这几个域名。tasktracker和jobtracker,datanode和namenode之间的heartbeat里面包含的信息都是hostname,而不是slaves文件里所写的域名。
-
Slaves
-
Typically you choose one machine in the cluster to act as the NameNode and one machine as to act as the JobTracker, exclusively. The rest of the machines act as both a DataNode and TaskTracker and are referred to as slaves.
-
-
List all slave hostnames or IP addresses in your conf/slaves file, one per line.
注:关于配置文件
conf/masters (master only)
conf/slaves (master only)
conf/*-site.xml (all machines)
start-mapred.sh/stop-mapred.sh、start-dfs.sh/stop-dfs.sh等。它们都会参考slaves文件,对slave上的datanode,tasktracker进程进行操作。
再次提醒:the machine on which bin/start-all.sh is run will become the primary NameNode.
6、格式化,在namenode操作
namenode上会生成目录/hadoop_data/name。
在重新格式化一个新的分布式文件时,需要将你NameNode上所配置的dfs.name.dir这一namenode用来存放NameNode 持久存储名字空间及事务日志的本地文件系统路径删除,同时将各DataNode上的dfs.data.dir的路径 DataNode 存放块数据的本地文件系统路径的目录也删除。
这是因为Hadoop在格式化一个新的分布式文件系统时,每个存储的名字空间都对应了建立时间的那个版本(可以查看/home/hadoop /NameData/current目录下的VERSION文件,上面记录了版本信息),在重新格式化新的分布式系统文件时,最好先删除NameData 目录。必须删除各DataNode的dfs.data.dir。这样才可以使namedode和datanode记录的信息版本对应。
注意:删除是个很危险的动作,不能确认的情况下不能删除!!做好删除的文件等通通备份!!
格式化完成的提示:
11/05/03 16:58:11 INFO datanode.DataNode: SHUTDOWN_MSG:
/************************************************************
SHUTDOWN_MSG: Shutting down DataNode at centosvm3/192.168.122.31
************************************************************/
特别注意这里的主机名和ip是否正确。
7、启动hadoop集群
在name节点操作
(start-dfs.sh and start-mapred.sh)
日志位于/usr/local/hadoop/logs
查看hdfs存储的状态
11/04/27 19:33:20 INFO security.Groups: Group mapping impl=org.apache.hadoop.security.ShellBasedUnixGroupsMapping; cacheTimeout=300000
11/04/27 19:33:20 WARN conf.Configuration: mapred.task.id is deprecated. Instead, use mapreduce.task.attempt.id
Configured Capacity: 0 (0 KB)
Present Capacity: 0 (0 KB)
DFS Remaining: 0 (0 KB)
DFS Used: 0 (0 KB)
DFS Used%: ?%
Under replicated blocks: 0
Blocks with corrupt replicas: 0
Missing blocks: 0
-------------------------------------------------
Datanodes available: 0 (0 total, 0 dead)
Datanodes available: 0 (0 total, 0 dead)
显示没有可用的数据节点。
登陆到数据节点,查看日志
2011-04-27 19:34:19,066 INFO org.apache.hadoop.ipc.Client: Retrying connect to server: hadoopm/192.168.122.31:9000. Already tried 8
time(s).
原因:检查 iptables。
name节点:
org.apache.hadoop.ipc.RemoteException: java.io.IOException:
File /hadoop_data/tmp/mapred/system/jobtracker.info could only be
replicated to 0 nodes, instead of 1
到data节点查看日志:
STARTUP_MSG: host = java.net.UnknownHostException: chdp2: chdp2
2013-12-25 10:45:47,716 INFO org.apache.hadoop.metrics.MetricsUtil: Unable to obtain hostName
原因:主机名写错了~~
重试
hadoop dfsadmin -report
11/04/27 22:06:51 INFO security.Groups: Group mapping impl=org.apache.hadoop.security.ShellBasedUnixGroupsMapping; cacheTimeout=300000
11/04/27 22:06:51 WARN conf.Configuration: mapred.task.id is deprecated. Instead, use mapreduce.task.attempt.id
Configured Capacity: 39105191936 (36.42 GB)
Present Capacity: 29099364352 (27.1 GB)
DFS Remaining: 29099233280 (27.1 GB)
DFS Used: 131072 (128 KB)
DFS Used%: 0%
Under replicated blocks: 0
Blocks with corrupt replicas: 0
Missing blocks: 0
-------------------------------------------------
Datanodes available: 2 (2 total, 0 dead)
Live datanodes:
Name: 192.168.122.20:50010 (192.168.122.20)
Decommission Status : Normal
Configured Capacity: 19552595968 (18.21 GB)
DFS Used: 65536 (64 KB)
Non DFS Used: 5422440448 (5.05 GB)
DFS Remaining: 14130089984 (13.16 GB)
DFS Used%: 0%
DFS Remaining%: 72.27%
Last contact: Wed Apr 27 22:06:50 CST 2011
Name: 192.168.122.31:50010 (hadoopm)
Decommission Status : Normal
Configured Capacity: 19552595968 (18.21 GB)
DFS Used: 65536 (64 KB)
Non DFS Used: 4583387136 (4.27 GB)
DFS Remaining: 14969143296 (13.94 GB)
DFS Used%: 0%
DFS Remaining%: 76.56%
Last contact: Wed Apr 27 22:06:49 CST 2011
有2个datanode,却显示只有1个?等一等,可能就恢复了,为什么?超时时间? 等了大概6分钟,有时3分钟
试试手动添加:
hadoop datanode hdp-slave1
经测试,在0.21版本当namenode即是namenode也是datanode情况下会出现这个问题,0.20.204未测试过
一些基本操作:
更多查看文档:
创建目录
hadoop dfs -mkdir data
查看目录
hadoop dfs -ls
drwxr-xr-x - haodop supergroup 0 2011-04-27 19:38 /user/hadoop/data
上传文件到
hadoop dfs -put test1G data/
查看w文件内容:
hadoop dfs -cat hadoop/test1234
查看及kill job
hadoop job -list
hadoop job -kill job_201110201517_0001
离开安全模式
hadoop dfsadmin -safemode leave
hadoop dfsadmin --help
-safemode : Safe mode maintenance command.
Safe mode is a Namenode state in which it
1. does not accept changes to the name space (read-only)
2. does not replicate or delete blocks.
Safe mode is entered automatically at Namenode startup, and
leaves safe mode automatically when the configured minimum
percentage of blocks satisfies the minimum replication
condition. Safe mode can also be entered manually, but then
it can only be turned off manually as well.
safemode
在启动时,namenode进入safemode,在这期间,不会发生数据块的复制,namenode从datanode接收heartbeat和blockreport。一个blockreport包含该datanode所host的数据块的列表。每个数据块都有一个最小副本的数量。当namenode检查数据块块包含最小副本数量时,认为该数据块是安全的。当安全数据块的副本的百分比达到所设定的值时,30秒后,namenode离开safemode。如果有数据块的副本数小于最小副本数,namenode开始创建该数据块的副本。
web显示的状态信息
/usr/java/jdk1.6.0_22/bin/jps
一个很好的命令jps很好用,这是java1.5之后的版本的才用的,用来查看java虚拟机里面在跑着那些程序。比如使用bin/start-all.sh运行了hadoop后使用jps命令检查一下是不是所有的node和tracker都起来了。
namenode配置文件
core-site.xml
-
<property>
-
<name>fs.default.name</name>
-
<value>hdfs://hdp-namenode:9000</value>
-
</property>
-
-
<property>
-
<name>hadoop.tmp.dir</name>
-
<value>/hadoop_data/tmp</value>
-
</property>
hdfs-site.xml
-
<property>
-
<name>dfs.name.dir</name>
-
<value>/hadoop_data/name</value>
-
</property>
-
-
<property>
-
<name>dfs.data.dir</name>
-
<value>/hadoop_data/data</value>
-
</property>
-
-
<property>
-
<name>dfs.hosts</name>
-
<value>/usr/local/hadoop/conf/datanode-allow-list</value>
-
</property>
-
-
<property>
-
<name>dfs.hosts.exclude</name>
-
<value>/usr/local/hadoop/conf/datanode-deny-list</value>
-
</property>
-
-
<property>
-
<name>dfs.block.size</name>
-
-
-
134217728
-
<description>128M per block size</description>
-
</property>
-
<property>
-
<name>dfs.balance.bandwidthPerSec</name>
-
<value>104857600</value>
-
</property>
mapred-site.xml
-
<property>
-
<name>mapred.job.tracker</name>
-
<value>hdp-namenode:9001</value>
-
</property>
-
-
<property>
-
<name>mapred.hosts</name>
-
<value>/usr/local/hadoop/conf/node-allow-list</value>
-
</property>
-
-
<property>
-
<name>mapred.hosts.exclude</name>
-
<value>/usr/local/hadoop/conf/node-deny-list</value>
-
</property>
-
-
<property>
-
<name>mapred.reduce.tasks</name>
-
<value>10</value>
-
</property>
-
-
<property>
-
<name>mapred.jobtracker.restart.recover</name>
-
<value>true</value>
-
</property>
-
-
<property>
-
<name>mapred.child.java.opts</name>
-
<value>-Xmx512m</value>
-
</property>
mapred.reduce.child.java.opts
-Xmx512m
-
-
<property>
-
<name>mapred.compress.map.output</name>
-
<value>true</value>
-
</property>
-
-
<property>
-
<name>mapred.child.env</name>
-
<value>JAVA_LIBRARY_PATH=/usr/local/hadoop/lib/native/Linux-amd64-64</value>
-
</property>
datanode/tasktracker配置文件
core-site.xml
-
<property>
-
<name>fs.default.name</name>
-
<value>hdfs://hdp-namenode:9000</value>
-
</property>
-
-
<property>
-
<name>hadoop.tmp.dir</name>
-
<value>/hadoop_data/tmp</value>
-
</property>
-
hdfs-site.xml
-
<property>
-
<name>dfs.name.dir</name>
-
<value>/hadoop_data/name</value>
-
</property>
-
-
<property>
-
<name>dfs.data.dir</name>
-
<value>/hadoop_data/data</value>
-
</property>
-
<property>
-
<name>dfs.replication</name>
-
<value>2</value>
-
</property>
dfs.datanode.du.reserved
1073741824
Reserved 1GB space in bytes per volume
mapred-site.xml
-
<property>
-
<name>mapred.job.tracker</name>
-
<value>hdp-namenode:9001</value>
-
</property>
-
-
<property>
-
<name>slave.host.name</name>
-
<value>hdp-datanode145</value>
-
</property>
-
-
<property>
-
<name>mapred.tasktracker.map.tasks.maximum</name>
-
<value>6</value>
-
</property>
-
-
<property>
-
<name>mapred.tasktracker.reduce.tasks.maximum</name>
-
<value>6</value>
-
</property>
-
-
<property>
-
<name>mapred.child.java.opts</name>
-
<value>-Xmx512m</value>
-
</property>
mapred.reduce.child.java.opts
-Xmx512m
io.sort.mb
200
true
io.sort.factor
20
true
-
-
<property>
-
<name>mapred.compress.map.output</name>
-
<value>true</value>
-
</property>
-
-
<property>
-
<name>mapred.child.env</name>
-
<value>JAVA_LIBRARY_PATH=/usr/local/hadoop/lib/native/Linux-amd64-64</value>
-
</property>
-
-
<property>
-
<name>mapred.reduce.parallel.copies</name>
-
<value>20</value>
-
</property>
之所以为io.sort.mb添加true是因为我修改该值后,运行job,登陆tasktracker,查看相应的map的syslog,总是恢复为默认值100,所以,添加了final
syslog:
/usr/local/hadoop/logs/userlogs/job_201111041104_0001/attempt_201111041104_0001_m_000006_0
数据文件单独存放在一个磁盘分区?
默认的方式下linux会把文件访问的时间atime做记录,这在绝大部分的场合都是没有必要的
Make sure to mount the partition used for data storage in each
cluster node with "noatime" option. With noatime, read access to a file
will no longer result in an update to the atime information associated
with the file. For example, /etc/fstab in each cluster node can have:
/dev/sdb1 ext4 noatime 1 1