Hadoop入门学习笔记之一

http://hadoop.apache.org/docs/r1.2.1/api/index.html

适当的利用 null 在map中可以实现对文件的简单处理,如排序,和分集合输出等。

需要关心的内容

一个节点面对的是一个Map任务,一个Map任务面对的是一个split文件,一个map方法面对的是一个split文件生成的键值对。

mapper类中map方法的输入是InputFormat的ReadeRecord类读取到的键值对

学习一周之后问题总结:

1.实验时使用的文件过小,大量小文件问题,需要通过处理,最终形成sequencefile进行处理。

2.在设置sequenceFileOutputFormat.class时,设置setOutputKeyClass() setOutoutvalueClass(),中的数据类型时,有问题,

3.sequenceFile相关的 recordreader不知道应该怎么使用,总是会有错。

4.在未设置reduce过程时,系统默认的是将key value都作为text进行输出。

5.文件划分split的大小还不会设置

6.文件划分,record读写的自定义函数还不会重载

7.输入文件夹和输出文件的路径,以及在不同运行环境中,指的是hdfs中的位置还是pc中的路径,还不太明白,在eclipse中虚拟云中不带hdfs://的是本地路径,在真正的云环境中运行则都代表hdfs中的路径

8.构建较大的数据集,如果采用程序将大量的小文件合并成云上的 序列文件,时间非常长,如果将构建好的序列文件下载到本地,下次可以直接将该文件上传至云端,速度较快。

9.在大数据集是(分块64M)没有真正的分布在各个子节点中运行,是应为在eclipse环境中默认是使用的虚拟云。需要在代码中进行相关的配置,从而真正的运行到云端。

10.运行过程中class not found 、jar not found、500030端口中查看job运行为none登等情况的处理~

http://os.51cto.com/art/201305/392965.htm

如果程序中使用了系统的动态链接库.so文件,执行作业之前一定要首先确保每台节点上的执行环境已经配置好,特别是节点中有64位和32位的机器时,

首先将自己的自定义库代码针对不同的平台进行编译。(特别是在使用了JNI的情况下),否则最终的分配给节点 的任务还是执行失败。

编译打包:

引用的外部包路径+java源码路径+class输出路径

(将.java文件编译成.class文件, 将.class文件打包成.jar文件,jar文件的名字可以随便起)

