1.系统参数配置
1.1.通过API对相关组件的参数进行配置
Hadoop的API分为以下几个部分:
org.apache.hadoop.conf:系统参数的配置文件处理API
org.apache.hadoop.fs:抽象的文件系统API
org.apache.hadoop.dfs:Hadoop分布式文件系统HDFS模块的实现
org.apache.hadoop.mapred:Hadoop分布式计算系统MapReduce模块的实现,包括任务的分发调度等
org.apache.hadoop.ipc:用在网络服务端和客户端的工具,封装了网络异步I/O的基础模块
org.apache.hadoop.io:定义了通用的I/O API,用于针对网络,数据库,文件等数据对象进行读写操作等.
Configuration类由源来设置,每个源包含以XML形式出现的一系列属性/值对.每个源以一个字符串或一个路径来命名.如果是以字符串命名,则通过类路径检查该字符串代表的路径是否存在;如果是以路径命名的,则直接通过本地文件系统进行检查,而不用类路径.
1.2.多个配置文件的整合
如果使用两个资源configuation-default.xml和configuration-site.xml来定义配置,将资源按顺序添加到Configuration中,代码如下:
Configuration conf = new Configuration();
conf.addResource("configuation-default.xml");
conf.addResource("|configuration-site.xml");
后添加进来的属性取值覆盖掉前面所添加资源中的属性取值.另外,被标记为final的属性不能被后面定义的属性覆盖.
2.配置开发环境
3.编写MapReduce程序
3.1.Map处理
Mapper处理的数据时由InputFormat分结果的数据集,其中InputFormat的作用是将数据集切割成小数据集InputSplit,每一个InputSplit将由一个Mapper负责处理.此外,InputFormat中还提供了一个RecordReader的实现,并将一个InputSplit解析成<key,value>对提供给Map函数.InputFormat的默认值是TextInputFormat,它针对文本文件,按行将文本切割成InputSplit,并且用LineRecordReader将InputSplit解析成<key,value>对,key是行在文本中的位置,value是文件中的一行.
3.2.Reduce处理
Map处理的结果会通过partition分发到Reducer,Reducer作为Reduce操作后,将通过OutputFormat输出结果.
Mapper最终处理的结果<key,value>对会被送到Reducer中进行合并,在合并的时候,由相同key的键/值对会被送到同一个Reducer上.Reducer是所有用户定制Reducer类的基类,它的输入时key及这个key对应的所有value的一个迭代器,还有Reducer的上下文.Reduce处理的结果将通过Reducer.Context的write方法输出到文件中.
4.本地测试
5.运行MapReduce程序
5.1.打包
5.2.在本地模式下运行
hadoop jar ScoreProcessFinal.jar inputOfScoreProcessFinal outputOfScoreProcessFinal
inputOfScoreProcessFinal为输入路径,outputOfScoreProcessFinal为输出路径
5.3.在集群上运行
hadoop dfs -copyFromLocal /home/u/Desktop/inputOfScoreProssFinal inputOfScoreProcesFinal
hadoop jar /home/u/TG/ScoreProcessFinal.jar ScoreProcessFinal inputOfScoreProcessFinal outputOfScoreProcessFinal
6.网络用户界面
7.性能调优
7.1.输入采用大文件
一种方式是将大量的小文件,进行合并后再使用MR进行计算.
二种是如果不对小文件做合并的预处理,也可以借用Hadoop中的CombineFileInputFormat. 它可以将多个文件打包到一个输入单元中,从而每次执行Map操作就会处理更多的数据.同时,CombineFileInputFormat会考虑节点和集群的位置信息,以决定哪些文件被打包到一个单元之中,所以使用CombineFileInputFormat也会使性能得到提高.
7.2.压缩文件
Hadoop的Map阶段所处理的输出大小也会影响整个MapReduce程序的执行时间.因为Map阶段的输出首先会存储在一定大小的内存缓冲区中,如果Map输出的大小超出一定限度,Map task就会将结果写入磁盘,等Map任务结束后再将它们复制到Reduce任务的节点.如果数据量大,中间的数据交换会占用很多的时间.
mapred.compress.map.output #设置为true,对Map的输出数据进行压缩.
mapred.map.output.compression.codec #压缩格式的设置
7.3.过滤数据
数据过滤主要是指在面对海量输入数据作业时,在作业执行之前先将数据中无用数据,噪声数据和异常数据清除.
Bloom Filter
7.4.修改作业属性
mapred.tasktracker.map.tasks.maximum 默认值为2,Map任务数
mapred.tasktracker.reduce.tasks.maximum 默认值为2,Reduce任务数
设置一个较大的值,使得每个节点上同时运行的Map和Reduce任务数增加,从而缩短运行的时间,提高整体的性能.
8.MapReduce工作流
8.1.复杂的Map和Reduce函数
Map和Reduce都继承自MapReduce的Mapper和Reducer基类,MapReduce框架根据用户继承后的衍生类和类中覆盖的核心函数来识别自定义的Map处理阶段和Reduce处理阶段.
除了核心函数Map和Reduce外,这里在介绍一些其他的函数.
8.1.1.setup函数
setup函数在task启动之后数据处理之前只调用一次,而覆盖的Map函数或Reduce函数会针对输入分片中的每个key调用一次.
所以setup函数可以看做task上的一个全局处理,而不像在Map函数或Reduce函数中,处理只对向前输入分片中的正在处理数据产生作用.
注意,这里setup是对应task上的全局操作,而不是整个作业上的全局操作.
8.1.2.cleanup函数
cleanup与setup类型,是在task销毁之前执行的.
8.1.3.run函数
run函数是Map类或Reduce类的启动方法:先调用setup函数,然后针对每个key调用一次Map函数或者Reduce函数,最后销毁task之前再调用cleanup函数.
如果想更加完备的控制Map或者Reduce阶段,可以覆盖此函数,并添加自己的控制内容.
8.2.MapReduce Job中全局共享数据
如果想在整个Job中保存全局变量,直接使用代码级别的全局变量是不现实的.因为每个task都是不同的JVM虚拟机.
下面介绍几种在MapReduce编程中相对有效的设置全局共享数据的方法:
8.2.1.读写HDFS文件
能够实现读写,比较直观.缺点:要共享一些很小的全局数据也需要使用I/O,将占用系统资源,增加作业完成的资源消耗.
8.2.2.配置Job属性
task可以读取Job的属性,基于这个特性,可以在任务启动之初就利用Configuration类中set(String name,String value)将一些简单的全局数据封装到作业的配置睡醒中.
然后在task中再利用Configuration类中的get(String name)获取配置到属性中的全局数据.
优点是简单;缺点是对量比较大的共享数据显得比较无力.
8.2.3.使用DistributedCache
DistributedCache是MapReduce为应用提供缓存文件的只读工作,可以缓冲文本文件,压缩文件和jar文件等.
优点是每个Job共享文件只会在启动后复制一次,并且适合大量的共享数据;缺点就是它是只读的.
1).将要缓存的文件复制到HDFS中
hadoop fs -copyFromLocal lookup /myapp/lookup
2).启用作业的属性配置,并设置待缓存文件
Configuration conf = new Configuration();
DistributedCache addCacheFile(new URI('/myapp/lookuo #lookup'),conf);
3).在Map函数中使用DistributedCache
public static class Map extends Mapper<Object,Text,Text,Text> {
private Path[] localArchives;
private Path[] localFiles;
public void setup(Context context) {
//获取缓存文件
Configuration conf = context.getConfiguration();
localArchives = DistributedCache.getLocalCacheArchives(conf);
localFiles = DistributedCache.getLocalCacheFiles(conf);
}
}
8.3.链接MapReduce Job
在日常的数据处理过程中,有些问题不是一个MapReduce作业就可以解决的,这时就需要多个MapReduce组合起来完成复杂任务.
8.3.1.线性MapReduce Job流
线性MapReduce Job就是设置多个有一定顺序的Job,每个Job以前一个Job的输出作为输入,经过处理,将数据再输出到下一个Job中.
具体做法就是:将每个Job的启动代码设置成只有上一个Job结束后才执行,然后将Job的输入设置成上一个Job的输出路径.
8.3.2.复制MapReduce Job流
除了线性情况外,更为复制的情况下.MapReduce提供了让用户将Job组织成复杂Job流的API---ControlledJob类和JobControl类 (在org.apache.hadoop.mapreduce.lib.jobcontrol包)
具体做法是:先按照正常情况配置各个Job,配置完成后再将各个Job封装到对应的ControlledJob对象中,然后使用ControlledJob的addDependingJob()设置依赖关系,接着在实例化一个JobControl对象,并使用addJob()方法将所有的Job注入JobControl对象中,最后使用JobControl对象的run方法启动Job流
8.3.3.Job设置预处理和后处理过程
这种情况既是在Job处理前和处理后做一些额外的事情,其实可以通过8.3.1线性也能实现.
具体做法是:通过MapReduce中org.apache.hadoop.mapred.lib包下的ChainMapper和ChainReducer两个静态类来实现的,这种方法最终形成的是一个独立的Job,而不是Job流,并且只有针对Job的输入输出流,各个阶段函数之间的输入输出MapReduce框架会自动组织.