一、 Hadoop节点热拔插

二、 数据负载均衡

三、Namenode恢复

四、安全模式

五、web查看hdfs

六、HDFS基本操作

七、hadoop性能优化

八、Apache Hadoop最佳实践和反模式

九、小文件解决思路

十、Hadoop部署

 

一、 Hadoop节点热拔插

在Hadoop集群中经常会进行增添节点操作,即实现节点的热拔插。在这些操作中不希望对集群进行重启。

1.在集群中添加节点:

a. 把新节点IP或者主机名字加入到主节点的slaves文件。

b. 登录到新节点,执行:

cd $HADOOP_HOME &&

bin/hadoop-daemon.sh start datanode

bin/hadoop-daemon.sh start tasktracker

2. 从集群中移走节点,且对移走节点的数据进行备份:

a. 在主节点的core-site.xml配置文件中添加

dfs.hosts.exclude

excludes

b. 在主节点的$HADOOP_HOME目录下新建文件excludes,每行为需要移走的节点。

c. 运行命令:hadoop dfsadmin -refreshNodes,该命令可以动态刷新dfs.hosts和dfs.hosts.exclude配置,无需重启NameNode。此刻datanode消失了,但是tasktracker还存在。

d. 然后通过 bin/hadoop dfsadmin -report查看e. 在停掉节点Decommission Status不为Normal前, mapreduce操作会出现异常。

f. 节点移走64G数据需要十分钟左右。

二、 数据负载均衡

1. 在Hadoop集群中新添加一个Datanode时,需要对集群数据进行负载均衡。

2. 在主节点运行bin/start-balancer.sh命令,可以添加参数-threshold 5,threshold是平衡阈值,默认是10%,值越小负载越均衡,但需要更长的时间去执行 。

3.

在使用start-balancer.sh时,默认使用1M/S(1048576)的速度移动数据(so slowly...)

修改hdfs-site.xml配置,这里我们使用的是20m/S

<property>
<name>dfs.balance.bandwidthPerSec</name>
<value>20971520</value>
<description> Specifies the maximum bandwidth that each datanode can utilize for the balancing purpose in term of the number of bytes per second. </description>
</property>

然后结果是导致job运行变得不稳定,出现一些意外的长map单元,某些reduce时间处理变长(整个集群负载满满的情况下,外加20m/s的balance),据说淘宝的为10m/s,需要调整后实验,看看情况如何。

hadoop balancer -threshold 5
三、Namenode恢复
1.修改conf/core-site.xml,增加
         <property>
         <name>fs.checkpoint.period</name>
         <value>3600</value>
         <description>The number of seconds between two periodic checkpoints. </description>
         </property>
 
         <property>
         <name>fs.checkpoint.size</name>
         <value>67108864</value>
         <description>The size of the current edit log (in bytes) that triggers a periodic checkpoint even if the fs.checkpoint.period hasn't expired. </description>
         </property>
 
         <property>
         <name>fs.checkpoint.dir</name>
         <value>/data/work/hdfs/namesecondary</value>
         <description>Determines where on the local filesystem the DFS secondary name node should store the temporary images to merge. If this is a comma-delimited list of directories then the image is replicated in all of the directories for redundancy. </description>
         </property>

 

fs.checkpoint.period表示多长时间记录一次hdfs的镜像。默认是1小时。

fs.checkpoint.size表示一次记录多大的size,默认64M

2.修改conf/hdfs-site.xml,增加

     

<property>
         <name>dfs.http.address</name>
         <value>master:50070</value>
         <description> The address and the base port where the dfs namenode web ui will listen on. If the port is 0 then the server will start on a free port. </description>
         </property>

0.0.0.0改为namenode的IP地址

3.重启hadoop,然后检查是否启动是否成功。

登录secondarynamenode所在的机器,输入jps查看secondarynamenode进程

进入secondarynamenode的目录/data/work/hdfs/namesecondary

正确的结果:

如果没有,请耐心等待,只有到了设置的checkpoint的时间或者大小,才会生成。

4.恢复

制造namenode宕机的情况

1) kill 掉namenode的进程

         [root@master name]# jps

         11749 NameNode

         12339 Jps

         11905 JobTracker

         [root@master name]# kill 11749

2)删除dfs.name.dir所指向的文件夹,这里是/data/work/hdfs/name

         [root@master name]# rm -rf *