$ javac -classpath /home/sunny/usr/hadoop-1.2.1/hadoop-core-1.2.1.jar:/home/sunny/usr/hadoop-1.2.1/lib/commons-cli-1.2.jar -d ./classes ./src/test/example/Facelib.java ./src/newMatching/*.java
$ jar -cvf newMatching.jar -C ./classes/ .

放到云端执行:

jar包+主类的包名.主类名

[email protected]:~/usr/hadoop-1.2.1/bin$ ./hadoop jar /home/sunny/workspace/eclipse/newMatching/newMatching.jar newMatching.MatchDoer

在分布式计算的时候,datanode节点需要从hdfs文件系统上将Job的jar文件下载到本地磁盘进行本地计算,所以需要在终端中提交任务的时候将jar包提交上去。

在eclipse中Run on hadoop 是在eclipse的虚拟云上进行执行的,没有生成jar文件。

在分布式执行的过程中可能遇到的问题:

1. class not found, job代码中添加job.setJarByClass(xxx.class);(xxx是自己的主类)

2. native lib  .so not found, 如果使用了系统中的动态链接库,则需要保证每台及节点系统中已经配安装了相应的库文件,特别是在使用了JNI的情况下。

3.在eclipse中直接点击Run on Hadoop,默认使用的是本地文件系统,LocalFileSystem, 如果文件路径前没有显示的加上hdfs://master:9000/所处理的

就是本地磁盘路径。如果在代码中添加:

conf.set("fs.default.name", "hdfs://master:9000/");  //在你的文件地址前自动添加:hdfs://master:9000/
conf.set("hadoop.job.user","yourname");
conf.set("mapred.job.tracker","master:9001");  

这样文件路径默认的就是HDFS分布式文件系统上的了。

综上:

1.eclipse中的hadoop就是在本地运行的java程序,(文件存储在本地磁盘,没有jobTrack进行作业调度,程序顺序执行);

2.加上conf.set之后文件系统使用的是hdfs,但依然没有jobTracker,进行map的节点只有本机一个,程序顺序执行;

3.通过终端命令进行job申请和提交才会触发jobtracker进行真正的分布式计算。

>>开发过程:

1.在eclipse中coding;

2.在eclipse中运行通过;                (Run on Hadoop)

3.将eclipse生成的bin目录下的class文件打包成.jar文件;(jar -cvf yourname.jar  -C ./bin  .)

4.在命令行中提交作业,进行分布式执行;       (./hadoop jar  yourname.jar packename.classname args1 args2)

其中1~3步骤是编程调试阶段,第4步是真正运行阶段。  ^.^

 

master独自运行job        分布式运行

另一种方案:

在代码中添加: conf.set("mapred.job.tracker", "master:9000");

之后eclipse中的Run on hadoop 就会在云端执行(而不是仅仅在当前节点上map),但是其他节点会class not found异常(不知道是应为jar没找到还是主类没找到);

在eclipse工程上右键java build path->add external jar 上选中自己用jar -cvf生成的jar包,然后执行run on hadoop就可以分布式执行了。

使用这种方法之后,每次修改了程序后要先生成jar,然后在在eclipse中run on hadoop

(不知道对不对, java程序都是执行在vm上的, 不需要知道hadoop的安装路径,执行job相关的 程序就可以提交作业;jar是给别的节点用的,java程序是给自己执行的,

直接执行java程序仅仅是默认没有读取hadoop的配置文件,所以需要在程序中明确的指明hdfs和jobtracker)

在eclipse中开发,hadoop的配置文件什么时候生效,很困惑,直接在eclipse中点击Run运行,hadoop的conf下配置文件的有些选项不生效。

要在代码里conf.set("name",value);,但是单机模式时conf.set("mapred.child.java.opts","-Xss1m");也不生效,必须在RunConfigurations中配置VM变量。

从源码中可以看到,hadoop jar xxx.jar xxx ,hadoop脚本对参数jar的处理时调用RunJar类,该类的源码在src/core/org/apache/hadoop/util下,

其中的main函数(args, jar, manifest, unjar, runtime)

以上费劲周折使程序运行在真正的分步式化境中,但是这是又会有新的问题出现:

1.在程序中使用本地磁盘的路径:LocalFileSystem,或者对于FileInputStream这样的java API默认使用的就是本地地址,也可以使用LocalFileSystem

2.程序中的调试信息输出问题:eclipse中的虚拟环境为单机运行,所以程序执行起来与普通java程序类似,所有打印信息都在eclipse的console中输出,

当成许运行在分布式环境中时, main中的system.out,system.err等调试信息会在提交作业的终端中显示,但是mapper和reducer中的调试信息则不会显示到终端中,

查看他们的调试信息只能到web上的500030的JobTracker中找到相应的map task的log信息中查看。

参考:http://blog.csdn.net/azhao_dn/article/details/8003998

3.程序的修改,更改之后要先重新生成jar,才能是修改生效。

4. 在分布式环境中程序不仅仅运行在本节点上,所以一定要保证程序所需的 数据、链接库等在各个节点上都具备

从以上几点来看,在开发阶段使用eclipse的虚拟云可以大大提高开发和调试的效率。

分布式的节点在启动hadoop服务之后,会读取本节点中hadoop安装文件夹中conf下的配置文件,hdfs-site.xml下配置的相关

真正的分布式环境配置成功之后,如果启动了hdfs服务之后,有些datanode没有启动,则应该检查各个节点hadoop的配置文件是否相同。

(待思考的问题:各个分布式节点用户名要相同, hadoop安装目录要相同,hadoop配置文件要相同, java路径随便)

也可以尝试将各个节点/tmp/hadoop相关目录删除,yourhadooppath/logs/内容目录删除,重新namenode  -format

跟namenode、jobtracker相关的配置选项只对master节点有作用,其他hdfs相关配置会对每个节点起作用。

配置文件、log文件、tmp临时文件对hadoop 各节点的正常运行还是很重要的。

hadoop中配置文件的相关选项还是不太了解。。 。。。 。

有时候4个节点都正常启动了,但是stop-all.sh之后再启动,关机某些节点在开启之后,启动服务,往往是最后启动的机器能够启动

dfs节点,这种开关机不同步导致的datanode节点不能正常完全启动的问题,。。。。全部重启,namenode -format,

集群节点较多的时候并不是mapper过程完全结束之后才开始reduce,很能在mapper完成大半后就开始reduce了。

setNumOfReduce之后,去掉了reduce过程,最终的输出结果是未经排序的!

有几个mapper就会将几个mapper的结果输出到最后的几个文件中part-m-0000

reduce的执行节点根据具体的执行状况分配给某节点进行,并不固定。

如果上传分块过小(<64M),则系统不再自动分块,也不会自动合并,按照上传分块为单位分配给mapper处理。

编写程序时的注意:

在反复遍历生成文件时,由于数据量很大,所以在循环内外的变量分配很重要, 不然内存会溢出。

打开的文件流,使用完之后一定要记得关闭。

定义的变量,在使用之前一定记得new 否则会产生null pointer的异常。

如果在mapper或者reducer中设置了全局变量,而在使用中这些变量又与初始值相关(如直接|、&、^,++等),则需要注意在一个单元使用完成之后进行

初始化,特别是reduce中对应的是key+list链表,一个key的所有value处理完成之后需要对全局变量进行初始化,为下一个key的处理做准备!

hadoop的运行效率不仅仅与节点的个数有关,job中的任务执行,文件的读写,数据量的划分,网路传输,精简不必要的工作

每个代码块的执行效率有关。

配置最大map和reduce并行task数量:

mapred-site.xml 配置:mapred.tasktracker.map.tasks.maximum和mapred.tasktracker.reduce.tasks.maximum, 默认都是2.

要求reduce<map, 这样可以留有一些备用节点,提高故障时作业的恢复时间,如果reduce>map,那么空余的reduce没有文件输入但是还是会

启动task生成空文件,浪费了系统资源和效率。

将大量的较小的中间键值对合并成较少的较大的中间键值对, 以减少网络中的流量(for reduce),在大数据处理时优势会显现的非常明显,可以通过web界面

查看各个过程处理的键值对数量。

mapreduce框架:

inputformat(文件分割+键值对生成)      map    排序     combine(相同key的value累加)      partitioner(hash映射分组)

排序+相同key构成value-list     reduce(生成键值对)   outputformat(写回HDFS)

过程中的系统默认:

TextInputFormat:将输入文件作为文本文件处理, 生成行行文本的键值对

IdentityMapper:将输入的键值对 原封不动的 输出

Combiner:null , 不进行中间结果的合并

Partitioner: HashPartitioner, 用hash进行分组

IdentityReducer: 将输入的中间结果键值对直接输出键值对

TextOutputFormat:将最终键值对结果生成文本文件, 每行一个<key, value>对, key 和 value之间用tab分隔。

---

setOutputKeyClass, setOutputValueClass来设置最终的key、value的类型 (?),setMapOutputKeyClass, 默认情况下和最终结果的键值对类型相同。

键值对 的类型对如何解析、理解和处理数据时有影响的。

combiner在编程时就等同于reduce,只有类的名称不同,(可能combiner的输入也是经过中间的排序和累加之后)

没有combine后,reduce接收到的就不再是<key,list<value>>的形式了。

综上: mapred默认框架是将输入文本文件按行解析, 排序, 最后按照<key, value>每行的形式输出到文本文件中。

其key的默认类型时Longwritabel, value的默认类型是Text,Long可以转化输出到文本中,显示的还是long数据的值。

当数据量很大时, 在reduce函数中进行本地排序往往不可行,算法对于不同大小的数据集不通用

通用框架的自定义: 根据输入的键值对进行处理,然后利用context上下文书写自己的下一阶段的键值对。

在进行combiner编程时,就把他当做是reducer。

要充分的利用系统的排序功能。

如果此时你run java aplication,你的程序只会在eclipse中虚拟的一个云环境中运行,而不会跑上云端去运行,所以无法再master:50070/jobtracker.jsp页面中监控到该作业;需要在main方法中添加几行代码,代码附录如下:

//在你的文件地址前自动添加:hdfs://master:9000/
conf.set("fs.default.name", "hdfs://master:9000/");
conf.set("hadoop.job.user","mango");
//指定jobtracker的ip和端口号,master在/etc/hosts中可以配置
conf.set("mapred.job.tracker","master:9001");  

MapReduce框架

任务调度程序,将任务并行的分给节点进行计算

将输入文件划分为split供Mapper类使用, 考虑到数据要尽量进行本地运算,所以划分的split的大小应该<=文件块的存储大小(64M)

在完成combine和shuffle之后map的中间结果被直接写到本地磁盘,通知JpbTracker中间结果文件的位置, 再由JobTracker告知Reducer到

哪个Datanode上去取中间结果。 每个Reducer要想多个Mapper节点取得落在其负责范围内的中间结果然后执行reduce函数,形成一个最终结果文件。

执行过程:

job执行前的工作:

1.编写MapReduce代码,编译,打包成jar

2.将数据上传到HDFS上,分布式系统HDFS会自动将大文件划分成块进行分布式存储(FlieBlockLocations)

终端申请提交作业:

outputformat检查job输出目录是否已经存在,进行出错检查。

inputformat将HDFS上的job inputpath中的逻辑文件划分成逻辑的split块,(List<split>将记录每块在源文件中的偏移量和所在的主机)

将MapReduce的jar包、配置文件、split list信息上传到HDFS的一个目录中,(以Job ID作为目录名)

提交作业完毕

JobTracker:

将终端提交的作业放到作业队列中

开始执行当前作业时,首先将作业目录中的InputSplit信息取出来,根据实际运行情况为每个InputSplit创建一个Map任务

创建reduce等任务

TaskTracker

接到新任务后,将这个任务的程序jar文件、数据split从HDFS上复制到本地磁盘上,进行本地计算。

配置环境相关不错的网址:http://www.cnblogs.com/xia520pi/archive/2012/05/20/2510723.html

时间: 2024-10-26 05:28:27

Hadoop入门学习笔记之一的相关文章

Hadoop入门学习笔记---part4

紧接着<Hadoop入门学习笔记---part3>中的继续了解如何用java在程序中操作HDFS. 众所周知,对文件的操作无非是创建,查看,下载,删除.下面我们就开始应用java程序进行操作,前提是按照<Hadoop入门学习笔记---part2>中的已经在虚拟机中搭建好了Hadoop伪分布环境:并且确定现在linux操作系统中hadoop的几个进程已经完全启动了. 好了,废话不多说!实际的例子走起. 在myeclipse中新建一个java工程: 在项目工程中新建一个lib包用于存放

Hadoop入门学习笔记---part1

随着毕业设计的进行,大学四年正式进入尾声.任你玩四年的大学的最后一次作业最后在激烈的选题中尘埃落定.无论选择了怎样的选题,无论最后的结果是怎样的,对于大学里面的这最后一份作业,也希望自己能够尽心尽力,好好做.正是因为选题和hadoop有关,现在正式开始学习hadoop.将笔记整理于此,希望与志同道合的朋友共同交流. 作者:itRed 邮箱:[email protected] 个人博客链接:http://www.cnblogs.com/itred 好了,废话不多说.进入正题!开始hadoop的学习

Hadoop入门学习笔记---part3

2015年元旦,好好学习,天天向上.良好的开端是成功的一半,任何学习都不能中断,只有坚持才会出结果.继续学习Hadoop.冰冻三尺,非一日之寒! 经过Hadoop的伪分布集群环境的搭建,基本对Hadoop有了一个基础的了解.但是还是有一些理论性的东西需要重复理解,这样才能彻底的记住它们.个人认为重复是记忆之母.精简一下: NameNode:管理集群,并且记录DataNode文件信息: SecondaryNameNode:可以做冷备份,对一定范围内的数据作快照性备份: DataNode:存储数据:

汇编入门学习笔记 (六)—— si、di,双重循环

疯狂的暑假学习之  汇编入门学习笔记 (六)-- si.di,双重循环 参考: <汇编语言> 王爽 第7章 1. and和or指令,与[bx+idata] and和or,就不多说了. [bx+idata] 这样写是可以的,某些情况下,比较方便. [bx+idata] 也可以写成 idata[bx] 直接见例子: 把'ABcde' 跟 'fGHig' 都改成大写(ASCII中大写字母与小写字母二进制中,只有第五位不同,大写字母是0,小写字母是1) assume cs:code,ds:data d

汇编入门学习笔记 (八)—— 转移指令

疯狂的暑假学习之  汇编入门学习笔记 (八)--  转移指令 參考: <汇编语言> 王爽 第9章 能够改动ip或者同一时候改动cs和ip的指令统称为转移指令. 8086CPU转移行为分为: 段内转移:仅仅改动ip 段间转移:同一时候改动cs和ip 段内转移按ip改动的范围可分为: 短转移:ip改动范围 -128~127 近转移:ip改动范围 -32768~32767 转移指令分为: 无条件转移指令.如 jmp 条件转移指令 循环指令.如 loop 过程. 中断. 1. offset,nop指令

汇编入门学习笔记 (三) —— 第一个程序

疯狂的暑假学习之  汇编入门学习笔记 (三)-- 第一个程序 参考:<汇编语言> 王爽  第四章 1.一个源程序从写到执行的过程 第一步:编写汇编源程序 第二步:对源程序进行编译连接 第三步:在操作系统中执行 2.源程序 代码: assume cs:first first segment start: mov ax,2 add ax,ax add ax,ax mov ax,4C00H int 21H first ends end start 代码解释: assume .segment.ends

Python 实现 CNKI批量下载 和FireFox Extension 入门学习笔记

?                                 Python 实现 CNKI批量下载 和FireFox Extension 入门学习笔记? 由于需要也是为了督促自己学习新的东西,我原本想要尝试着写一个爬虫程序,能够在cnki上自动得将论文进行批量下载,学习过程中遇到了诸多情况,cnki也真是专业,不得不佩服cnki的强大. 下面进入正题: 学习.实验环境:ubuntu 14.04 工具:Eclipse ,  FireFox, FireBug,HttpFox 编程语言:pyth

汇编入门学习笔记 (十四)—— 直接定址表

疯狂的暑假学习之  汇编入门学习笔记 (十四)-- 直接定址表 参考: <汇编语言> 王爽 第16章 1. 描述单元长度的标号 普通的标号:a,b assume cs:code code segment a:db 1,2,3,4,5,6,7,8 b:dw 0 start: mov si,offset a mov di,offset b mov ah,0 mov cx,8 s: mov al,cs:[si] add cs:[di],ax inc si loop s mov ax,4c00h in

汇编入门学习笔记 (四)—— [BX] 和 loop指令

疯狂的暑假学习之  汇编入门学习笔记 (四)-- [BX]  和 loop指令 参考:<汇编语言> 王爽 第5章 1.[BX] mov al,[1] 在debug中,会把bs:1 中数据赋给al,但在在masm中不会把bs:1 中数据赋给al,而是把 [1] 认为是 1 赋给al. 如果要实现在debug中的mov al,[1],在masm中就需要[bx] 如: mov bx,1 mov al,[bx] 还可以用 bs:[1] 的方式 如: mov al,bs:[1] 2.loop 循环 要使