删除name目录下的所有内容,但是必须保证name这个目录是存在的

3)从secondarynamenode远程拷贝namesecondary文件到namenode的namesecondary

         [root@master hdfs]# scp -r slave-001:/data/work/hdfs/namesecondary/ ./

4)启动namenode

         [root@master /data]# hadoop namenode –importCheckpoint

正常启动以后,屏幕上会显示很多log,这个时候namenode就可以正常访问了

5)检查

使用hadoop fsck /user命令检查文件Block的完整性

6)停止namenode,使用crrl+C或者会话结束

7)删除namesecondary目录下的文件(保存干净)

         [root@master namesecondary]# rm -rf *

8)正式启动namenode

         [root@master bin]# ./hadoop-daemon.sh start namenode

恢复工作完成,检查hdfs的数据

四、安全模式

NameNode在启动的时候首先进入安全模式,如果datanode丢失的block达到一定的比例(1-dfs.safemode.threshold.pct),则系统会一直处于安全模式状态即只读状态。

dfs.safemode.threshold.pct(缺省值0.999f)表示HDFS启动的时候,如果DataNode上报的block个数达到了元数据记录的block个数的0.999倍才可以离开安全模式,否则一直是这种只读模式。如果设为1则HDFS永远是处于SafeMode。

 

 

有两个方法离开这种安全模式:

1)     修改dfs.safemode.threshold.pct为一个比较小的值,缺省是0.999。

dfs.safemode.threshold.pct(缺省值0.999f)

HDFS启动的时候,如果DataNode上报的block个数达到了元数据记录的block个数的0.999倍才可以离开安全模式,否则一直是这种只读模式。如果设为1则HDFS永远是处于SafeMode。

2)     hadoop dfsadmin -safemode leave命令强制离开

dfsadmin -safemode value 参数value的说明:

enter - 进入安全模式

leave - 强制NameNode离开安全模式

get - 返回安全模式是否开启的信息

wait - 等待,一直到安全模式结束。

 

五、web查看hdfs

HDFS启动后,可以通过WEB界面来查看,缺省端口为50070,比如

http://master:50070/

即可查看整个HDFS的状态以及使用统计。

对于Mapreduce的WEB界面,缺省端口是50030

六、HDFS基本操作

启动HDFS服务

在/data/hadoop/install/bin下有很多命令,

* start-all.sh 启动所有的Hadoop守护,包括namenode, datanode,jobtracker,tasktrack,secondarynamenode。

* stop-all.sh 停止所有的Hadoop。

* start-mapred.sh 启动Map/Reduce守护,包括Jobtracker和Tasktrack。

* stop-mapred.sh 停止Map/Reduce守护

* start-dfs.sh 启动Hadoop DFS守护,Namenode和Datanode。

* stop-dfs.sh 停止DFS守护

七、hadoop性能优化

Hadoop机架感知实现及配置:分布式的集群通常包含非常多的机器,由于受到机架槽位和交换机网口的限制,通常大型的分布式集群都会跨好几个机架,由多个机架上的机器共同组成一个分布式集群。机架内的机器之间的网络速度通常都会高于跨机架机器之间的网络速度,并且机架之间机器的网络通信通常受到上层交换机间网络带宽的限制。

具体到Hadoop集群,由于Hadoop的HDFS对数据文件的分布式存放是按照分块block存储,每个block会有多个副本(默认为3),并且为了数据的安全和高效,所以Hadoop默认对3个副本的存放策略为:

     在本地机器的hdfs目录下存储一个block

     在另外一个rack的某个datanode上存储一个block

     在该机器的同一个rack下的某台机器上存储最后一个block

这样的策略可以保证对该block所属文件的访问能够优先在本rack下找到,如果整个rack发生了异常,也可以在另外的rack上找到该block的副本。这样足够的高效,并且同时做到了数据的容错。

但是,Hadoop对机架的感知并非是自适应的,亦即,Hadoop集群分辨某台slave机器是属于哪个rack并非是只能的感知的,而是需要Hadoop的管理者人为的告知Hadoop哪台机器属于哪个rack,这样在Hadoop的namenode启动初始化时,会将这些机器与rack的对应信息保存在内存中,用来作为对接下来所有的HDFS的写块操作分配datanode列表时(比如3个block对应三台datanode)的选择datanode策略,做到Hadoop allocate block的策略:尽量将三个副本分布到不同的rack。

接下来的问题就是:通过什么方式能够告知Hadoop namenode哪些slaves机器属于哪个rack?以下是配置步骤。

默认情况下,Hadoop的机架感知是没有被启用的。所以,在通常情况下,Hadoop集群的HDFS在选机器的时候,是随机选择的,也就是说,很有可能在写数据时,Hadoop将第一块数据block1写到了rack1上,然后随机的选择下将block2写入到了rack2下,此时两个rack之间产生了数据传输的流量,再接下来,在随机的情况下,又将block3重新又写回了rack1,此时,两个rack之间又产生了一次数据流量。在job处理的数据量非常的大,或者往Hadoop推送的数据量非常大的时候,这种情况会造成rack之间的网络流量成倍的上升,成为性能的瓶颈,进而影响作业的性能以至于整个集群的服务。

要将Hadoop机架感知的功能启用,配置非常简单,在namenode所在机器的Hadoop-site.xml配置文件中配置一个选项:

topology.script.file.name

/path/to/script

这个配置选项的value指定为一个可执行程序,通常为一个脚本,该脚本接受一个参数,输出一个值。接受的参数通常为某台datanode机器的ip地址,而输出的值通常为该ip地址对应的datanode所在的rack,例如”/rack1”。Namenode启动时,会判断该配置选项是否为空,如果非空,则表示已经用机架感知的配置,此时namenode会根据配置寻找该脚本,并在接收到每一个datanode的heartbeat时,将该datanode的ip地址作为参数传给该脚本运行,并将得到的输出作为该datanode所属的机架,保存到内存的一个map中。

至于脚本的编写,就需要将真实的网络拓朴和机架信息了解清楚后,通过该脚本能够将机器的ip地址正确的映射到相应的机架上去。一个简单的实现如下:

#!/usr/bin/perl -w
use strict;
my $ip = $ARGV[0];
my $rack_num = 3;
my @ip_items = split /\./, $ip;
my $ip_count = 0;
foreach my $i (@ip_items) {
$ip_count += $i;
}
my $rack = "/rack".($ip_count % $rack_num);
print "$rack";

 

写入数据

当没有配置机架信息时,所有的机器Hadoop都默认在同一个默认的机架下,名为 “/default-rack”,这种情况下,任何一台datanode机器,不管物理上是否属于同一个机架,都会被认为是在同一个机架下,此时,就很容易出现之前提到的增添机架间网络负载的情况。例如,对没有机架信息的Hadoop HDFS启动instance上传一个文件,其block信息如下:

在没有机架信息的情况下,namenode默认将所有的slaves机器全部默认为在/default-rack下,根据Hadoop代码的分析也能知道哦啊,此时在写block时,三个datanode机器的选择完全是随机的。

而当配置了机架感知信息以后,Hadoop在选择三个datanode时,就会进行相应的判断:

1.如果上传本机不是一个datanode,而是一个客户端,那么就从所有slave机器中随机选择一台datanode作为第一个块的写入机器(datanode1)。

而此时如果上传机器本身就是一个datanode(例如mapreduce作业中task通过DFSClient向hdfs写入数据的时候),那么就将该datanode本身作为第一个块写入机器(datanode1)。

2.随后在datanode1所属的机架以外的另外的机架上,随机的选择一台,作为第二个block的写入datanode机器(datanode2)。

3.在写第三个block前,先判断是否前两个datanode是否是在同一个机架上,如果是在同一个机架,那么就尝试在另外一个机架上选择第三个datanode作为写入机器(datanode3)。而如果datanode1和datanode2没有在同一个机架上,则在datanode2所在的机架上选择一台datanode作为datanode3。

4.得到3个datanode的列表以后,从namenode返回该列表到DFSClient之前,会在namenode端首先根据该写入客户端跟datanode列表中每个datanode之间的“距离”由近到远进行一个排序。如果此时DFS写入端不是datanode,则选择datanode列表中的第一个排在第一位。客户端根据这个顺序有近到远的进行数据块的写入。在此,判断两个datanode之间“距离”的算法就比较关键,Hadoop目前实现如下,以两个表示datanode的对象DatanodeInfo(node1,node2)为例:

a)首先根据node1和node2对象分别得出两个datanode在整个hdfs集群中所处的层次。这里的层次概念需要解释一下:每个datanode在hdfs集群中所处的层次结构字符串是这样描述的,假设hdfs的拓扑结构如下:

每个datanode都会对应自己在集群中的位置和层次,如node1的位置信息为“/rack1/datanode1”,那么它所处的层次就为2,其余类推。

b)得到两个node的层次后,会沿着每个node所处的拓朴树中的位置向上查找,如“/rack1/datanode1”的上一级就是“/rack1”,此时两个节点之间的距离加1,两个node分别同上向上查找,直到找到共同的祖先节点位置,此时所得的距离数就用来代表两个节点之间的距离。所以,如上图所示,node1和node2之间的距离就为4.

5.当根据“距离”排好序的datanode节点列表返回给DFSClient以后,DFSClient便会创建Block OutputStream,并想这次block写入pipeline中的第一个节点(最近的节点)开始写入block数据。

6.写完第一个block以后,依次按照datanode列表中的次远的node进行写入,直到最后一个block写入成功,DFSClient返回成功,该block写入操作结束。

通过以上策略,namenode在选择数据块的写入datanode列表时,就充分考虑到了将block副本分散在不同机架下,并同时尽量的避免了之前描述的网络多于开销。

对配置了机架信息的Hadoop HDFS启动instance上传一个文件,其block信息如下:

在配置了机架信息的情况下,为了减少机架间的网络流量,namenode会将其中两个副本写在同一个机架上,并且为了尽量做到容错,会将第三个block写道另一个机架上的datanode上。

 

八、Apache Hadoop最佳实践和反模式

Apache Hadoop是一个用于构建大规模,共享存储和计算基础设施的软件框架,Hadoop集群经常用于各种研究和开发项目,如Yahoo!,eBay,Facebook,Twitter等互联网公司就大量使用了Hadoop,并在核心业务系统中扮演中关键角色,因此正确部署Hadoop集群是确保获得最佳投资回报的关键。

本文介绍了在Apache Hadoop上运行应用程序的最佳实践,实际上,我们引入了网格模式(Grid Pattern)的概念,它和设计模式类似,它代表运行在网格(Grid)上的应用程序的可复用解决方案。

概述

Hadoop上的应用程序数据是使用Map-Reduce(映射-化简)范式写入的,Map-Reduce作业通常要将输入数据集拆分成独立的数据块,由Map任务以完全并行的方式处理,框架对Map的输出结果排序,然后传递给Reduce任务,通常情况下,作业的输入和输出结果都保存在文件系统上,框架管理计划任务,监控它们的执行情况,以及重新执行失败的任务。

Map-Reduce应用程序指定输入/输出位置,通过实现适当的Hadoop接口,如Mapper和Reducer,分别提供Map和Reduce功能,它们和其它作业参数一起构成作业配置。Hadoop作业客户端将作业(jar/可执行文件等)和配置提交给JobTracker,JobTracker承担起分配软件/配置,调度任务和监控的职责,为作业客户端提供状态和诊断信息。

Map/Reduce框架工作在(键/值)对上,也就是说,框架将给作业的输入看作是一对,并产生一对作为作业的输出,当然输入输出的类型可能是不同的。

绝大多数Map-Reduce应用程序都在网格上执行,不会直接实现低级的Map-Reduce接口,相反,它们使用高级语言,如Pig实现。

Oozie是网格上完美的工作流管理和调度解决方案,它支持多种接口(Hadoop Map-Reduce,Pig,Hadoop Streaming和Hadoop Pipes等),并可以根据时间或数据可用性实现应用程序的调度。

网格模式

这部分内容涉及在网格上运行Map-Reduce应用程序的最佳实践。

输入

Hadoop Map-Reduce专门为处理大批量数据做了优化,Map通常使用并行方式处理数据,至少1个HDFS数据块,也就是说每次最少要处理128MB的数据。

◆默认情况下,这个框架每个Map至少要处理1个HDFS文件,这意味着如果某个应用程序要处理非常大的输入文件,最好是通过一种特殊的输入格式,如MultiFileInputFormat,让每个Map处理多个文件,即便是在处理为数不多的小型输入文件时也理应如此,每个Map处理多个文件可以大大提高效率。

◆如果应用程序需要处理大量的数据,即使它们存在于大型文件中,每个Map处理超过128MB的数据也会更快。

网格模式:在少量Map中聚合处理多个小型输入文件,使用更大的HDFS块大小处理超大型数据集。

Map(映射)

Map的数量通常是由输入的总大小决定的,即所有输入文件的总数据块数,因此,如果你要处理10TB输入数据,块大小128MB,那么总共需要82000个Map。

任务设置需要一段时间,因此执行大型作业时,Map至少需要一分钟。正如前面提到的,让每个Map同时处理多个文件效率会更高,因此,如果应用程序要处理超大型输入文件,让每个Map处理更大的数据块更有效,例如,让每个Map处理更多数据的一个方法是让应用程序处理更大的HDFS数据块,如512MB或尽可能更大。

作为一个极端的例子,Map-Reduce开发团队使用大约66000个Map完成了PB级数据的排序(PetaSort),也就是说,66000个Map处理了1PB数据(每个Map负责12.5GB)。但太多的Map在很短的时间内同时运行很容易造成反效果。

九、小文件解决思路

1.Hadoop自带的解决方案

对于小文件问题,Hadoop本身也提供了几个解决方案,分别为:Hadoop Archive,Sequence file和CombineFileInputFormat。

(1) Hadoop Archive

Hadoop Archive或者HAR,是一个高效地将小文件放入HDFS块中的文件存档工具,它能够将多个小文件打包成一个HAR文件,这样在减少namenode内存使用的同时,仍然允许对文件进行透明的访问。

对某个目录/foo/bar下的所有小文件存档成/outputdir/ zoo.har:

hadoop archive -archiveName zoo.har -p /foo/bar /outputdir

当然,也可以指定HAR的大小(使用-Dhar.block.size)。

HAR是在Hadoop file system之上的一个文件系统,因此所有fs shell命令对HAR文件均可用,只不过是文件路径格式不一样,HAR的访问路径可以是以下两种格式:

har://scheme-hostname:port/archivepath/fileinarchive
har:///archivepath/fileinarchive(本节点)
可以这样查看HAR文件存档中的文件:
hadoop dfs -ls har:///user/zoo/foo.har
输出:
har:///user/zoo/foo.har/hadoop/dir1
har:///user/zoo/foo.har/hadoop/dir2

使用HAR时需要两点,第一,对小文件进行存档后,原文件并不会自动被删除,需要用户自己删除;第二,创建HAR文件的过程实际上是在运行一个mapreduce作业,因而需要有一个hadoop集群运行此命令。

此外,HAR还有一些缺陷:第一,一旦创建,Archives便不可改变。要增加或移除里面的文件,必须重新创建归档文件。第二,要归档的文件名中不能有空格,否则会抛出异常,可以将空格用其他符号替换(使用-Dhar.space.replacement.enable=true 和-Dhar.space.replacement参数)。

(2) Sequence file

sequence file由一系列的二进制key/value组成,如果为key小文件名,value为文件内容,则可以将大批小文件合并成一个大文件。

Hadoop-0.21.0中提供了SequenceFile,包括Writer,Reader和SequenceFileSorter类进行写,读和排序操作。如果hadoop版本低于0.21.0的版本,实现方法可参见[3]。

(3)CombineFileInputFormat

CombineFileInputFormat是一种新的inputformat,用于将多个文件合并成一个单独的split,另外,它会考虑数据的存储位置。

2.小文件处理模块

实际上思路类似:在原有HDFS基础上添加一个小文件处理模块,当一个文件到达时,判断该文件是否属于小文件,如果是,则交给小文件处理模块处理,否则,交给通用文件处理模块处理。小文件处理模块的设计思想是,先将很多小文件合并成一个大文件,然后为这些小文件建立索引,以便进行快速存取和访问。

 HADOOP部署

单节点集群部署:

http://www.michael-noll.com/tutorials/running-hadoop-on-ubuntu-linux-single-node-cluster/

多节点集群部署:

http://www.michael-noll.com/tutorials/running-hadoop-on-ubuntu-linux-multi-node-cluster/

集群更新:

http://www.michael-noll.com/blog/2011/08/23/performing-an-hdfs-upgrade-of-an-hadoop-cluster/